#[cfg(test)]
mod tests;
use crate::{Ratio, try_from_str};
use core::{
fmt::{self, Formatter},
marker::PhantomData,
ops::Mul,
str::FromStr,
};
use num_integer::Integer;
use num_traits::Pow;
use serde::de::{self, Deserialize, Deserializer, Unexpected, Visitor};
#[derive(Clone, Copy, Debug)]
pub struct Rational<T>(pub Ratio<T>);
impl<'de, T> Deserialize<'de> for Rational<T>
where
T: Clone
+ From<u8>
+ FromStr
+ Integer
+ for<'a> Mul<&'a T, Output = T>
+ Pow<usize, Output = T>,
{
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct RationalVisitor<T> {
_x: PhantomData<fn() -> T>,
}
impl<T> Visitor<'_> for RationalVisitor<T>
where
T: Clone
+ From<u8>
+ FromStr
+ Integer
+ for<'a> Mul<&'a T, Output = T>
+ Pow<usize, Output = T>,
{
type Value = Rational<T>;
fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter.write_str("struct Rational")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
try_from_str(v).map_or_else(
|_| {
Err(E::invalid_value(
Unexpected::Str(v),
&"a rational number in fraction or decimal notation",
))
},
|val| Ok(Rational(val)),
)
}
}
deserializer.deserialize_str(RationalVisitor { _x: PhantomData })
}
}