You will need to write you own deserializer, because, when you think about it, Map
, in and of itself, cannot be Deserialize
. It can only be deserialized when within the bigger picture. So, if you want a helper auto-Deserialize
type, that type would be one with a name: Option<String>
:
- Relevant logic:
#[derive(Deserialize)]
struct RawMap {
#[serde(default)]
name: Option<String>,
#[serde(default = "default_false_value")]
collisions: bool,
}
while let Some((key, value)) = access.next_entry::<String, RawMap>()? {
let value = Map {
collisions: value.collisions,
name: value.name.unwrap_or_else(|| key.clone()),
};
map.insert(key, value);
}
Full snippet (manual impl of Deserialize
based off Deserialize for custom map type ยท Serde):
#[derive(Deserialize, Debug)]
pub struct Root {
#[serde(deserialize_with = "deserialize_maps")]
pub maps: HashMap<String, Map>,
}
fn default_false_value () -> bool { false }
#[derive(Debug, /* Deserialize */)]
pub
struct Map {
pub
name: String,
pub
collisions: bool,
}
fn deserialize_maps<'de, D> (deserializer: D)
-> Result<HashMap<String, Map>, D::Error>
where
D : ::serde::de::Deserializer<'de>,
{
// Based off https://serde.rs/deserialize-map.html
use ::serde::de::*;
type MyMap = HashMap<String, Map>;
struct MyMapVisitor;
impl<'de> Visitor<'de> for MyMapVisitor {
// The type that our Visitor is going to produce.
type Value = MyMap;
// Format a message stating what data this Visitor expects to receive.
fn expecting(&self, formatter: &mut ::core::fmt::Formatter)
-> ::core::fmt::Result
{
formatter.write_str("a map")
}
// Deserialize MyMap from an abstract "map" provided by the
// Deserializer. The MapAccess input is a callback provided by
// the Deserializer to let us see each entry in the map.
fn visit_map<M>(self, mut access: M)
-> Result<Self::Value, M::Error>
where
M : MapAccess<'de>,
{
let mut map = MyMap::with_capacity(access.size_hint().unwrap_or(0));
#[derive(Deserialize)]
struct RawMap {
#[serde(default)]
name: Option<String>,
#[serde(default = "default_false_value")]
collisions: bool,
}
// While there are entries remaining in the input, add them
// into our map.
while let Some((key, value)) = access.next_entry()? {
// type-hint `key`
let _: String = key;
// Extract fields and type-hint `value`
let RawMap { name, collisions } = value;
let value = Map {
collisions,
name: name.unwrap_or_else(|| key.clone()),
};
map.insert(key, value);
}
Ok(map)
}
}
deserializer.deserialize_map(MyMapVisitor)
}