serde_describe 0.2.5

Make non-self-describing serde formats behave like they're self-describing.
Documentation
pub(crate) trait LosslessCast<IntoT> {
    fn lossless_cast(self) -> Option<IntoT>;
}

macro_rules! impl_lossless_cast {
    ($($int:ident),+; $($float:ident),+; ) => {
        impl_lossless_cast! { @try_from_many_to_many; ($($int,)+); ($($int,)+) }
        impl_lossless_cast! { @int_to_float_many_to_many; ($($int,)+); ($($float,)+) }
    };
    (@try_from_many_to_many; ($($from:ident,)+); $to:tt) => {
        $(
            impl_lossless_cast! { @try_from_one_to_many; $from; $to }
        )+
    };
    (@try_from_one_to_many; $from:ident; ($($to:ident,)+)) => {
        $(
            impl_lossless_cast! { @try_from_one; $from; $to }
        )+
    };
    (@try_from_one; $from:ident; $to:ident) => {
        impl LosslessCast<$to> for $from {
            #[inline]
            fn lossless_cast(self) -> Option<$to> {
                $to::try_from(self).ok()
            }
        }
    };
    (@int_to_float_many_to_many; $ints:tt; ($($float:ident,)+)) => {
        $(
            impl LosslessCast<$float> for $float {
                #[inline]
                fn lossless_cast(self) -> Option<$float> {
                    Some(self)
                }
            }

            impl_lossless_cast! { @int_to_float_one_to_many; $ints; $float }
        )+
    };
    (@int_to_float_one_to_many; ($($int:ident,)+); $float:ident) => {
        $(
            impl_lossless_cast! { @int_to_float_one; $int; $float }
        )+
    };
    (@int_to_float_one; $int:ident; $float:ident) => {
        impl LosslessCast<$int> for $float {
            #[inline]
            fn lossless_cast(self) -> Option<$int> {
                if self.is_finite() && (self as $int as $float) == self {
                    Some(self as $int)
                } else {
                    None
                }
            }
        }

        impl LosslessCast<$float> for $int {
            #[inline]
            fn lossless_cast(self) -> Option<$float> {
                if (self as $float).is_finite() && (self as $float as $int) == self {
                    Some(self as $float)
                } else {
                    None
                }
            }
        }
    };
}

impl_lossless_cast! {
    u8, u16, u32, u64, u128,
    i8, i16, i32, i64, i128;
    f32, f64;
}

impl LosslessCast<f64> for f32 {
    #[inline]
    fn lossless_cast(self) -> Option<f64> {
        Some(f64::from(self))
    }
}

impl LosslessCast<f32> for f64 {
    #[inline]
    fn lossless_cast(self) -> Option<f32> {
        None
    }
}