use crate::{error::ToleranceError, Myth16, Myth32, Unit};
#[cfg(feature = "serde")]
use serde::{de::Visitor, Deserialize, Deserializer, Serialize};
use std::convert::TryFrom;
use std::fmt::{Debug, Display, Formatter};
use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
use std::str::FromStr;
#[cfg_attr(feature = "serde", derive(Serialize))]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
#[must_use]
pub struct Myth64(pub(crate) i64);
super::calc_with_myths!(Myth64, i64, Myth64, Myth32, Myth16);
super::from_myths!(Myth64, Myth32, Myth16);
super::from_number!(Myth64, u32, u16, u8, i64, i32, i16, i8);
super::standard_myths!(Myth64, i64, u64, u32, u16, u8, usize, i64, i32, i16, i8, isize);
super::try_from_number!(Myth64, u64, usize, isize);
#[cfg(feature = "serde")]
super::de_serde!(Myth64, i64);
#[cfg(test)]
mod should {
use super::{Myth64, Unit};
use pretty_assertions::assert_eq;
#[test]
fn multiply() {
let d = Myth64(2_500_000);
let p1 = Myth64(100_000);
let p2 = Myth64(250_000);
assert_eq!(d, p1 * 25);
assert_eq!(d, 10 * p2);
}
#[test]
fn subtract() {
let s = Myth64(350_000);
let s1 = Myth64(100_000);
let s2 = Myth64(250_000);
assert_eq!(s1, s - s2);
assert_eq!(s2, s - s1);
}
#[test]
fn try_from_str() {
let d = Myth64::try_from("12345.12343").unwrap();
assert_eq!(d, Myth64(123_451_234));
let d = Myth64::try_from("6.02").unwrap();
assert_eq!(d, Myth64(60_200));
let d = Myth64::try_from("18").unwrap();
assert_eq!(d, Myth64(180_000));
let d = Myth64::try_from("0").unwrap();
assert_eq!(d, Myth64(0));
let d = Myth64::try_from("14.9300").unwrap();
assert_eq!(d, Myth64(149_300));
let d = Myth64::try_from(" +2.07").unwrap();
assert_eq!(d, Myth64(20_700));
let d = Myth64::try_from("-3.01").unwrap();
assert_eq!(d, Myth64(-30_100));
let d = Myth64::try_from(".01").unwrap();
assert_eq!(d, Myth64(100));
let d = Myth64::try_from(".01").unwrap();
assert_eq!(d, Myth64(100));
let d = Myth64::try_from("-.044").unwrap();
assert_eq!(d, Myth64(-440));
let d = Myth64::try_from("+.01").unwrap();
assert_eq!(d, Myth64(100));
let d = Myth64::try_from("-12345.12343").unwrap();
assert_eq!(d, -Myth64(123_451_234));
let d = Myth64::try_from("-12345.12346345").unwrap();
assert_eq!(d, -Myth64(123_451_234));
let d = Myth64::try_from("12345*12343");
assert!(d.is_err());
let d = Myth64::try_from(" ");
assert!(d.is_err());
let d = Myth64::try_from(" - ");
assert!(d.is_err());
let d = Myth64::try_from("+");
assert!(d.is_err());
let m = Myth64::from(5445.234);
let m_s = m.to_string();
assert_eq!("5445.234", m_s);
assert_eq!(Ok(m), Myth64::try_from(m_s));
}
#[test]
fn round() {
let m = Myth64(1_234_567);
assert_eq!(Myth64(1_234_570), m.round(Unit::MY));
assert_eq!(Myth64(1_200_000), m.round(Unit::CM));
assert_eq!(Myth64(10_000_000), Myth64(9_999_000).round(Unit::MM));
assert_eq!(Myth64(0), Myth64::from(-0.4993).round(Unit::MM));
assert_eq!(Myth64(-4990), Myth64::from(-0.4993).round(Unit::MY));
assert_eq!(Myth64(-10000), Myth64::from(-5000).round(Unit::MM));
let m = Myth64::from(340.993);
assert_eq!(10, *Unit::potency(1));
assert_eq!(Myth64(3_409_930), m.round(Unit::potency(1)));
assert_eq!(100, *Unit::potency(2));
assert_eq!(Myth64(3_409_900), m.round(Unit::potency(2)));
assert_eq!(1000, *Unit::potency(3));
assert_eq!(Myth64(3_410_000), m.round(Unit::potency(3)));
assert_eq!(Myth64(3_400_000), m.floor(Unit::potency(4)));
assert_eq!(-341.000, (-340.993_f64).floor());
assert_eq!(
Myth64(-3_410_000),
Myth64::from(-340.993).floor(Unit::potency(4))
);
assert_eq!(Myth64(0), Myth64(4_567).floor(Unit::potency(4)));
assert_eq!(Myth64(10_000), Myth64(5_567).round(Unit::potency(4)));
let m = Myth64(-67);
assert_eq!(Myth64(0), m.round(Unit::potency(3)));
let m = Myth64(-67);
assert_eq!(Myth64(-1_000), m.floor(Unit::potency(3)));
let m = Myth64(-67);
assert_eq!(Myth64(-100), m.floor(Unit::potency(2)));
}
#[test]
fn display() {
let m = Myth64(12455);
assert_eq!("1.2455", format!("{m}").as_str());
assert_eq!("1.246", format!("{m:.3}").as_str());
assert_eq!("1.2", format!("{m:.1}").as_str());
assert_eq!("1.2455", format!("{m:.7}").as_str());
assert_eq!("1", format!("{m:.0}").as_str());
assert_eq!("-1.2455", format!("{:.7}", -m).as_str());
let m = Myth64(-455);
assert_eq!("-0.046", format!("{m:.3}").as_str());
assert_eq!("-0.345", format!("{}", Myth64(-3450)).as_str());
assert_eq!("-455", format!("{m:#}").as_str());
let m = Myth64::from(4566.4689);
assert_eq!(format!("{m:.3}"), "4566.469");
assert_eq!(format!("{m:>15.2}"), " 4566.47");
assert_eq!(format!("{m:>010.4}"), "04566.4689");
let m = Myth64::ZERO;
assert_eq!(format!("{m:.2}"), "0.00");
}
#[test]
fn min_max() {
let max = Myth64::MAX;
let min = Myth64::MIN;
assert_eq!(max.0, 9_223_372_036_854_775_807);
assert_eq!(min.0, -9_223_372_036_854_775_808);
}
#[test]
fn as_unit() {
let m = Myth64::from(12456.832);
assert_eq!(m.as_unit(Unit::CM), 1245.6832);
assert_eq!(m.as_unit(Unit::METER), 12.456_832);
let m = Myth64::MAX;
assert_eq!(m.as_unit(Unit::KM), 922_337_203.685_477_6);
}
#[test]
fn sum() {
let m64s = (0..10).map(|d| Myth64::from(d * 10_000));
assert_eq!(Myth64::from(450_000), m64s.sum());
}
#[cfg(feature = "serde")]
mod serde {
use crate::Myth64;
use serde::{Deserialize, Serialize};
use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
#[test]
fn serialize_i64() {
let m = Myth64::from(12456.832);
assert_tokens(
&m,
&[
Token::NewtypeStruct { name: "Myth64" },
Token::I64(124_568_320),
],
);
}
#[test]
fn deserialize_string() {
assert_de_tokens_error::<Myth64>(
&[Token::String("nonumber")],
"invalid value: string \"nonumber\", expected 1.0",
);
assert_de_tokens(&Myth64::from(23.004), &[Token::String("23.004")]);
assert_de_tokens(&Myth64::from(0.04), &[Token::String(".04")]);
assert_de_tokens(&Myth64::from(0.04), &[Token::Str(".04")]);
}
#[test]
fn deserialize_f64() {
assert_de_tokens(&Myth64::from(23.004), &[Token::F64(23.004)]);
assert_de_tokens(&Myth64::from(0.0043), &[Token::F64(0.0043)]);
}
#[test]
fn deserialize_i64() {
assert_de_tokens(&Myth64::from(23.004), &[Token::I64(23_0040)]);
assert_de_tokens(&Myth64::from(0.0043), &[Token::I64(0_0043)]);
}
#[test]
fn deserialize_option() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct T {
w: Option<Myth64>,
}
let t1 = T {
w: Some(Myth64::from(23.004)),
};
assert_eq!(
"{\n \"w\": 230040\n}",
serde_json::to_string_pretty(&t1).unwrap()
);
assert_de_tokens(
&t1,
&[
Token::Struct { name: "T", len: 1 },
Token::Str("w"),
Token::Some,
Token::I64(23_0040),
Token::StructEnd,
],
);
let t2 = T { w: None };
assert_de_tokens(
&t2,
&[
Token::Struct { name: "T", len: 1 },
Token::Str("w"),
Token::None,
Token::StructEnd,
],
);
assert_de_tokens(
&Some(Myth64::from(0.0043)),
&[Token::Some, Token::String(".0043")],
);
assert_de_tokens(&None::<Myth64>, &[Token::None]);
}
#[test]
fn deserialize_i32() {
assert_de_tokens(&Myth64::from(23.004), &[Token::I32(23_0040)]);
assert_de_tokens(&Myth64::from(0.0043), &[Token::I32(0_0043)]);
}
#[test]
fn deserialize_json() {
let m = serde_json::from_slice(b"23.004").unwrap();
assert_eq!(Myth64::from(23.004), m);
let m = serde_json::from_slice(b"\".004\"").unwrap();
assert_eq!(Myth64::from(0.004), m);
let m: Myth64 = serde_json::from_slice(b"4000").unwrap();
assert_eq!(Myth64::from(0.4), m);
let m: Option<Myth64> = serde_json::from_slice(b"4000").unwrap();
assert_eq!(Some(Myth64::from(0.4)), m);
let m: Option<Myth64> = serde_json::from_slice(b"null").unwrap();
assert_eq!(None, m);
let m: Option<Myth64> = serde_json::from_slice(b"\"0.4\"").unwrap();
assert_eq!(Some(Myth64::from(0.4)), m);
}
#[test]
fn serialize_to_myth_string() {
use crate::into_string;
use serde::*;
#[derive(Serialize)]
struct T2 {
#[serde(serialize_with = "into_string")]
width: Myth64,
#[serde(serialize_with = "into_string")]
length: Option<Myth64>,
}
let t = T2 {
width: Myth64::from(123455),
length: Some(Myth64::from(1230.0)),
};
assert_eq!(
r#"{"width":"12.3455","length":"1230.0"}"#,
serde_json::to_string(&t).unwrap()
);
let t = T2 {
width: Myth64::from(123.4),
length: None,
};
assert_eq!(
r#"{"width":"123.4","length":null}"#,
serde_json::to_string(&t).unwrap()
);
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct T3 {
width: Option<Myth64>,
}
let t = T3 { width: None };
assert_eq!(r#"{"width":null}"#, serde_json::to_string(&t).unwrap());
assert_eq!(serde_json::from_str::<T3>(r#"{"width":null}"#).unwrap(), t);
assert_eq!(
serde_json::from_str::<T3>(r#"{"width": "123.34"}"#).unwrap(),
T3 {
width: Some(Myth64::from(123.34))
}
);
}
}
}