How to deserialize a subfield of a struct from the original struct's JSON with Serde?

后端 未结 2 896
迷失自我
迷失自我 2021-01-20 05:31

I want to have the Test::team_size attribute be deserialized from the data of Test object itself:

#[derive(Debug, Serialize, Deseri         


        
2条回答
  •  情歌与酒
    2021-01-20 06:09

    The Serde documentation has a chapter on how to implement custom deserialization when the autogenerated attributes don't fully do what you want. Starting from there, it's not too complicated, just tedious:

    extern crate serde;
    extern crate serde_json;
    
    use std::fmt;
    
    use serde::de::{self, Deserialize, Deserializer, Visitor, MapAccess};
    
    #[derive(Debug)]
    struct TeamSize {
        pub min: i64,
        pub max: i64,
    }
    
    #[derive(Debug)]
    struct Test {
        pub i: i64,
        pub team_size: TeamSize,
    }
    
    impl<'de> Deserialize<'de> for Test {
        fn deserialize(deserializer: D) -> Result
            where D: Deserializer<'de>
        {
            struct TestVisitor;
    
            impl<'de> Visitor<'de> for TestVisitor {
                type Value = Test;
    
                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("struct Test")
                }
    
                fn visit_map(self, mut map: V) -> Result
                    where V: MapAccess<'de>
                {
                    let mut min = None;
                    let mut max = None;
                    let mut i = None;
    
                    while let Some(key) = map.next_key()? {
                        match key {
                            "min" => {
                                if min.is_some() {
                                    return Err(de::Error::duplicate_field("min"));
                                }
                                min = Some(map.next_value()?);
                            }
                            "max" => {
                                if max.is_some() {
                                    return Err(de::Error::duplicate_field("max"));
                                }
                                max = Some(map.next_value()?);
                            }
                            "i" => {
                                if i.is_some() {
                                    return Err(de::Error::duplicate_field("i"));
                                }
                                i = Some(map.next_value()?);
                            }
                            _ => {
                                /* Ignore extra fields */
                            }
                        }
                    }
    
                    let min = min.ok_or_else(|| de::Error::missing_field("min"))?;
                    let max = max.ok_or_else(|| de::Error::missing_field("max"))?;
                    let i = i.ok_or_else(|| de::Error::missing_field("i"))?;
    
                    Ok(Test { i, team_size: TeamSize { min, max }})
                }
            }
    
            const FIELDS: &'static [&'static str] = &["min", "max", "i"];
            deserializer.deserialize_struct("Test", FIELDS, TestVisitor)
        }
    }
    
    fn main() {
        let t: Test = serde_json::from_str(r#"{"i": -2, "min": 2, "max": 5}"#).unwrap();
        assert_eq!(t.i, -2);
        assert_eq!(t.team_size.min, 2);
        assert_eq!(t.team_size.max, 5);
    }
    

提交回复
热议问题