It's not impossible to serialize a HashMap
, it's just not possible to serialize it as a JSON object with non-string keys, because JSON objects only have string keys. So the way that serde_json
deals with this is by panicking when passed a HashMap
whose keys are not stringy.
let key = format!("{{offset: {}, count: {}}}", k.offset, k.count);
Ok, so this is the format you've chosen to stringify Request
. Have you also written a function that turns a string like {offset: 10, count: 20}
back into a Request
? You'll need to use that in the deserialize
function. (Or you could just use serde_json::to_string
and serde_json::from_str
, which do the hard work for you.)
The right way is to write a struct and implement serde::de::Visitor
for it such that calling visit_map
constructs the HashMap<Request, u32>
.
The easy way is to just deserialize to a HashMap<String, u32>
and convert it to a HashMap<Request, u32>
after the fact:
pub(super) fn deserialize<'de, D: Deserializer<'de>>(des: D) -> Result<Attr, D::Error> {
let attr: HashMap<String, u32> = serde::Deserialize::deserialize(des)?;
Ok(attr
.into_iter()
.map(|(k, v)| {
(
// assuming the serialize function calls serde_json::to_string
serde_json::from_str(&k).expect("Could not deserialize Request"),
v,
)
})
.collect())
}
This is wasteful of space and probably also slower than doing it the "right" way. But it gets you moving (and if serialization is a bottleneck you probably shouldn't be using JSON).
I'd like to assume that serde_with
does things the "right" way. If that's the case I'd probably use that instead. IIUC this is equivalent to @jonasbb's first suggestion:
#[serde_as]
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)]
struct Attributes {
#[serde_as(as = "HashMap<serde_with::json::JsonString, _>")]
pub attr: HashMap<Request, u32>,
}