Sertde + TOML handles deserialization of missing Option
fields by producing None
:
#[test]
fn toml_u32() {
#[derive(Deserialize, Debug)]
struct X { a: Option<u32> }
assert_eq!(parse::<X>("a = 10").a, Some(10));
assert_eq!(parse::<X>(" ").a, None );
}
Where parse
is this helper function:
fn parse<'d, D: Deserialize<'d>>(input: &'d str) -> D {
toml::from_str(input).unwrap()
}
Can this give-me-None-if-field-missing behaviour be implemented when using [serde(dezerialize_with = ...)]
?
My attempts give me "missing field"
errors:
#[test]
fn toml_u32_deserialize_with() {
#[derive(Deserialize, Debug)]
struct X {
#[serde(deserialize_with = "bbb")]
a: Option<u32>
}
assert_eq!(parse::<X>("a = 10").a, Some(10));
assert_eq!(parse::<X>(" ").a, None );
fn bbb<'d, D: Deserializer<'d>>(deserializer: D) -> Result<Option<u32>, D::Error> {
Ok(Option::<u32>::deserialize(deserializer)?)
}
}
gives the error
panicked at 'called `Result::unwrap()` on an `Err` value: Error { inner: ErrorInner { kind: Custom, line: None, col: 0, at: None, message: "missing field `a`", key: [] } }'
on the second assert_eq!
.
Background
I'm trying to parse optional fields whose types are physical quantities from uom
.
This works if the quantity is expressed as a number without units
#[test]
fn toml_time_without_units() {
#[derive(Deserialize, Debug)]
struct X { a: Option<Time> }
assert_eq!(parse::<X>("a = 2").a, Some(ps(2.)));
assert_eq!(parse::<X>(" ").a, None );
}
with the base unit of the quantity being used implicitly, but this defeats half of the point of uom
: ensuring that units are explicit! uom
provides parsers for numbers-with-units:
let t: Time = "2 ps".parse()?;
assert_eq!(t, ps(2.));
let t: Time = "2 ns".parse()?; // `ns` instead of `ps`
assert_eq!(t, ps(2000.));
so I want these to be used in the deserialization process.
In other words, I want to pass tests like these:
#[test]
fn toml_time_with_units() {
#[derive(Deserialize, Debug)]
struct X {
#[serde(deserialize_with = "bbb")]
a: Option<Time>
}
assert_eq!(parse::<X>(r#"a = "2 ps""#).a, Some(ps(2. )));
assert_eq!(parse::<X>(r#"a = "2 ns""#).a, Some(ps(2000.)));
assert_eq!(parse::<X>(r#" "#).a, None );
}
I haven't added the uom
examples to the playground, as uom
is not available there.