Search code examples
rustserde

Using serde, how can I keep a copy of the serialized data while deserializing?


I'm using Rust and Serde. Suppose I have a struct that wants to keep a copy of the JSON data that created it, maybe so that it can re-send that same JSON elsewhere without having to re-serialize. (And it's not as simple as just keeping a copy of the original JSON data, since the struct might be inside more JSON data.) Example:

#[derive(Deserialize)]
struct LargerStruct {
    value: i32,
    inner: InnerStruct,
}

#[derive(Deserialize)]
struct InnerStruct {
    this_json: String,
    inner_value: i32,
}

fn main() {
    let json = r#"
        {
          "value": 42, 
          "inner": { "inner_value": 100 }
        }
    "#;

    let val: LargerStruct = // ???

    assert_eq!(&val.inner.this_json, r#"{ "inner_value": 100 }"#);
}

What might fill the ??? comment?


Solution

  • /*
    [dependencies]
    serde.version = "*"
    serde.features = ["derive"]
    serde_json.version = "*"
    serde_json.features = ["raw_value"]
    */
    
    use serde::*;
    use serde_json::value::RawValue;
    
    #[derive(Deserialize)]
    struct LargerStruct {
        value: i32,
        inner: InnerStruct,
    }
    
    struct InnerStruct {
        this_json: String,
        inner_value: i32,
    }
    
    impl<'de> Deserialize<'de> for InnerStruct {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            let this_json: Box<RawValue> = Deserialize::deserialize(deserializer)?;
    
            #[derive(Deserialize)]
            struct InnerStruct {
                inner_value: i32,
            }
            let this: InnerStruct =
                serde_json::from_str(this_json.get()).map_err(serde::de::Error::custom)?;
    
            Ok(Self{
                this_json: this_json.get().to_string(),
                inner_value: this.inner_value,
            })
        }
    }
    
    fn main() {
        let json = r#"
            {
              "value": 42, 
              "inner": { "inner_value": 100 }
            }
        "#;
    
        let val: LargerStruct = serde_json::from_str(json).unwrap();
    
        assert_eq!(&val.inner.this_json, r#"{ "inner_value": 100 }"#);
    }
    

    Playground

    You can use the serde_json::value::RawValue type to capture the original JSON in raw form. The code uses a custom Deserialize implementation for InnerStruct to achieve the goal of capturing the JSON and deserialize. It deserializes the struct, by calling serde_json again on the captured JSON inside the Deserialize implementation. This is necessary, since the deserializer is consumed after deserializing the RawValue.