2017-06-01 5 views
2

Ich möchte das Test::team_size Attribut haben aus den Daten von Test Objekt selbst deserialisiert werden:Wie ein Teilfeld einer Struktur aus dem JSON der ursprünglichen Struktur mit Serde deserialisieren?

#[derive(Debug, Serialize, Deserialize)] 
struct TeamSize { 
    pub min: i64, 
    pub max: i64, 
} 

#[derive(Debug, Serialize, Deserialize)] 
struct Test { 
    pub i: i64, 
    pub team_size: TeamSize, 
} 

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); 
} 

Dieser Code kompiliert nicht, und ich weiß nicht, wie Serde tun, was ich will. Gibt es eine Möglichkeit, team_size in diesem Beispiel aus dem JSON der ursprünglichen Struktur zu deserialisieren, wo es ein Unterfeld ist?

Es scheint, dass ich etwas wollen wie#[serde(untagged)] aber für eine Struktur und für ein Feld und nicht die gesamte Struktur.

+1

relevantes Thema: [serde # 119] (https://github.com/serde-rs/serde/issues/119) –

Antwort

2

Wir beabsichtigen, dieses Muster zu unterstützen besser in Serde mit so etwas wie:

#[derive(Serialize, Deserialize)] 
struct Test { 
    pub i: i64, 

    #[serde(flatten)] 
    pub team_size: TeamSize, 
} 

Diese Arbeit in serde-rs/serde#119 verfolgt wird. Denn nun ist die einfachste Problemumgehung in einem privaten Helfer-Typ deserialisiert und es restrukturieren nach Bedarf:

#[macro_use] 
extern crate serde_derive; 

extern crate serde; 
extern crate serde_json; 

use serde::{Serialize, Serializer, Deserialize, Deserializer}; 

#[derive(Debug)] 
pub struct TeamSize { 
    pub min: i64, 
    pub max: i64, 
} 

#[derive(Debug)] 
pub struct Test { 
    pub i: i64, 
    pub team_size: TeamSize, 
} 

// Private helper 
#[derive(Serialize, Deserialize)] 
struct Helper { 
    pub i: i64, 
    pub min: i64, 
    pub max: i64, 
} 

impl Serialize for Test { 
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 
     where S: Serializer 
    { 
     let helper = Helper { 
      i: self.i, 
      min: self.team_size.min, 
      max: self.team_size.max, 
     }; 
     helper.serialize(serializer) 
    } 
} 

impl<'de> Deserialize<'de> for Test { 
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 
     where D: Deserializer<'de> 
    { 
     let helper = Helper::deserialize(deserializer)?; 
     Ok(Test { 
      i: helper.i, 
      team_size: TeamSize { 
       min: helper.min, 
       max: helper.max, 
      }, 
     }) 
    } 
} 

fn main() { 
    let j = r#" { "i": -2, "min": 2, "max": 5 } "#; 

    let de: Test = serde_json::from_str(j).unwrap(); 
    println!("{:#?}", de); 

    let ser = serde_json::to_string_pretty(&de).unwrap(); 
    println!("{}", ser); 
} 
1

Die Serde documentation enthält ein Kapitel zur Vorgehensweise bei implement custom deserialization, wenn die automatisch generierten Attribute nicht das erreichen, was Sie möchten. Von dort aus ist es nicht zu kompliziert, nur mühsam:

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<D>(deserializer: D) -> Result<Self, D::Error> 
     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<V>(self, mut map: V) -> Result<Test, V::Error> 
       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); 
}