macro_rules! integer_helper {
($ty:ident, $deserialize_name:ident, $trait: ident, $from_name:ident, $visitor:ident) => {
+ #[doc(hidden)]
pub trait $trait: Sized + Default {
fn $from_name(value: $ty) -> Self;
}
integer_helper!(i16, deserialize_i16, FromI16, from_i16, I16Visitor);
integer_helper!(i32, deserialize_i32, FromI32, from_i32, I32Visitor);
integer_helper!(i64, deserialize_i64, FromI64, from_i64, I64Visitor);
+
+// float helpers:
+
+macro_rules! float_helper {
+ ($ty:ident, $deserialize_name:ident, $visitor:ident) => {
+ pub fn $deserialize_name<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ T: FromF64,
+ {
+ deserializer.deserialize_any($visitor::<T>::new())
+ }
+
+ struct $visitor<T>(std::marker::PhantomData<T>);
+
+ impl<T> $visitor<T> {
+ fn new() -> Self {
+ Self(std::marker::PhantomData)
+ }
+ }
+
+ impl<'de, T: FromF64> serde::de::DeserializeSeed<'de> for $visitor<T> {
+ type Value = T;
+
+ fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ $deserialize_name(deserializer)
+ }
+ }
+
+ impl<'de, T> serde::de::Visitor<'de> for $visitor<T>
+ where
+ T: FromF64,
+ {
+ type Value = T;
+
+ fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(concat!("a ", stringify!($ty), "-ish..."))
+ }
+
+ fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ deserializer.deserialize_any(self)
+ }
+
+ fn visit_none<E>(self) -> Result<Self::Value, E> {
+ Ok(Default::default())
+ }
+
+ fn visit_f64<E: serde::de::Error>(self, value: f64) -> Result<Self::Value, E> {
+ Ok(T::from_f64(value))
+ }
+
+ fn visit_i128<E: serde::de::Error>(self, value: i128) -> Result<Self::Value, E> {
+ let conv = value as f64;
+ if conv as i128 == value {
+ Ok(T::from_f64(conv))
+ } else {
+ Err(E::invalid_value(Unexpected::Other("i128"), &self))
+ }
+ }
+
+ fn visit_i64<E: serde::de::Error>(self, value: i64) -> Result<Self::Value, E> {
+ let conv = value as f64;
+ if conv as i64 == value {
+ Ok(T::from_f64(conv))
+ } else {
+ Err(E::invalid_value(Unexpected::Signed(value), &self))
+ }
+ }
+
+ fn visit_u128<E: serde::de::Error>(self, value: u128) -> Result<Self::Value, E> {
+ let conv = value as f64;
+ if conv as u128 == value {
+ Ok(T::from_f64(conv))
+ } else {
+ Err(E::invalid_value(Unexpected::Other("u128"), &self))
+ }
+ }
+
+ fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Self::Value, E> {
+ let conv = value as f64;
+ if conv as u64 == value {
+ Ok(T::from_f64(conv))
+ } else {
+ Err(E::invalid_value(Unexpected::Unsigned(value), &self))
+ }
+ }
+
+ fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
+ let value = value
+ .parse()
+ .map_err(|_| E::invalid_value(Unexpected::Str(value), &self))?;
+ self.visit_f64(value)
+ }
+ }
+ };
+}
+
+#[doc(hidden)]
+pub trait FromF64: Sized + Default {
+ fn from_f64(value: f64) -> Self;
+}
+
+impl FromF64 for f32 {
+ #[inline(always)]
+ fn from_f64(f: f64) -> f32 {
+ f as f32
+ }
+}
+
+impl FromF64 for f64 {
+ #[inline(always)]
+ fn from_f64(f: f64) -> f64 {
+ f
+ }
+}
+
+impl<T: FromF64> FromF64 for Option<T> {
+ #[inline(always)]
+ fn from_f64(f: f64) -> Option<T> {
+ Some(T::from_f64(f))
+ }
+}
+
+float_helper!(f32, deserialize_f32, F32Visitor);
+float_helper!(f64, deserialize_f64, F64Visitor);