fixed_num_validator/
lib.rs

1pub use bigdecimal::BigDecimal;
2use std::str::FromStr;
3use std::fmt::{Debug, Display};
4use fixed_num_helper::*;
5
6#[derive(Clone, Debug)]
7pub struct Series {
8    pub seed: u64,
9    pub int_prec: RandRange,
10    pub frac_prec: RandRange,
11}
12
13impl Series {
14    pub fn new(int_prec: impl IntoRandRange, frac_prec: impl IntoRandRange) -> Self {
15        let int_prec = int_prec.into_rand_range();
16        let frac_prec = frac_prec.into_rand_range();
17        Self {
18            seed: 0,
19            int_prec,
20            frac_prec,
21        }
22    }
23}
24
25pub fn series_str<T>(cfg: Series) -> Vec<String>
26where T: Rand + Display {
27    let count = 10_000;
28    let seed_base = cfg.seed * 1_000_000;
29    (0..count)
30        .map(|i| T::rand(seed_base + i, cfg.int_prec.clone(), cfg.frac_prec.clone()))
31        .map(|t| format!("{t}"))
32        .collect()
33}
34
35pub fn series_pair1<A, B>(mut cfg: Series) -> Vec<(A, B)> where
36A: Rand + Display + FromStr<Err:Debug>,
37B: FromStr<Err:Debug> {
38    if cfg.seed == 0 { cfg.seed = 7; }
39    let vec_str = series_str::<A>(cfg);
40    let a_vec = vec_str.iter().map(|a| A::from_str(a).unwrap()).collect::<Vec<_>>();
41    let b_vec = vec_str.iter().map(|a| B::from_str(a).unwrap()).collect::<Vec<_>>();
42    a_vec.into_iter().zip(b_vec.into_iter()).collect::<Vec<_>>()
43}
44
45pub fn series_pair2<A, B>(mut cfg1: Series, mut cfg2: Series) -> Vec<((A, B), (A, B))> where
46A: Rand + Display + FromStr<Err:Debug>,
47B: FromStr<Err:Debug> {
48    if cfg1.seed == 0 { cfg1.seed = 7; }
49    if cfg2.seed == 0 { cfg2.seed = 17; }
50    series_pair1(cfg1).into_iter().zip(series_pair1(cfg2).into_iter()).collect()
51}
52
53pub fn fuzzy1<A, B>(cfg1: Series, f: impl Fn(A, B)) where
54    A: Rand + Display + FromStr<Err:Debug>,
55    B: FromStr<Err:Debug> {
56    for (a, b) in series_pair1::<A, B>(cfg1) {
57        f(a, b);
58    }
59}
60
61pub fn fuzzy2<A, B>(cfg1: Series, cfg2: Series, f: impl Fn((A, B), (A, B))) where
62A: Rand + Display + FromStr<Err:Debug>,
63B: FromStr<Err:Debug> {
64    for (a, b) in series_pair2::<A, B>(cfg1, cfg2) {
65        f(a, b);
66    }
67}
68
69pub fn should_panic<T: Debug>(f: impl FnOnce() -> T + std::panic::UnwindSafe, desc: &str) {
70    let result = std::panic::catch_unwind(|| f());
71    assert!(result.is_err(), "Expected panic, but got: {result:?} in {desc}");
72}
73
74
75pub fn cmp<T>(a: T, b: BigDecimal) -> Result<(), String>
76where T: Copy + Display {
77    let a_str = format!("{a:.19}");
78    let b_str = format!("{:.19}", b.with_scale(19));
79    if a_str == b_str {
80        Ok(())
81    } else {
82        Err(format!("Mismatch: {a_str} != {b_str}"))
83    }
84}
85
86pub trait ShouldEq<T> {
87    fn should_eq(self, other: T);
88}
89
90impl<T> ShouldEq<BigDecimal> for T
91where T: Display {
92    fn should_eq(self, other: BigDecimal) {
93        let a_str = format!("{self:.19}");
94        let b_str = format!("{:.19}", other.with_scale(19));
95        assert_eq!(a_str, b_str, "Mismatch: {a_str} != {b_str}");
96    }
97}
98
99pub fn should_eq<A, B>(a: A, b: B)
100where A: ShouldEq<B> {
101    a.should_eq(b);
102}
103
104#[macro_export]
105macro_rules! check {
106    ( [] $cases:tt ) => {};
107    ( [$f:expr $(, $($fns:tt)*)?] $cases:tt ) => {
108        check! { @1 $f, $cases }
109        check! { [$($($fns)*)?] $cases }
110    };
111    ( @1 $f:expr, {}) => {
112
113    };
114    ( @1 $f:expr, { $args:tt => FAIL $(, $($ts:tt)* )? } ) => {
115        check! { @2 $f, $args => FAIL }
116        check! { @1 $f, { $($($ts)*)? } }
117    };
118    ( @1 $f:expr, { $args:tt => $out:expr $(, $($ts:tt)* )? } ) => {
119        check! { @2 $f, $args => $out }
120        check! { @1 $f, { $($($ts)*)? } }
121    };
122    ( @2 $f:expr, ($($args:tt)*) => FAIL ) => {
123        should_panic(|| $f($($args)*).unwrap_all(), stringify!($f($($args)*) != FAIL));
124    };
125    ( @2 $f:expr, ($($args:tt)*) => $out:expr ) => {
126        assert_eq!($f($($args)*).unwrap_all(), $out, stringify!($f($($args)*) != $out));
127    };
128}