Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.

Related tags

rust serde derive no-std
Overview

Serde   Build Status Latest Version serde: rustc 1.13+ serde_derive: rustc 1.31+

Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.


You may be looking for:

Serde in action

Click to show Cargo.toml. Run this code in the playground.
[dependencies]

# The core APIs, including the Serialize and Deserialize traits. Always
# required when using Serde. The "derive" feature is only required when
# using #[derive(Serialize, Deserialize)] to make Serde work with structs
# and enums defined in your crate.
serde = { version = "1.0", features = ["derive"] }

# Each data format lives in its own crate; the sample code below uses JSON
# but you may be using a different one.
serde_json = "1.0"

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let point = Point { x: 1, y: 2 };

    // Convert the Point to a JSON string.
    let serialized = serde_json::to_string(&point).unwrap();

    // Prints serialized = {"x":1,"y":2}
    println!("serialized = {}", serialized);

    // Convert the JSON string back to a Point.
    let deserialized: Point = serde_json::from_str(&serialized).unwrap();

    // Prints deserialized = Point { x: 1, y: 2 }
    println!("deserialized = {:?}", deserialized);
}

Getting help

Serde is one of the most widely used Rust libraries so any place that Rustaceans congregate will be able to help you out. For chat, consider trying the #general or #beginners channels of the unofficial community Discord, the #rust-usage channel of the official Rust Project Discord, or the #general stream in Zulip. For asynchronous, consider the [rust] tag on StackOverflow, the /r/rust subreddit which has a pinned weekly easy questions post, or the Rust Discourse forum. It's acceptable to file a support issue in this repo but they tend not to get as many eyes as any of the above and may get closed without a response after some time.


License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Issues
  • Xml

    Xml

    would you be so kind as to review the serde_macros and Deserializer changes?

    current state:

    • [x] xml to struct deserialization
    • [x] deserialize bool, int, string from <anytagname>value</anythingelse>
    • [x] deserialize sequences (tuple, array, vector) as struct member
    • [x] deserialize escaped chars (&abcd;)
    • [x] deserialize CDATA
    • [ ] deserialize enumerations
    • [ ] deserialize arrays of enumerations
    • [ ] deserialize errors instead of assertions
    • [ ] more deserialize tests
    • [x] parse to dom tree
    • [ ] remove debug print! messages
    • [ ] struct to xml serialization

    anti-features (just ignoring stuff I don't like):

    • [x] ignore namespaces
    • [x] skip xml comments
    • [x] skip xml version tag
    • [x] ignoring xml-attributes

    things that would be nice to have but might not be possible

    • [ ] xsd verification
    • [ ] sequences of sequences (how would these even look like in xml?)
    • [ ] attributes to collapse xml elements that only contain a single type of element.
    opened by oli-obk 53
  • Flatten

    Flatten

    I am interacting with an API which returns pagination information on most of their requests. Here is an example:

    {
        "limit": 25,
        "offset": 0,
        "total": 1,
        "users": [
            {...}
        ]
    }
    

    limit, offset, and total are present for many of the responses received. Here is the struct I deserialize the JSON response into:

    #[derive(Debug, Serialize, Deserialize)]
    pub struct Users {
        limit: i32,
        offset: i32,
        total: i32,
        users: Vec<User>
    }
    

    The problem that I'm having is that I don't know how I can avoid repeating those same 3 fields in other structs.

    I would like to have something similar to this:

    #[derive(Debug, Serialize, Deserialize)]
    pub struct Pagination {
        offset: i32,
        limit: i32,
        total: i32
    }
    
    #[derive(Debug, Serialize, Deserialize)]
    pub struct Users {
        pagination: Pagination,
        users: Vec<User>
    }
    

    Here serde would see that no field pagination was present but the type of the struct field is Pagination which contains fields which are present in the response.

    I guess this could be solved with some kind of struct inheritance but Rust doesn't have that at the moment which restricts us to use composition.

    Any ideas?

    enhancement derive 
    opened by arnm 40
  • i128 and u128 integers missing Deserialize impls

    i128 and u128 integers missing Deserialize impls

    They should behind the unstable flag.

    enhancement 
    opened by PlasmaPower 32
  • (De)serialization of enums could use a simpler format

    (De)serialization of enums could use a simpler format

    I have worked only with serde_json, to I may be missing something that applies to other (de)serializers.

    Serialization

    Serialization of enums seems to always produce objects, even for trivial constructors

    #[derive(Serialize, Deserialize)]
    pub enum Foo {
        A, B, C
    }
    
    fn main() {
      println!("{}", serde_json::to_string(&Foo::A).unwrap());
      // prints: `{"A":[]}`
    }
    

    This produces {"A":[]}. I would prefer if it produced just the string "A".

    Deserialization

    More importantly, deserialization of enums seems to always require objects, which is annoying when one attempts to implement a protocol.

    #[derive(Serialize, Deserialize)]
    pub enum Foo {
        A, B, C
    }
    
    fn main() {
      let a : Foo = self::serde_json::from_str("\"A\"").unwrap();
      // panics with a syntax error
    }
    

    I would have preferred if it managed to deserialize the string "A" into enum constructor A.

    edit Fixed typo in the second example.

    enhancement 
    opened by Yoric 32
  • Helper library of useful de/serialize_with functions

    Helper library of useful de/serialize_with functions

    For example the ones from https://github.com/serde-rs/serde/issues/550 and https://github.com/serde-rs/serde-rs.github.io/issues/22. These don't need to be in serde itself but if there are ones that people ask for over and over, we can stick those in a helper crate and provide a better out-of-the-box experience compared to "implement your own serialize_with" or "paste this code into your project."

    discussion 
    opened by dtolnay 32
  • Rc<> gets deserialized incorrectly

    Rc<> gets deserialized incorrectly

    The way serde currently treats ref-counted data structures means that it creates copies of the references objects. This is bad for several reasons:

    • Potentially increased memory usage
    • Equality comparison that relies on comparison of address breaks
    • Interior mutability is not reflected in copies and maybe more that I can't think of right away. I think there should at least be big warnings in the documentation about this behaviour, but the support should be either fixed or deprecated, imo.
    breaking change 
    opened by shahn 31
  • Decide whether Syntex bumps require a Serde major version change

    Decide whether Syntex bumps require a Serde major version change

    @alexcrichton https://github.com/serde-rs/serde/pull/346#issuecomment-223723712

    Changes like this which update syntex, a public dependency of serde_codegen (e.g. it reexports types from syntex) are actually a breaking change for the serde crate. Could this be signaled with a major version update or holding off the upgrade? This unfortunately breaks any other crate which is depending on serde_codegen as it may get a mismatch of syntex versions otherwise.

    We're probably damned either way. If Serde were on version 0.33, the 275 crates that depend on Serde would be fragmented across all of them (about half are still on ^0.6) and would not work together.

    On the one hand (no major version change), we occasionally break crates that use a ^ dependency on Serde and also have another dependency on Syntex. Where this is unacceptable, you could use an = dependency.

    On the other hand, we would never break ^ dependencies but practically every time you do cargo update you would end up in a broken state until 275 crates synchronize their Serde dependency.

    logistics 
    opened by dtolnay 29
  • more flexible JSON serialization

    more flexible JSON serialization

    Serialization for machines

    When structures are serialized to JSON to be transferred over the wire, there may be servers that expect null values to be omitted, possibly to save bandwidth. Right now, there is no way in serde to omit null values.

    As a practical example, imagine someone trying to upload a video to youtube:

    $ youtube3 --debug videos insert \
    -r snippet \
    title="Google APIs for Rust: Developer Diary #2 [Making CLIs]" \
    description="TBD" \
    tags="Google APIs, Google, rust-lang, Diary, OSS" \
    category-id=22 \
    ..status privacy-status=private \
    embeddable=true \
    license=youtube \
    -u resumable ~/Movies/youtube-originals/Google\ APIs\ for\ Rust\ -\ Using\ youtube3\ to\ upload\ a\ video.mov application/octet-stream
    

    Which yields the following error:

    Bad Requst (400): Invalid value for: null is not a valid value
    

    As well as the following dialogue between client and server:

    POST /resumable/upload/youtube/v3/videos?part=status%2Csnippet&alt=json&uploadType=resumable HTTP/1.1
    User-Agent: google-api-rust-client/0.1.6
    Host: www.googleapis.com
    Transfer-Encoding: chunked
    Content-Type: application/json
    X-Upload-Content-Type: application/octet-stream
    Authorization: Bearer ya29.YwHqwwVjMrn7y_qO7d6RR5KeowbDJFO_2mLk5pTPs9iJZP0k3DEHUm6E4xkOv3pw5oEhX3GBjI-H4A
    
    33C
    {"status":{"license":"youtube","embeddable":true,"privacyStatus":"private","publishAt":null,"publicStatsViewable":null,"uploadStatus":null,"rejectionReason":null,"failureReason":null},"topicDetails":null,"monetizationDetails":null,"suggestions":null,"ageGating":null,"fileDetails":null,"player":null,"id":null,"localizations":null,"liveStreamingDetails":null,"snippet":{"description":"TBD","tags":["Google APIs, Google, rust-lang, Diary, OSS"],"channelId":null,"defaultLanguage":null,"liveBroadcastContent":null,"publishedAt":null,"thumbnails":null,"title":"Google APIs for Rust: Developer Diary #2 [Making CLIs]","categoryId":"22","localized":null,"channelTitle":null},"kind":null,"statistics":null,"projectDetails":null,"conversionPings":null,"processingDetails":null,"etag":null,"contentDetails":null,"recordingDetails":null}
    0
    
    HTTP/1.1 400 Bad Request
    Vary: Origin
    Vary: X-Origin
    Content-Type: application/json; charset=UTF-8
    Content-Length: 234
    Date: Tue, 28 Apr 2015 06:31:59 GMT
    Server: UploadServer ("Built on Apr 20 2015 22:37:13 (1429594633)")
    Alternate-Protocol: 443:quic,p=1
    
    {
     "error": {
      "errors": [
       {
        "domain": "global",
        "reason": "invalid",
        "message": "Invalid value for: null is not a valid value"
       }
      ],
      "code": 400,
      "message": "Invalid value for: null is not a valid value"
     }
    }
    

    As you can see, the request contains null values which are not allowed.

    To further stress the importance of this feature, have a look at the respective Go implementation ...

    type AccessPolicy struct {
        // Allowed: The value of allowed indicates whether the access to the
        // policy is allowed or denied by default.
        Allowed bool `json:"allowed,omitempty"`
    
        // Exception: A list of region codes that identify countries where the
        // default policy do not apply.
        Exception []string `json:"exception,omitempty"`
    }
    

    ... where the marker omitempty will prevent it to be serialized if unset.

    You can try it yourself using the youtube3 program, which can be downloaded here.

    Serialization for human consumption

    Right now there is exactly one method to get 'pretty', i.e. more human-friendly json output. It provides no option to specify how exactly that could be done.

    The most prominent one to me would be a setting for whether or not to ignore null values. Other options could be the indentation string to use, e.g. \t or .

    Motivation

    When printing the server response of any of the various google apis using a generated command-line interface, simple invocation yield results like this:

    $ discovery1 apis get-rest discovery v1
    {
      "protocol": "rest",
      "methods": null,
      "labels": null,
      "kind": "discovery#restDescription",
      "canonicalName": null,
      "ownerName": "Google",
      "documentationLink": "https://developers.google.com/discovery/",
      "auth": null,
      "packagePath": null,
      "batchPath": "batch",
      "id": "discovery:v1",
      "features": null,
      "ownerDomain": "google.com",
      "rootUrl": "https://www.googleapis.com/",
      "name": "discovery",
      "parameters": {
        "key": {
          "description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.",
          "format": null,
          "enum": null,
          "variant": null,
          "enumDescriptions": null,
          "readOnly": null,
          "minimum": null,
          "repeated": null,
          "id": null,
          "$ref": null,
          "default": null,
          "items": null,
          "required": null,
          "maximum": null,
          "properties": null,
          "location": "query",
          "pattern": null,
          "additionalProperties": null,
          "type": "string",
          "annotations": null
        },
        "userIp": {
          "description": "IP address of the site where the request originates. Use this if you want to enforce per-user limits.",
          "format": null,
          "enum": null,
          "variant": null,
          "enumDescriptions": null,
          "readOnly": null,
          "minimum": null,
          "repeated": null,
          "id": null,
          "$ref": null,
          "default": null,
          "items": null,
          "required": null,
          "maximum": null,
          "properties": null,
          "location": "query",
          "pattern": null,
          "additionalProperties": null,
          "type": "string",
          "annotations": null
        },
      [...]
      "revision": null
    }
    

    The above should look like this:

    $ discovery1 apis get-rest discovery v1
    {
     "kind": "discovery#restDescription",
     "etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/rJ-Wlqqs_yJDjtCFAIylPtmqXPY\"",
     "discoveryVersion": "v1",
     "id": "discovery:v1",
     "name": "discovery",
     "version": "v1",
     "title": "APIs Discovery Service",
     "description": "Lets you discover information about other Google APIs, such as what APIs are available, the resource and method details for each API.",
     "ownerDomain": "google.com",
     "ownerName": "Google",
     "icons": {
      "x16": "http://www.google.com/images/icons/feature/filing_cabinet_search-g16.png",
      "x32": "http://www.google.com/images/icons/feature/filing_cabinet_search-g32.png"
     },
     "documentationLink": "https://developers.google.com/discovery/",
     "protocol": "rest",
     "baseUrl": "https://www.googleapis.com/discovery/v1/",
     "basePath": "/discovery/v1/",
     "rootUrl": "https://www.googleapis.com/",
     "servicePath": "discovery/v1/",
     "batchPath": "batch",
     "parameters": {
      "alt": {
       "type": "string",
       "description": "Data format for the response.",
       "default": "json",
       "enum": [
        "json"
       ],
       "enumDescriptions": [
        "Responses with Content-Type of application/json"
       ],
       "location": "query"
      },
      "fields": {
       "type": "string",
       "description": "Selector specifying which fields to include in a partial response.",
       "location": "query"
      },
      "key": {
       "type": "string",
       "description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.",
       "location": "query"
      },
      "oauth_token": {
       "type": "string",
       "description": "OAuth 2.0 token for the current user.",
       "location": "query"
      },
      "prettyPrint": {
       "type": "boolean",
       "description": "Returns response with indentations and line breaks.",
       "default": "true",
       "location": "query"
      },
      "quotaUser": {
       "type": "string",
       "description": "Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Overrides userIp if both are provided.",
       "location": "query"
      },
      "userIp": {
       "type": "string",
       "description": "IP address of the site where the request originates. Use this if you want to enforce per-user limits.",
       "location": "query"
      }
     },
     "schemas": {
      "DirectoryList": {
       "id": "DirectoryList",
       "type": "object",
       "properties": {
        "discoveryVersion": {
         "type": "string",
         "description": "Indicate the version of the Discovery API used to generate this doc.",
         "default": "v1"
        },
        "items": {
         "type": "array",
         "description": "The individual directory entries. One entry per api/version pair.",
         "items": {
          "type": "object",
          "properties": {
           "description": {
            "type": "string",
            "description": "The description of this API."
           },
           "discoveryLink": {
            "type": "string",
            "description": "A link to the discovery document."
           },
           "discoveryRestUrl": {
            "type": "string",
            "description": "The URL for the discovery REST document."
           },
           "documentationLink": {
            "type": "string",
            "description": "A link to human readable documentation for the API."
           },
           "icons": {
            "type": "object",
            "description": "Links to 16x16 and 32x32 icons representing the API.",
            "properties": {
             "x16": {
              "type": "string",
              "description": "The URL of the 16x16 icon."
             },
             "x32": {
              "type": "string",
              "description": "The URL of the 32x32 icon."
             }
            }
           },
           "id": {
            "type": "string",
            "description": "The id of this API."
           },
           "kind": {
            "type": "string",
            "description": "The kind for this response.",
            "default": "discovery#directoryItem"
           },
           "labels": {
            "type": "array",
            "description": "Labels for the status of this API, such as labs or deprecated.",
            "items": {
             "type": "string"
            }
           },
           "name": {
            "type": "string",
            "description": "The name of the API."
           },
           "preferred": {
            "type": "boolean",
            "description": "True if this version is the preferred version to use."
           },
           "title": {
            "type": "string",
            "description": "The title of this API."
           },
           "version": {
            "type": "string",
            "description": "The version of the API."
           }
          }
         }
        },
        "kind": {
         "type": "string",
         "description": "The kind for this response.",
         "default": "discovery#directoryList"
        }
       }
      },
     [...]
    }
    
    enhancement 
    opened by Byron 28
  • Capture other unrecognized fields

    Capture other unrecognized fields

    #[derive(Serialize, Deserialize)]
    struct S {
        a: u32,
        b: String,
        #[serde(other)]
        other: Map<String, Value>,
    }
    
    {"a":0,"b":"","c":true}
    

    This would deserialize into other containing "c" => true.

    enhancement derive 
    opened by dtolnay 27
  • Add codegen expr magic for default, skip serializing, and alternative serializers

    Add codegen expr magic for default, skip serializing, and alternative serializers

    This is an alternative implementation of #214, #198, #208 and implements #90 and #216. This allows one to write:

    #[derive(Serialize, Deserialize)]
    struct Struct {
        #[serde(default="123")]
        a: i32,
        #[serde(skip_serializing_if="self.b == 123")]
        b: i32,
        #[serde(serialize_with="(self.b == 123).serialize(serializer)"]
        c: i32,
        #[serde(deserialize_with="Ok(if try!(bool::deserialize(deserializer) { 123) } else { 0 })"]
        d: i32,
    }
    

    cc @oli-obk, @target-san, @arcnmx

    opened by erickt 25
  • Use cache in the CI

    Use cache in the CI

    This is a better cache than there currently is. It caches only the stuff that is needed.

    opened by Milo123459 0
  • Content in adjacently tagged enums does/can not use default when missing

    Content in adjacently tagged enums does/can not use default when missing

    I want to do as shown in below example, but it doesn't seem to work. I feel like there is something I'm missing or serde is missing.

    I'd solve this by making two enums, one that is the real enum, and one that is only used (and seen) in a custom deserialize. But I don't like that pattern, so I want to know if there's something that can be improved here.

    https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2bf7a3b1c76f9fe9d7741dce671011cf

    // [dependencies]
    // serde = {version = "1", features = ["derive"]}
    // serde_json = "1"
    
    use serde;
    use serde_json;
    
    #[derive(serde::Deserialize)]
    pub struct Foo {
        pub bar: i64,
    }
    
    #[derive(serde::Deserialize, Default)]
    pub struct NoContent {}
    
    #[derive(serde::Deserialize)]
    #[serde(tag = "tag", content = "content")]
    #[serde(rename_all = "snake_case")]
    pub enum Data {
        WithContent(Foo),
        WithOptContent(Option<NoContent>),
        // There is no way to make this work.
        WithoutContent(#[serde(default)] NoContent),
    }
    
    #[test]
    fn deserialize() {
        let things = vec![
            r#"{"tag":"with_content", "content": { "bar": 10}}"#, // This works fine
            r#"{"tag":"with_opt_content"}"#, // This works because the content is wrapped with an Option
            r#"{"tag":"without_content" }"#, // This fails
        ];
        for i in things {
            serde_json::from_str::<Data>(i).unwrap_or_else(|_| panic!("failed on {:?}", i));
        }
    }
    
    opened by Emilgardis 0
  • Custom serde_json::Value deserialization?

    Custom serde_json::Value deserialization?

    I'd like to apply a normalization function on the field names when deserializing to serde_json::Value.

    let field_normalizer = |name: &str| {
                return name.to_lowercase().replace("#", "_");
    };
    
    let value: Value = serde_json::from_str_with_custom_normalizer(r#"{"Field_1": 1, "Field#2": 2}"#, field_normalizer)?;
    dbg(&value);
    

    The value displayed by the dbg macro should be:

    [main.rs:10] &value = Object({
        "field_2": Number(
            2,
        ),
        "field_1": Number(
            1,
        ),
    })
    

    I'm well aware of the possible name collision after normalization but I have a mechanism to deal with that.

    How can I implement a such custom generic deserialization without creating a modified copy of a Value?

    opened by lquerel 0
  • Add Serde Gura to Data formats list

    Add Serde Gura to Data formats list

    opened by Genarito 0
  • Allow `#[serde(default)]` together with `#[serde(with =

    Allow `#[serde(default)]` together with `#[serde(with = "some_module")]`

    I am trying to get serde working with Option<sqlx::types::Uuid>, for this I implemented serialize and deserialize in the module some_module, but when using the "with" attribute, the default attribute is not applied.

    error[E0308]: mismatched types
      --> src/lib.rs:79:25
       |
    79 | #[derive(sqlx::FromRow, Serialize)]
       |                         ^^^^^^^^^ expected struct `Uuid`, found enum `std::option::Option`
       |
       = note: expected reference `&Uuid`
                  found reference `&'__a std::option::Option<Uuid>`
    
    opened by zohaad 1
  • support for fully qualified names?

    support for fully qualified names?

    One thing that has come up in some of my work is that the rename options do not have a way to automatically include e.g. the full module path. Example:

    struct A;
    mod B {
    struct A;
    }
    

    In this example the struct name for both B::A and A would be the same, unless it's somehow overriden. This becomes more of an issue when working with structs from e.g. different crates.

    This is related to previously discussed issues:

    • https://github.com/serde-rs/serde/issues/1964
    • https://github.com/serde-rs/serde/issues/1636

    but much more specific since it's just a case of needing crate/module unique identifiers.

    opened by JeremyRubin 0
  • Implement Serialize/Deserialize for Infallible

    Implement Serialize/Deserialize for Infallible

    Suppose I have an API where a value can only be null. In Rust, the semantic way to represent null is via Option::<T>::None, but it's unclear what T should be because the value can never be Some(value), only None.

    I think it would be useful to be able to use Option<Infallible> (and possibly Option<!>) to represent these values. One way to do this is to implement Serialize directly for Infallible:

    impl Serialize for Infallible {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            match *self {}
        }
    }
    

    Since an instance of Infallible should theoretically never be serialized, this would allow Option<Infallible> to serialize as None.

    It would also be nice to be able to deserialize Option<Infallible>:

    impl<'de> Deserialize<'de> for Infallible {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            Err(de::Error::custom("value can never be constructed"))
        }
    }
    

    As a temporary solution, it's possible to define an empty enum and implement these traits on it.

    opened by TehPers 0
  • Prefix name of flattened fields

    Prefix name of flattened fields

    Usecase

    I want to serialize a struct containing other structs to CSV, which is why I use flatten. However some of these structs have fields with the same name, which make the output unpractical to read. I would like to prefix the flattened fields to be able to distinguish them.

    Minimal example

    use serde::Serialize;
    
    fn main() {
        let json = serde_json::to_string(&Message::default()).unwrap();
        println!("{}", json);
    }
    
    #[derive(Serialize, Default)]
    struct Message {
        content: String,
        #[serde(flatten)] // put new feature here
        from: Person,
        #[serde(flatten)] // put new feature here
        to: Person,
    }
    
    #[derive(Serialize, Default)]
    struct Person {
        name: String,
    }
    

    Output

    {"content":"","name":"","name":""}
    

    Wanted Output example

    {"content":"","from.name":"","to.name":""}
    

    Maybe this could be implemented as an option on the flatten macro, or as an extension on the renaming macro ?

    opened by tristanCadet 1
  • How can I serialize an alloc::string::String or alloc::vec::Vec in no_std environment?

    How can I serialize an alloc::string::String or alloc::vec::Vec in no_std environment?

    How can I serialize an alloc::string::String or alloc::vec::Vec in no_std environment? I have been using these two data structures in a no_std rust project, but I have encountered a problem that #[derive(Serialize, Deserialize)] cannot generate the proper function

    #[derive(Serialize, Deserialize)]
    pub(crate) struct Test {
        pub(crate) test: String, // this is alloc::string::String in no_std environment
    }
    
    error[E0277]: the trait bound `String: Serialize` is not satisfied
      --> src/image/mod.rs:36:5
       |
    36 |     pub(crate) test: String,
       |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Serialize` is not implemented for `String`
       |
       = note: required by `image::_::_serde::ser::SerializeStruct::serialize_field`
    
    error[E0277]: the trait bound `String: Deserialize<'_>` is not satisfied
      --> src/image/mod.rs:36:5
       |
    36 |     pub(crate) test: String,
       |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `String`
       |
       = note: required by `next_element`
    
    error[E0277]: the trait bound `String: Deserialize<'_>` is not satisfied
      --> src/image/mod.rs:36:5
       |
    36 |     pub(crate) test: String,
       |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `String`
       |
       = note: required by `next_value`
    
    opened by wangtianxia-sjtu 0
  • Flatten an array of partial objects into struct

    Flatten an array of partial objects into struct

    Hello there! First of all, thanks for the amazing project! :)

    I have been digging through Serde's documentation on how to handle a specific case, but haven't been able to create a generic version so far. I'd greatly appreciate it if someone could give me some pointers on how to solve this deserialisation issue generically.

    The problem

    I'm trying to work with an API which formats its JSON responses as such:

    [
        {
            "Account": {
                "id": 0,
            }
        },
        {
            "Account": {
                "id": 1,
            }
        },
        {
            "Session": {
                "id": "Hello",
            }
        }
    ]
    

    Now, the issue is that some objects are guaranteed to only appear once (Session), while others are guaranteed to be a list (Account). With those guarantees in mind, I would like to deserialise the response into the following structs:

    use serde::Deserialize;
    
    #[derive(Deserialize)]
    #[serde(rename_all = "PascalCase")]
    struct Response {
        account: Vec<Account>,
        session: Session,
    }
    
    #[derive(Deserialize)]
    struct Account {
        id: usize,
    }
    
    #[derive(Deserialize)]
    struct Session {
        id: String,
    }
    

    Handwritten Deserialize

    I've managed to write a handwritten Deserialize implementation (Playground, Gist). However, my question to you is whether there is room for improvement. Specifically:

    • Can a version of this code exist where I do not have to specify Field and Temporary?
    • Can a version of this code work generically on either a Wrapper<Response> struct or a deserialize_with function?

    Sources used

    Thank you!

    opened by m-rots 1
Releases(v1.0.130)
  • v1.0.130(Aug 28, 2021)

  • v1.0.129(Aug 28, 2021)

  • v1.0.128(Aug 21, 2021)

  • v1.0.127(Jul 31, 2021)

  • v1.0.126(May 12, 2021)

  • v1.0.125(Mar 22, 2021)

  • v1.0.124(Mar 5, 2021)

  • v1.0.123(Jan 25, 2021)

    • Support Self keywords in fields of types that derive Deserialize (#1830, thanks @taiki-e)
    • Allow floats to be deserialized from ints in tagged unions (#1842, thanks @Timmmm)
    • Support Self inside fields that use serialize_with (#1970)
    Source code(tar.gz)
    Source code(zip)
  • v1.0.122(Jan 24, 2021)

    • Add IntoDeserializer impl for &[u8] (#1898, thanks @Mingun)

    • Handle unrecognized numeric field keys during deserialization of a field_identifier, equivalently to string field keys (#1914, thanks @Mingun)

    • Add attribute to override default deserialization failure expectation message (#1916, thanks @Mingun)

      #[derive(Deserialize)]
      #[serde(untagged, expecting = "single version or array of versions")]
      struct VersionSpec {
          One(Version),
          Many(Vec<Version>),
      }
      
    • Improve serde_test handling of map entries and error message construction (#1918, thanks @Mingun)

    • Produce more accurate location information on test failures from serde_test crate (#1920, thanks @Mingun)

    • Improve diagnostic on failure to parse a rename_all attribute (#1960, #1961)

    • Eliminate unnecessary trait bounds on some value Deserializer impls (#1963)

    Source code(tar.gz)
    Source code(zip)
  • v1.0.121(Jan 23, 2021)

    • Support borrowed data during deserialization of a field identifier (#1917, thanks @Mingun)
    • Fix panic when deserializing Duration with nanoseconds that cause the seconds counter to overflow (#1958, thanks @jonasbb)
    Source code(tar.gz)
    Source code(zip)
  • v1.0.120(Jan 19, 2021)

  • v1.0.118(Dec 5, 2020)

  • v1.0.117(Oct 15, 2020)

  • v1.0.116(Sep 11, 2020)

    • Fix deserialization of IpAddr, SocketAddr, Bound, Result, OsString in formats which process variant identifiers as u64 (#1888, thanks @joshtriplett)
    Source code(tar.gz)
    Source code(zip)
  • v1.0.115(Aug 10, 2020)

  • v1.0.114(Jun 21, 2020)

  • v1.0.113(Jun 19, 2020)

  • v1.0.112(Jun 14, 2020)

  • v1.0.111(May 29, 2020)

    • Process borrowed lifetimes inside of interpolated macro_rules metavariables, such as in the case of #[derive(Deserialize)] struct S<'a> { field: $field } (#1821)
    Source code(tar.gz)
    Source code(zip)
  • v1.0.110(May 10, 2020)

  • v1.0.109(May 10, 2020)

    • Allow adjacently tagged newtype variants containing Option to omit the content field when deserializing (#1553, #1706, thanks @zth0)
    • Avoid panicking when a SystemTime older than UNIX_EPOCH is serialized (#1702, thanks @hjiayz)
    Source code(tar.gz)
    Source code(zip)
  • v1.0.108(May 9, 2020)

    • Provide a Serializer impl that can write primitives and unit variants to a &mut fmt::Formatter (#1705, thanks @jethrogb)

      use serde::Serialize;
      use std::fmt::{self, Display};
      
      #[derive(Serialize)]
      #[serde(rename_all = "kebab-case")]
      pub enum MessageType {
          StartRequest,
          EndRequest,
      }
      
      impl Display for MessageType {
          fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
              self.serialize(f)
          }
      }
      
    Source code(tar.gz)
    Source code(zip)
  • v1.0.107(May 8, 2020)

  • v1.0.106(Apr 3, 2020)

  • v1.0.105(Mar 18, 2020)

  • v1.0.104(Dec 15, 2019)

  • v1.0.103(Nov 24, 2019)

  • v1.0.102(Oct 27, 2019)

  • v1.0.101(Sep 16, 2019)

    • Report errors on malformed serde attributes, like #[serde(rename =)] -- the compiler used to reject these itself, but when the compiler relaxed its requirements on attribute syntax these malformed attributes began silently being ignored by serde_derive

    • Eliminate unused variable warning when using skip_serializing inside a tuple variant of an adjacently tagged enum (#1617, thanks @arilotter)

    • Support skip attribute inside of newtype variants (#1622, thanks @Xaeroxe)

    Source code(tar.gz)
    Source code(zip)
  • v1.0.100(Sep 7, 2019)

    • Provide serde::ser::StdError and serde::de::StdError which are either a re-export of std::error::Error (if Serde's "std" feature is enabled) or a new identical trait (otherwise).

      #[cfg(feature = "std")]
      pub use std::error::Error as StdError;
      
      #[cfg(not(feature = "std"))]
      pub trait StdError: Debug + Display {
          fn source(&self) -> Option<&(StdError + 'static)> { None }
      }
      

      Serde's error traits serde::ser::Error and serde::de::Error require std::error::Error as a supertrait, but only when Serde is built with "std" enabled. Data formats that don't care about no_std support should generally provide their error types with a std::error::Error impl directly:

      #[derive(Debug)]
      struct MySerError {...}
      
      impl serde::ser::Error for MySerError {...}
      
      impl std::fmt::Display for MySerError {...}
      
      // We don't support no_std!
      impl std::error::Error for MySerError {}
      

      Data formats that do support no_std may either have a "std" feature of their own as has been required in the past:

      [features]
      std = ["serde/std"]
      
      #[cfg(feature = "std")]
      impl std::error::Error for MySerError {}
      

      ... or else now may provide the std Error impl unconditionally via Serde's re-export:

      impl serde::ser::StdError for MySerError {}
      
    Source code(tar.gz)
    Source code(zip)
A priority queue for Rust with efficient change function.

PriorityQueue This crate implements a Priority Queue with a function to change the priority of an object. Priority and items are stored in an IndexMap

null 80 Sep 13, 2021
A proof of concept implementation of cyclic data structures in stable, safe, Rust.

A proof of concept implementation of cyclic data structures in stable, safe, Rust. This demonstrates the combined power of the static-rc crate and the

null 120 Sep 11, 2021
Obake is a procedural macro for declaring and maintaining versioned data-structures.

Obake is a procedural macro for declaring and maintaining versioned data-structures. The name 'obake' is taken from the Japanese 'お化け (おばけ)', a class of supernatural beings in Japanese folklore that shapeshift.

Nathan Corbyn 128 Sep 6, 2021
Algorithms and Data Structures of all kinds written in Rust.

Classic Algorithms in Rust This repo contains the implementation of various classic algorithms for educational purposes in Rust. Right now, it is in i

Alexander González 10 Sep 3, 2021
Generic array types in Rust

generic-array This crate implements generic array types for Rust. Requires minumum Rust version of 1.36.0, or 1.41.0 for From<[T; N]> implementations

Bartłomiej Kamiński 277 Sep 15, 2021
Parameterized routing for generic resources in Rust

Usher Usher provides an easy way to construct parameterized routing trees in Rust. The nodes of these trees is naturally generic, allowing Usher to le

Isaac Whitfield 31 Feb 25, 2021
Rust library for string parsing of basic data structures.

afmt Simple rust library for parsing basic data structures from strings. Usage You can specify string formats to any strucute, via the use of the fmt

Eduard 4 May 7, 2021
RiteLinked - LinkedHashMap & LinkedHashSet in Rust

RiteLinked -- HashMap-like containers that hold their key-value pairs in a user controllable order RiteLinked provides more up to date versions of Lin

Rite Database 38 Sep 4, 2021
Ternary search tree collection in rust

tst Ternary search tree collection in rust with similar API to std::collections as it possible. Ternary search tree is a type of trie (sometimes calle

Alexey Pervushin 17 Sep 12, 2021
Hypergraph is a data structure library to generate directed hypergraphs.

Hypergraph is data structure library to create a directed hypergraph in which a hyperedge can join any number of vertices.

Davy Duperron 112 Aug 24, 2021
SegVec data structure for rust. Similar to Vec, but allocates memory in chunks of increasing size.

segvec This crate provides the SegVec data structure. It is similar to Vec, but allocates memory in chunks of increasing size, referred to as "segment

Jacob Ryan McCollum 25 Aug 25, 2021
K-dimensional tree in Rust for fast geospatial indexing and lookup

kdtree K-dimensional tree in Rust for fast geospatial indexing and nearest neighbors lookup Crate Documentation Usage Benchmark License Usage Add kdtr

Rui Hu 108 Sep 9, 2021
A number of collections, such as linked-lists, binary-trees, or B-Trees are most easily implemented with aliasing pointers.

StaticRc is a safe reference-counted pointer, similar to Rc or Arc, though performing its reference-counting at compile-time rather than run-time, and

null 265 Sep 4, 2021
Array helpers for Rust's Vector and String types

array_tool Array helpers for Rust. Some of the most common methods you would use on Arrays made available on Vectors. Polymorphic implementations for

Daniel P. Clark 52 May 15, 2021
Extra iterator adaptors, iterator methods, free functions, and macros.

Itertools Extra iterator adaptors, functions and macros. Please read the API documentation here How to use with cargo: [dependencies] itertools = "0.1

null 1.4k Sep 13, 2021
Redis Tree(Ploytree) Structure Module

RedisTree is a Redis module that implements Polytree as a native data type. It allows creating,locating,pushing and detaching tree from Redi

Bonsai 43 Aug 28, 2021
wait-free spsc linked-list queue with individually reusable nodes

A wait-free single-producer single-consumer linked-list queue with individually reusable nodes.

glowcoil 9 Jun 12, 2021
Roaring bitmap implementation for Rust

RoaringBitmap This is not yet production ready. The API should be mostly complete now. This is a Rust port of the Roaring bitmap data structure, initi

Roaring bitmaps: A better compressed bitset 232 Sep 9, 2021
Hash Table Implementation in Rust

Hash Table Implementation in Rust Purely for educational and recreational purposes. For real world production please use std::collections::HashMap. Fo

Tsoding 8 May 4, 2021