use crate::cast::cast;
use crate::complex::OrdComplex;
use crate::float;
use crate::serdeize::{self, Data, PrecReq, PrecVal};
use crate::{Assign, Complex};
use gmp_mpfr_sys::mpfr;
use serde::de::{Deserialize, Deserializer, Error as DeError};
use serde::ser::{Serialize, Serializer};
impl Serialize for Complex {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let prec = self.prec();
let radix = if (prec.0 <= 32 || !self.real().is_normal())
&& (prec.1 <= 32 || !self.imag().is_normal())
{
10
} else {
16
};
let prec = PrecVal::Two(prec);
let value = self.to_string_radix(radix, None);
let data = Data { prec, radix, value };
serdeize::serialize("Complex", &data, serializer)
}
}
impl<'de> Deserialize<'de> for Complex {
fn deserialize<D>(deserializer: D) -> Result<Complex, D::Error>
where
D: Deserializer<'de>,
{
let (prec, radix, value) = de_data(deserializer)?;
let p = Complex::parse_radix(&value, radix).map_err(DeError::custom)?;
Ok(Complex::with_val(prec, p))
}
fn deserialize_in_place<D>(deserializer: D, place: &mut Complex) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
let (prec, radix, value) = de_data(deserializer)?;
let p = Complex::parse_radix(&value, radix).map_err(DeError::custom)?;
unsafe {
let parts = place.as_mut_real_imag();
mpfr::set_prec(parts.0.as_raw_mut(), cast(prec.0));
mpfr::set_prec(parts.1.as_raw_mut(), cast(prec.1));
}
place.assign(p);
Ok(())
}
}
fn de_data<'de, D>(deserializer: D) -> Result<((u32, u32), i32, String), D::Error>
where
D: Deserializer<'de>,
{
let Data { prec, radix, value } = serdeize::deserialize("Complex", PrecReq::Two, deserializer)?;
let prec = match prec {
PrecVal::Two(two) => two,
_ => unreachable!(),
};
serdeize::check_range(
"real precision",
prec.0,
float::prec_min(),
float::prec_max(),
)?;
serdeize::check_range(
"imaginary precision",
prec.1,
float::prec_min(),
float::prec_max(),
)?;
serdeize::check_range("radix", radix, 2, 36)?;
Ok((prec, radix, value))
}
impl Serialize for OrdComplex {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.as_complex().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for OrdComplex {
fn deserialize<D>(deserializer: D) -> Result<OrdComplex, D::Error>
where
D: Deserializer<'de>,
{
Complex::deserialize(deserializer).map(From::from)
}
fn deserialize_in_place<D>(deserializer: D, place: &mut OrdComplex) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
Complex::deserialize_in_place(deserializer, place.as_complex_mut())
}
}
#[cfg(test)]
mod tests {
use crate::cast::cast;
use crate::float::{self, Special};
use crate::{Assign, Complex};
use serde_json::json;
fn assert(a: &Complex, b: &Complex) {
assert_eq!(a.prec(), b.prec());
assert_eq!(a.as_ord(), b.as_ord());
}
enum Check<'a> {
SerDe(&'a Complex),
De(&'a Complex),
DeError((u32, u32), &'a str),
}
impl Check<'_> {
fn check(self, radix: i32, value: &'static str) {
use crate::serdeize::test::*;
use byteorder::{LittleEndian, WriteBytesExt};
use serde_test::Token;
use std::io::Write;
let prec = match self {
Check::SerDe(c) | Check::De(c) => c.prec(),
Check::DeError(p, _) => p,
};
let tokens = [
Token::Struct {
name: "Complex",
len: 3,
},
Token::Str("prec"),
Token::Tuple { len: 2 },
Token::U32(prec.0),
Token::U32(prec.1),
Token::TupleEnd,
Token::Str("radix"),
Token::I32(radix),
Token::Str("value"),
Token::Str(value),
Token::StructEnd,
];
let json = json!({
"prec": [prec.0, prec.1],
"radix": radix,
"value": value,
});
let mut bincode = Vec::<u8>::new();
bincode.write_u32::<LittleEndian>(prec.0).unwrap();
bincode.write_u32::<LittleEndian>(prec.1).unwrap();
bincode.write_i32::<LittleEndian>(radix).unwrap();
bincode
.write_u64::<LittleEndian>(cast(value.len()))
.unwrap();
bincode.write_all(value.as_bytes()).unwrap();
match self {
Check::SerDe(c) => {
serde_test::assert_tokens(c.as_ord(), &tokens);
json_assert_value(c, &json, assert);
bincode_assert_value(c, &bincode, assert, Complex::new(1));
}
Check::De(c) => {
serde_test::assert_de_tokens(c.as_ord(), &tokens);
json_assert_de_value(c, json, assert);
bincode_assert_de_value(c, &bincode, assert);
}
Check::DeError(_, msg) => {
serde_test::assert_de_tokens_error::<Complex>(&tokens, msg);
}
}
}
}
#[test]
fn check() {
let prec_min = float::prec_min();
let real_prec_err = format!("real precision 0 less than minimum {}", prec_min);
let imag_prec_err = format!("imaginary precision 0 less than minimum {}", prec_min);
Check::DeError((0, 32), &real_prec_err).check(10, "0");
Check::DeError((40, 0), &imag_prec_err).check(10, "0");
Check::DeError((40, 32), "radix 1 less than minimum 2").check(1, "0");
Check::DeError((40, 32), "radix 37 greater than maximum 36").check(37, "0");
let mut c = Complex::new((40, 32));
Check::SerDe(&c).check(10, "(0.0 0.0)");
Check::De(&c).check(10, "0");
c = -c;
Check::SerDe(&c).check(10, "(-0.0 -0.0)");
Check::De(&c).check(16, "(-0 -0)");
c.assign((Special::Nan, 15.0));
Check::SerDe(&c).check(10, "(NaN 1.5000000000e1)");
Check::De(&c).check(10, "(+@nan@ 15)");
c = -c;
Check::SerDe(&c).check(10, "(-NaN -1.5000000000e1)");
c.assign((15.0, Special::Nan));
Check::SerDe(&c).check(16, "(f.0000000000 @NaN@)");
Check::De(&c).check(10, "(1.5e1 nan)");
Check::De(&c).check(15, "(1.0@1 @nan@)");
}
}