Description
I'm not sure if I'm doing something wrong here, but I'm trying to write a type that can deserialize from either strings or integers.
Initially I did this using an untagged
enumeration variant to do the heavy lifting - see here.
This worked fine until an upstream crate enabled the arbitrary_precision
feature. I found #559 and serde-rs/serde#1183 on the topic, and so opted to implement a custom visitor as these seem to suggest the issue was in the untagged variant generation.
I therefore tried using a custom visitor
struct NumberVisitor<T> {
_phantom: PhantomData<T>,
}
impl<'de, T> serde::de::Visitor<'de> for NumberVisitor<T>
where
T: FromStr,
<T as FromStr>::Err: std::error::Error,
T: FromPrimitive,
{
type Value = NumberDeserialize<T>;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("an integer or string")
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: Error,
{
T::from_i64(v)
.map(NumberDeserialize)
.ok_or_else(|| serde::de::Error::custom("cannot parse from i64"))
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: Error,
{
T::from_u64(v)
.map(NumberDeserialize)
.ok_or_else(|| serde::de::Error::custom("cannot parse from u64"))
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: Error,
{
T::from_f64(v)
.map(NumberDeserialize)
.ok_or_else(|| serde::de::Error::custom("cannot parse from f64"))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
v.parse()
.map(NumberDeserialize)
.map_err(serde::de::Error::custom)
}
}
impl<'de, T> serde::Deserialize<'de> for NumberDeserialize<T>
where
T: FromStr,
<T as FromStr>::Err: std::error::Error,
T: FromPrimitive,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_any(NumberVisitor {
_phantom: Default::default(),
})
}
}
However, this runs into an issue where with arbitrary_precision
, rather than calling visit_i* or similar, it calls visit_map with a custom map visitor for numeric types?! It would appear this then has a special-cased key of $serde_json::private::Number
.
I'm not really sure what I'm supposed to do here, it would appear enabling arbitrary_precision
makes it so that serializers don't decode numbers as numbers? Any help would be most appreciated.
As an aside whilst messing around with this I noticed enabling arbitrary_precision
makes this fail
let input = r#"{"$serde_json::private::Number":"hello"}"#;
let value = serde_json::from_str::<serde_json::Value>(input).unwrap();