Code Monkey home page Code Monkey logo

serde-aux's Introduction

serde-aux

Crates badge CI Documentation MIT licensed GitHub Sponsors

An auxiliary library for the serde crate.

Contains some useful helper stuff. See docs for more info.

The library is free for any contributions. The goal of this crate is to improve the user experience of the serde crate.

Rust version

The minimal rust version the library supports:

  • Up to version 3.0.0 (excluding) - rustc 1.36.
  • Since 3.0.0 - rustc 1.56.
  • Since 4.3.0 - rustc 1.57.

License

This project is licensed under the MIT license.

serde-aux's People

Contributors

alekspickle avatar anoadragon453 avatar dependabot-preview[bot] avatar dependabot[bot] avatar hrkrshnn avatar iddm avatar jonasbb avatar jtk18 avatar lucatrv avatar peanutbother avatar reitermarkus avatar ta32 avatar up9cloud avatar woodruffw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

serde-aux's Issues

RUSTSEC-2020-0071 and 'chrono' dependency

Hello,

Apparently the 'chrono' crate still includes its 'oldtime' feature as a default, which depends on an old version of the 'time' crate (v0.1.43) that has a vulnerability in it.
https://rustsec.org/advisories/RUSTSEC-2020-0071.html

For my own projects, I disable chrono's default features, then manually include all of the defaults except for 'oldtime', which is what the readme on chrono's repo recommends.

However, pulling in serde_aux seems to bring in chrono with the 'default' features selected, including 'oldtime'.

Any chance you could remove the 'oldtime' feature from your dependency on chrono to avoid this CVE in downstream projects?

`StringOrVecToVec` with trailing separator.

I have to parse a string of hex-encoded, space-separated bytes in a string but the source API includes a trailing space: "a1 b2 c3 d4 ".

If using a parser to turn the items into something other than a string type, such as an int, the parsing will fail due to the empty item.

Here is a test which demonstrates the problem:

#[test]
fn test_bytes_from_string() {
    fn bytes_from_string<'de, D>(deserializer: D) -> std::result::Result<Vec<u8>, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        StringOrVecToVec::new(' ', |s| {
            println!("{:?}", &s);
            u8::from_str_radix(s, 16)
        })
        .into_deserializer()(deserializer)
    }

    #[derive(serde::Deserialize, Debug)]
    struct MyStruct {
        #[serde(deserialize_with = "bytes_from_string")]
        list: Vec<u8>,
    }

    // Works
    let s = r#" { "list": "a1 b2 c3 d4" } "#;
    let a: MyStruct = serde_json::from_str(s).unwrap();
    assert_eq!(&a.list, &[0xa1, 0xb2, 0xc3, 0xd4]);

    // Fails:
    //   thread 'test_bytes_from_string' panicked at 'called `Result::unwrap()` on an `Err` value: Error("cannot parse integer from empty string", line: 1, column: 27)'
    let s = r#" { "list": "a1 b2 c3 d4 " } "#;
    let a: MyStruct = serde_json::from_str(s).unwrap();
}

Is there a way to resolve this or is this a bug with trailing separators?

Feature Request: Get the field names of a struct

Hi

Would a function implemented in this issue, be useful in this crate?
serde-rs/serde#1110

fn main() {
    // prints ["error", "description"]
    println!("{:?}", struct_fields::<AuthError>());
}

A function like this would eliminate a lot of boiler plate code in my app. I copied and pasted the implementation into my application and it works but I think it would be useful as apart of this library. The original issue was closed.

Note: link has implementation for enum and struct

Question: how to apply deserialize_struct_case_insensitive to a struct?

I am a bit confused by deserialize_struct_case_insensitive. It is categorized as a container_attribute in serde-aux's docs. However, the example seems to show it used as a field attribute. If it is a container_attribute, should I be able to do something like this?

#[derive(PartialEq, Eq, PartialOrd, Ord, Deserialize)]
#[serde(deserialize_with = "deserialize_struct_case_insensitive")]
pub struct Manifest {
    name: String,
    version: String,
}

Please add deserialize_datetime_utc_from_seconds

It is almost a copy of deserialize_datetime_utc_from_milliseconds, but I found myself implementing it over and over.

#[cfg(feature = "chrono")]
pub fn deserialize_datetime_utc_from_seconds<'de, D>(
    deserializer: D,
) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
where
    D: Deserializer<'de>,
{
    let number = deserialize_number_from_string::<i64, D>(deserializer)?;

    Ok(DateTime::<Utc>::from_utc(
        NaiveDateTime::from_timestamp(number, 0),
        Utc,
    ))
}

I will make a pull request if needed.
Thank you

Question: deserialize_option_number_from_string is not compatible with serde_json::Value::String

deserialize_option_number_from_string does not work when we are trying to deserialize from a json value. is this intentional?

    #[derive(Debug, Deserialize)]
    struct MyStruct {
        #[serde(deserialize_with = "deserialize_option_number_from_string")]
        option_num: Option<f32>,
        #[serde(default, deserialize_with = "deserialize_option_number_from_string")]
        missing: Option<i32>
    }

    fn serde_json_str_eq(s: &str, result: Option<f32>) {
        let a: MyStruct = serde_json::from_str(s).unwrap();
        assert_eq!(a.option_num, result);
        assert_eq!(a.missing, None);
    }

    fn serde_json_value_eq(s: Value, result: Option<f32>) {
        let a: MyStruct = serde_json::from_value(s).unwrap();
        assert_eq!(a.option_num, result);
        assert_eq!(a.missing, None);
    }
    let json_as_str = r#" { "option_num": "1" } "#;
    let json_as_value = serde_json::from_str::<Value>(json_as_str).unwrap();
    serde_json_str_eq(json_as_str, Some(1.0));
    serde_json_value_eq(json_as_value, Some(1.0));
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("data did not match any variant of untagged enum NumericOrNull", line: 0, column: 0)'

We cannot match to the enum used to deserialize the value

    #[derive(Deserialize)]
    #[serde(untagged)]
    enum NumericOrNull<'a, T> {
        Str(&'a str),
        FromStr(T),
        Null,
    }

Proposal: `deserialize_with_tilde` and `deserialize_optional_with_tilde`

First of all, thanks for this library! It's very neat, and I think it's a great idea to collect Serde "recipes" like this.

Here are two more I propose:

  • deserialize_with_tilde: Return a Result<String>, where the Ok(_) value is a string with the leading ~ replaced with the current user's $HOME directory.
  • deserialize_optional_with_tilde: The same as above, but Result<Option<String>> to allow for Option<String> as the input type.

The behavior here would come from the shellexpand crate, which only substitutes ~ if it's the first character in the string and the string is in "path" form, not "symbolic user" form (i.e. ~/foo/, not ~user/foo).

The main application of these is places where Serde is used to load from a config file: users generally prefer to specify paths with ~ rather than their home directory spelled out, and this would save a separate transform after deserialization.

Let me know what you think!

Cannot deserialize null

Hi I'm having an issue with conditional serialization.

#[serde(rename = "price")]
#[serde(deserialize_with = "deserialize_number_from_string")]
price: u32,

The payload: "price":null

I can't change price to Option<u32> since it isn't compatible with deserialize_number_from_string.

I think this is a bug?

deserialize_default_from_empty_object works differently when default tag is set on inner struct

Hi,

With the example here, if we tag InnerStruct with #[serde(default)], then the test with empty object fails. A default InnerStruct is created on the struct MyStruct, instead of None. I believe the default for an Option is None. So, not sure why a default object is being constructed in place of it. I have added comments to the relevant sections of the code.

extern crate serde_json;
extern crate serde_aux;
extern crate serde;

use serde_aux::prelude::*;

#[derive(Serialize, Deserialize, Debug)]
struct MyStruct {
    #[serde(deserialize_with = "deserialize_default_from_empty_object")]
    empty_as_default: Option<MyInnerStruct>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(default)] //Added this, so that mandatory will be set to 0, if the field is missing from json.
struct MyInnerStruct {
    mandatory: u64,
}

fn main() {
    let s = r#" { "empty_as_default": { "mandatory": 42 } } "#;
    let a: MyStruct = serde_json::from_str(s).unwrap();
    assert_eq!(a.empty_as_default.unwrap().mandatory, 42);

    let s = r#" { "empty_as_default": null } "#;
    let a: MyStruct = serde_json::from_str(s).unwrap();
    assert!(a.empty_as_default.is_none());

    let s = r#" { "empty_as_default": {} } "#;
    let a: MyStruct = serde_json::from_str(s).unwrap(); 
    assert!(a.empty_as_default.is_none()); //This assert fails

    let s = r#" { "empty_as_default": { "unknown": 42 } } "#;
    assert!(serde_json::from_str::<MyStruct>(s).is_err());
}

Thanks

[Bug] Introspect not working with `flatten` and (possibly) `serde_with`

Description

Structs with flattened argument are improperly introspected. Any introspection of such a struct results in the empty array. Cannot determine if serde_with causes unexpected behaviors, because it's dependent on the flatten

Unresolved issues

  • flatten working as expected
  • verify that serde_with prefix is working as expected

Example

ser.rs
// ser.rs

use serde::{Serialize, Deserialize};

serde_with::with_prefix!(my "my_)");

#[derive(Debug, Serialize, Deserialize)]
pub struct B {
    pub b: String,
    #[serde(rename="z")]
    pub b2: usize
}

#[derive(Debug, Serialize, Deserialize)]
pub struct A {
    pub a: usize,
    #[serde(flatten, with="my")]
    pub bx: B
}

#[derive(Debug, Serialize, Deserialize)]
pub struct A0 {
    pub a: usize,
    pub bx: B
}

#[derive(Debug, Serialize, Deserialize)]
pub struct A1 {
    #[serde(with="my")]
    pub a: usize
}

#[derive(Debug, Serialize, Deserialize)]
pub struct A2 {
    #[serde(flatten)]
    pub bx: B
}

#[derive(Debug, Serialize, Deserialize)]
pub struct A3 {
    #[serde(with="my")]
    pub bx: B
}
main.rs
// main.rs

use serde_aux::prelude::*;
mod ser;

fn main() {
    let b = ser::B {
        b: "AA".into(),
        b2: 22,
    };

    let a = ser::A {
        a: 2,
        bx: b.clone()
    };

    let a0 = ser::A0 {
        a: 2,
        bx: b.clone()
    };

    let _a1 = ser::A1 {
        a: 2,
    };

    let a2 = ser::A2 {
        bx: b.clone()
    };

    let a3 = ser::A3 {
        bx: b.clone()
    };

    println!("A = \t{}", serde_json::to_string_pretty(&a).unwrap());
    println!("A0 = \t{}", serde_json::to_string_pretty(&a0).unwrap());
    println!("A2 = \t{}", serde_json::to_string_pretty(&a2).unwrap());
    println!("A3 = \t{}", serde_json::to_string_pretty(&a3).unwrap());

    println!("A = \t{:?}", serde_introspect::<ser::A>());
    println!("A0 = \t{:?}", serde_introspect::<ser::A0>());
    println!("A1 = \t{:?}", serde_introspect::<ser::A1>());
    println!("A2 = \t{:?}", serde_introspect::<ser::A2>());
    println!("A3 = \t{:?}", serde_introspect::<ser::A3>());
}
stdout
# Output

A =     {
  "a": 2,
  "my_)b": "AA",
  "my_)z": 22
}
A0 =    {
  "a": 2,
  "bx": {
    "b": "AA",
    "z": 22
  }
}
A2 =    {
  "b": "AA",
  "z": 22
}
A3 =    {
  "bx": {
    "my_)b": "AA",
    "my_)z": 22
}

A =     []          # Wrong
A0 =    ["a", "bx"] # Control sample. This is always ok
A1 =                # Actually panics, my bad
A2 =    []          # Wrong
A3 =    ["bx"]      # Actually ok, my bad

deserialize_struct_case_insensitive + serde::rename

I have encountered strange behavior when deserialize_struct_case_insensitive is used in conjunction with serde::rename. Here is a slightly modified example taken from the deserialize_struct_case_insensitive documentation:

use serde::Deserialize;
use serde_aux::prelude::*;

#[derive(Deserialize, Debug)]
struct AnotherStruct {
    #[serde(rename = "fieldname")] 
    field_name: String,
}
#[derive(Deserialize, Debug)]
struct MyStruct {
    #[serde(deserialize_with = "deserialize_struct_case_insensitive")]
    another_struct: AnotherStruct,
}

fn main() {
    let s = r#"{ "another_struct": { "FiElDnAmE": "Test example" } }"#;
    let a: MyStruct = serde_json::from_str(s).unwrap();
    assert_eq!(a.another_struct.field_name, "Test example");
}

In this case everything works as expected, but if #[serde(rename = "fieldname")] is changed to #[serde(rename = "fieldName")] then I get the following error:

thread 'main' panicked at 'called Result::unwrap() on an Err value: Error("missing field fieldName", line: 1, column: 53)', src/main.rs:17:47

"deserialize_option_number_from_string" fails when property does not exist.

I have a JSON object

{
    "property1": "intString",
    "property2": "intString",
    "sometimesProperty": "intString",
}

and a rust struct link this:

use serde_aux::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct Object {
    #[serde(deserialize_with = "deserialize_number_from_string")]
    property1: u64,

    #[serde(deserialize_with = "deserialize_number_from_string")]
    property2: u64,

    #[serde(rename = "sometimesProperty", deserialize_with = "deserialize_option_number_from_string")]
    sometimes_property: Option<u64>,
}

This works as long as sometimesProperty exists on the json but if it doesn't then I get a Serde error saying that it expected sometimesProperty.

Is this expected behavior?

deserialize_default_from_empty_object with null value

With the following code, I get an error when the incoming json has a null value for a field.

extern crate serde;
extern crate serde_aux;
extern crate serde_json;

use serde::{Deserialize, Serialize};
use serde_aux::prelude::*;

#[derive(Serialize, Deserialize, Debug, Default)]
struct MyStruct {
    #[serde(deserialize_with = "deserialize_default_from_empty_object")]
    name: String,
}

fn main() {
    let s = r#" {"name": "George" }"#;
    let a: MyStruct = serde_json::from_str(s).unwrap();
    assert_eq!(a.name, "George");

    let s = r#" { "name": {} } "#;
    let a: MyStruct = serde_json::from_str(s).unwrap();
    assert_eq!(a.name, "");

    let s = r#" { "name": null} "#;
    let a: MyStruct = serde_json::from_str(s).unwrap();
    assert_eq!(a.name, "");
}

The error is

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("data did not match any variant of untagged enum EmptyOrNot", line: 1, column: 16)', src/main.rs:38:47
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Strangely, enough the following code does not error, the name field in MyStruct is now wrapped in an Option (as in the documentation example)

extern crate serde;
extern crate serde_aux;
extern crate serde_json;

use serde::{Deserialize, Serialize};
use serde_aux::prelude::*;

#[derive(Serialize, Deserialize, Debug, Default)]
struct MyStruct {
    #[serde(deserialize_with = "deserialize_default_from_empty_object")]
    name: Option<String>,
}

fn main() {
    let s = r#" {"name": "George" }"#;
    let a: MyStruct = serde_json::from_str(s).unwrap();
    assert_eq!(a.name, Some("George".to_owned()));

    let s = r#" { "name": {} } "#;
    let a: MyStruct = serde_json::from_str(s).unwrap();
    assert_eq!(a.name, None);

    let s = r#" { "name": null} "#;
    let a: MyStruct = serde_json::from_str(s).unwrap();
    assert_eq!(a.name, None);
}

deserialize_option_number_from_string does not seem to allow non-existent values

Normally when you deserialize something like

{
  "a": 1
}

into a Serde struct like

#[derive(Deserialize)]
struct Foo {
  a: Option<String>,
  b: Option<String>,
}

the deserialization succeeds, putting a None into the b field. However, if I apply deserialize_with = deserialize_option_number_from_string to that field, then I get an error that the field b is missing.

CC @younies

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.