serde
serde copied to clipboard
Lack of deserialisation context
I have to transform deserialised values before putting them out based on external map. I got stuck on how to implement this without some kind of context I would use in Deserialise:
pub struct SomeData {
some_field: u32,
}
pub struct Context {
map: HashMap<&'static str, u32>,
}
impl<'de> Deserialize<'de> for SomeData {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct SomeDataVisitor {
context: Context,
};
impl<'de> Visitor<'de> for SomeDataVisitor {
type Value = SomeData;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("SomeData format")
}
fn visit_str<E>(self, value: &str) -> Result<SomeData, E>
where
E: de::Error,
{
let val = *self.context.map.get(value).unwrap_or(&0);
Ok(SomeData { some_field: val })
}
}
deserializer.deserialize_identifier(SomeDataVisitor { context: context })
}
}
Any ideas how to pass Context into the Deserialiser / Visitor are appreciated.
You can implement DeserializeSeed
for your Context
-- this will allow you to deserialize top-level SomeData
struct, but unfortunately, this approach is not composable
Yep, SomeData
is a part of a large model. In real world it could be struct Country
which has been previously serialised to the yaml as shortcuts:
counterparties:
- name: SomeCompany
location: GB # here is the reference to Country dictionary
contacts:
- name: John
address:
country: GB # and here too
city: London
- name: Bob
address: ...
GB
is shortcut for Country I wanna substitute from external dictionary (map).
As far as I understood DeserializeSeed approach requires passing context manually by invoking seq.next_element_seed(context)
each time it faces Country property. But it could not be done if object tree is complex, right?
But it could not be done if object tree is complex, right?
Yes, at least with serde's derives. Probably the more realistic approach is to deserialize into intermediate stateless structure and then convert it to the final one
I've tried different approaches and end up with the conclusion that it would be great to introduce new #derive DeserializeSeed
for such cases. What do you think about this?
Hi @mozalmic, hopefully you got this working. If there is still an issue, I would recommend following up in any of the resources shown in https://www.rust-lang.org/community. This library is one of the most widely used Rust libraries and plenty of people will be able to provide guidance about it.