Во-первых, нам нужна другая структура, чтобы использовать deserialize_with
для нашей HashMap:
#[derive(Debug, Deserialize)]
struct Flatten {
#[serde(deserialize_with = "string_or_struct", flatten)]
obj: Obj,
}
Так что мы можем написать:
#[derive(Debug, Deserialize)]
struct InsideHashMap {
objs: HashMap<String, Flatten>,
}
Это должно работать, но это не потому, что (япока не знаю почему, похоже, что flatten и deserialize_with
не работают вместе, кажется, что он не использует deserialize_with
реализацию)
Итак, мы должны использовать сложный способ,реализовать это:
use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;
use serde; // 1.0.85
use serde::de::{self, Deserialize, MapAccess, Visitor}; // 1.0.85
use serde::Deserializer;
use serde_derive::Deserialize; // 1.0.85
use toml; // 0.4.10
use void::Void; // 1.0.2
#[derive(Debug)]
struct Obj {
x: isize,
y: String,
}
struct ObjVisitor;
// OjbAux is here to avoid implement the deserialiser of the map by hand we can't use
// Obj cause it will cause infinite recursion
#[derive(Debug, Deserialize)]
struct ObjAux {
x: isize,
y: String,
}
impl<'de> Visitor<'de> for ObjVisitor {
type Value = Obj;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("string or map")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(FromStr::from_str(value).unwrap())
}
fn visit_map<M>(self, visitor: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let aux: ObjAux = Deserialize::deserialize(de::value::MapAccessDeserializer::new(visitor))?;
Ok(Obj { x: aux.x, y: aux.y })
}
}
impl<'de> Deserialize<'de> for Obj {
fn deserialize<D>(deserializer: D) -> Result<Obj, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(ObjVisitor)
}
}
impl FromStr for Obj {
type Err = Void;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Obj {
x: 0,
y: s.to_owned(),
})
}
}
#[derive(Debug, Deserialize)]
struct Simple {
obj: Obj,
}
#[derive(Debug, Deserialize)]
struct InsideHashMap {
objs: HashMap<String, Obj>,
}
fn main() {
// Basic deserialization of Obj
let toml = r#"
x = 5
y = "hello"
"#;
let obj: Obj = toml::from_str(toml).unwrap();
println!("{:?}", obj);
// Basic deserialization of Obj as a field in a struct
let toml = r#"
[obj]
x = 5
y = "hello"
"#;
let simple: Simple = toml::from_str(toml).unwrap();
println!("{:?}", simple);
// Basic deserialization of Obj as a field in a struct as a string or struct
let toml = r#"
obj = "hello"
"#;
let simple: Simple = toml::from_str(toml).unwrap();
println!("{:?}", simple);
// Deserialization of an Obj inside a HashMap
let toml = r#"
[objs]
a = { x = 5, y = "hello" }
"#;
let working: InsideHashMap = toml::from_str(toml).unwrap();
println!("{:?}", working);
// Deserialization of Obj inside a HashMap field as a string or struct
let toml = r#"
[objs]
a = "hello"
"#;
let not_working: InsideHashMap = toml::from_str(toml).unwrap();
println!("{:?}", not_working);
}
Эта работа, как и ожидалось.