From IRC:
hmm, anyone know a way to treat serde_json::Value::Null and a field not existing differently without a custom deserialize?
ideally I'd have a type Option
This is one possible approach:
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
use serde::{Deserialize, Deserializer};
#[derive(Deserialize, Debug)]
struct S {
#[serde(default, deserialize_with = "deserialize_some")]
a: Option<Option<i32>>,
}
// Any value that is present is considered Some value, including null.
fn deserialize_some<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
where T: Deserialize<'de>,
D: Deserializer<'de>
{
Deserialize::deserialize(deserializer).map(Some)
}
fn main() {
println!("{:?}", serde_json::from_str::<S>("{}").unwrap());
println!("{:?}", serde_json::from_str::<S>("{\"a\":null}").unwrap());
println!("{:?}", serde_json::from_str::<S>("{\"a\":1}").unwrap());
}
That's a pretty awesome approach! Thank you, I will be using that.
The context for this is a server which sends "update" json messages - a field missing from the message means that nothing has changed, but a null value means the old data should be removed.
That custom method might actually be more useful than any built-in option for Option<Option<>> for me even, because (I think) it'll work even for a plain Option<InnerType> fields. I'm using a macro_rules!() macro to create the update struct to go along with the regular struct, so applying it to everything would make it much simplier.
I used this in the https://github.com/vitiral/jrpc crate! Thanks!
Is there a way to apply deserialize_with to all fields of a struct? It is kinda tedious to write that annotation above every field in my struct when i want every field to behave as explained above.
@cars10 I think you could wrap this into a new type and then implement Serialize/Deserialize for that type?
Most helpful comment
This is one possible approach: