I am unsure how to implement the following design pattern in the best way.
Background
I have a HashMap type defined as
type MyMap<T> = HashMap<String, Option<T>>
Using serde
, when serializing I want to only serialize the map's keys as an array, and when deserializing from an array of keys I want to initialize all values to None
.
Examples
Serialization (MyMap<i32>)
{
"k1": None,
"k2": Some(0)
}
should serialize to
["k1", "k2"]
Deserialization (MyMap<i32>)
["k1", "k2"]
should deserialize to
{
"k1": None,
"k2": None
}
I would like to accomplish this using serde
's serialize_with
and deserialize_with
field attributes.
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct MyStruct {
#[serde(serialize_with = "serialize_my_map")]
#[serde(deserialize_with = "deserialize_my_map")]
i32_map: MyMap<i32>,
#[serde(serialize_with = "serialize_my_map")]
#[serde(deserialize_with = "deserialize_my_map")]
f64_map: MyMap<f64>,
}
Attempt
I tried to create a serialize_my_map
and deserialize_my_map
functions to accomplish this.
use std::fmt;
use serde::de;
use serde::ser::{SerializeSeq, Serializer};
fn serialize_my_map<S, T>(
map: &MyMap<T>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(map.len()))?;
for (k, _) in map.iter() {
seq.serialize_element(&k)?;
}
seq.end()
}
fn deserialize_my_map<'de, D, T>(
deserializer: D,
) -> Result<MyMap<T>, D::Error>
where
D: de::Deserializer<'de>,
{
struct ElmVisitor;
impl<'de> de::Visitor<'de> for ElmVisitor {
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: de::SeqAccess<'de>,
{
let mut map: MyMap<T>;
match seq.size_hint() {
None => map = MyMap::new(),
Some(s) => map = MyMap::with_capacity(s),
};
while let Some(key) = seq.next_element::<T>()? {
map.insert(key, None);
}
Ok(map)
}
}
deserializer.deserialize_seq(ElmVisitor)
}
However, this won't work for several reasons.
- The function signatures of
serialize_my_map
anddeserialize_my_map
do not match those required byserde
'sserialize_with
anddeserailize_with
attributes. - In
deserialize_my_map
the outer generic typeT
is being used inside the implementation of ofde::Visitor for ElmVisitor
.
Any help on how to accomplish this would be greatly appreciated.
Rust Playground: Rust Playground