use serde::{Deserialize, Deserializer, Serialize, Serializer};
use oxinum_core::Sign;
use oxinum_int::native::BigUint;
use super::float::{BigFloat, FloatClass};
mod sign_serde {
use oxinum_core::Sign;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub(super) fn serialize<S: Serializer>(s: &Sign, ser: S) -> Result<S::Ok, S::Error> {
bool::from(*s).serialize(ser)
}
pub(super) fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<Sign, D::Error> {
bool::deserialize(de).map(Sign::from)
}
}
mod class_serde {
use super::FloatClass;
use serde::{de::Error, Deserialize, Deserializer, Serializer};
pub(super) fn serialize<S: Serializer>(class: &FloatClass, s: S) -> Result<S::Ok, S::Error> {
let name = match class {
FloatClass::Finite => "Finite",
FloatClass::Infinite => "Infinite",
FloatClass::Nan => "Nan",
};
s.serialize_str(name)
}
pub(super) fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<FloatClass, D::Error> {
let s = String::deserialize(d)?;
match s.as_str() {
"Finite" => Ok(FloatClass::Finite),
"Infinite" => Ok(FloatClass::Infinite),
"Nan" => Ok(FloatClass::Nan),
other => Err(D::Error::unknown_variant(
other,
&["Finite", "Infinite", "Nan"],
)),
}
}
}
#[derive(Serialize, Deserialize)]
struct BigFloatRepr {
#[serde(default)]
#[serde(with = "class_serde")]
class: FloatClass,
#[serde(with = "sign_serde")]
sign: Sign,
mantissa: BigUint,
exponent: i64,
precision: u32,
}
impl TryFrom<BigFloatRepr> for BigFloat {
type Error = String;
fn try_from(r: BigFloatRepr) -> Result<Self, Self::Error> {
if r.precision == 0 {
return Err("BigFloat precision must be > 0".to_string());
}
match r.class {
FloatClass::Nan => Ok(BigFloat::nan(r.precision)),
FloatClass::Infinite => Ok(if r.sign == Sign::Negative {
BigFloat::neg_infinity(r.precision)
} else {
BigFloat::infinity(r.precision)
}),
FloatClass::Finite => {
if r.mantissa.is_zero() {
Ok(BigFloat::zero(r.precision))
} else {
let bl = r.mantissa.bit_length() as u32;
if bl != r.precision {
return Err(format!(
"BigFloat invariant violated: mantissa bit_length {bl} != precision {}",
r.precision
));
}
Ok(BigFloat {
class: FloatClass::Finite,
sign: r.sign,
mantissa: r.mantissa,
exponent: r.exponent,
precision: r.precision,
})
}
}
}
}
}
impl Serialize for BigFloat {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
BigFloatRepr {
class: self.class,
sign: self.sign,
mantissa: self.mantissa.clone(),
exponent: self.exponent,
precision: self.precision,
}
.serialize(s)
}
}
impl<'de> Deserialize<'de> for BigFloat {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
BigFloatRepr::deserialize(d)
.and_then(|r| BigFloat::try_from(r).map_err(serde::de::Error::custom))
}
}