chinese_numerals/
macros.rs

1use crate::{
2    ChineseNumeral, Error, LongScaleInt, MidScaleInt, MyriadScaleInt, ShortScaleInt, Sign,
3};
4
5#[cfg(feature = "bigint")]
6use crate::{LongScaleBigInt, MidScaleBigInt, MyriadScaleBigInt};
7#[cfg(feature = "bigint")]
8use num_bigint::{BigInt, BigUint};
9
10macro_rules! impl_signed_int {
11    ($($int:ident, $data:ty),+ $(,)?) => {
12        $(impl crate::Signed for $int {
13            type Data = $data;
14
15            fn sign(&self) -> Sign {
16                self.sign
17            }
18
19            fn data(&self) -> &Self::Data {
20                &self.data
21            }
22        })+
23    };
24}
25
26impl_signed_int! {ShortScaleInt, u64, MyriadScaleInt, u128, MidScaleInt, u128, LongScaleInt, u128}
27
28#[cfg(feature = "bigint")]
29impl_signed_int! {MyriadScaleBigInt, BigUint, MidScaleBigInt, BigUint, LongScaleBigInt, BigUint}
30
31macro_rules! impl_disp {
32    ($($int:ident),+ $(,)?) => {
33        $(impl std::fmt::Display for $int {
34            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35                if f.alternate() {
36                    write!(f, "{}", self.to_uppercase_simp())
37                } else {
38                    write!(f, "{}", self.to_lowercase_simp())
39                }
40            }
41        })+
42    };
43}
44
45impl_disp! {ShortScaleInt, MyriadScaleInt, MidScaleInt, LongScaleInt}
46
47#[cfg(feature = "bigint")]
48impl_disp! {MyriadScaleBigInt, MidScaleBigInt, LongScaleBigInt}
49
50macro_rules! impl_try_from_uint {
51    ($($u:ty),+ $(,)?) => {
52        $(impl TryFrom<$u> for ShortScaleInt {
53            type Error = Error;
54
55            /// Performs the conversion. Returns [`Error`] if the absolute value is out of range.
56            fn try_from(value: $u) -> Result<Self, Self::Error> {
57                if value == 0 {
58                    Ok(Self::default())
59                } else if value <= Self::MAX_ABS as $u {
60                    Ok(Self {
61                        sign: Sign::Pos,
62                        data: value as u64,
63                    })
64                } else {
65                    Err(Error::ShortScaleOutOfRange(value as u128))
66                }
67            }
68        })+
69    };
70}
71
72impl_try_from_uint! {u64, u128, usize}
73
74macro_rules! impl_try_from_int {
75    ($($i:ty),+ $(,)?) => {
76        $(impl TryFrom<$i> for ShortScaleInt {
77            type Error = Error;
78
79            /// Performs the conversion. Returns [`Error`] if the absolute value is out of range.
80            fn try_from(value: $i) -> Result<Self, Self::Error> {
81                if value < -(Self::MAX_ABS as $i) || value > Self::MAX_ABS as $i {
82                    let abs = if value as i128 == i128::MIN {
83                        (i128::MAX as u128) + 1
84                    } else {
85                        value.abs() as u128
86                    };
87                    Err(Error::ShortScaleOutOfRange(abs))
88                } else if value.is_negative() {
89                    Ok(Self {
90                        sign: Sign::Neg,
91                        data: value.abs() as u64,
92                    })
93                } else if value.is_positive() {
94                    Ok(Self {
95                        sign: Sign::Pos,
96                        data: value as u64,
97                    })
98                } else {
99                    Ok(Self::default())
100                }
101            }
102        })+
103    };
104}
105
106impl_try_from_int! {i64, i128, isize}
107
108macro_rules! impl_from_int {
109    ($num:ident, $data:ty, $($pre:ty),+ $(,)?) => {
110        $(impl From<$pre> for $num {
111            fn from(value: $pre) -> Self {
112                if value == 0 {
113                    Self::default()
114                } else if value < 0 {
115                    let abs = if value == <$pre>::MIN {
116                        (<$pre>::MAX as $data) + 1
117                    } else {
118                        value.abs() as $data
119                    };
120                    Self {
121                        sign: Sign::Neg,
122                        data: abs,
123                    }
124                } else {
125                    Self {
126                        sign: Sign::Pos,
127                        data: value as $data,
128                    }
129                }
130            }
131        })+
132    };
133}
134
135impl_from_int! {ShortScaleInt, u64, i8, i16, i32}
136impl_from_int! {MyriadScaleInt, u128, i8, i16, i32, i64, i128, isize}
137impl_from_int! {MidScaleInt, u128, i8, i16, i32, i64, i128, isize}
138impl_from_int! {LongScaleInt, u128, i8, i16, i32, i64, i128, isize}
139
140macro_rules! impl_from_uint {
141    ($num:ident, $data:ty, $($pre:ty),+ $(,)?) => {
142        $(impl From<$pre> for $num {
143            fn from(value: $pre) -> Self {
144                if value == 0 {
145                    Self::default()
146                } else {
147                    Self {
148                        sign: Sign::Pos,
149                        data: value as $data,
150                    }
151                }
152            }
153        })+
154    };
155}
156
157impl_from_uint! {ShortScaleInt, u64, u8, u16, u32}
158impl_from_uint! {MyriadScaleInt, u128, u8, u16, u32, u64, u128, usize}
159impl_from_uint! {MidScaleInt, u128, u8, u16, u32, u64, u128, usize}
160impl_from_uint! {LongScaleInt, u128, u8, u16, u32, u64, u128, usize}
161
162#[cfg(feature = "bigint")]
163macro_rules! impl_try_from_big {
164    ($($int:ty, $err:ident),+ $(,)?) => {
165        $(
166            impl TryFrom<&BigUint> for $int {
167                type Error = Error;
168
169                /// Performs the conversion. Returns [`Error`] if the absolute value is out of range.
170                fn try_from(value: &BigUint) -> Result<Self, Self::Error> {
171                    use num_traits::Zero;
172                    if value == &BigUint::zero() {
173                        Ok(Self::default())
174                    } else if value <= &BigUint::from_slice(Self::MAX_ABS_ARR) {
175                        Ok(Self {
176                            sign: Sign::Pos,
177                            data: value.to_owned(),
178                        })
179                    } else {
180                        Err(Error::$err(value.to_owned()))
181                    }
182                }
183            }
184
185            impl TryFrom<BigUint> for $int {
186                type Error = Error;
187
188                /// Performs the conversion. Returns [`Error`] if the absolute value is out of range.
189                fn try_from(value: BigUint) -> Result<Self, Self::Error> {
190                    <$int>::try_from(&value)
191                }
192            }
193
194            impl TryFrom<&BigInt> for $int {
195                type Error = Error;
196
197                /// Performs the conversion. Returns [`Error`] if the absolute value is out of range.
198                fn try_from(value: &BigInt) -> Result<Self, Self::Error> {
199                    use num_traits::{Signed, Zero};
200                    if value < &BigInt::from_slice(num_bigint::Sign::Minus, Self::MAX_ABS_ARR) || value > &BigInt::from_slice(num_bigint::Sign::Plus, Self::MAX_ABS_ARR) {
201                        let abs = value.abs().to_biguint().unwrap();
202                        Err(Error::$err(abs))
203                    } else if value == &BigInt::zero() {
204                        Ok(Self::default())
205                    } else if value < &BigInt::zero() {
206                        Ok(Self {
207                            sign: Sign::Neg,
208                            data: value.abs().to_biguint().unwrap(),
209                        })
210                    } else {
211                        Ok(Self {
212                            sign: Sign::Pos,
213                            data: value.to_biguint().unwrap(),
214                        })
215                    }
216                }
217            }
218
219            impl TryFrom<BigInt> for $int {
220                type Error = Error;
221
222                /// Performs the conversion. Returns [`Error`] if the absolute value is out of range.
223                fn try_from(value: BigInt) -> Result<Self, Self::Error> {
224                    <$int>::try_from(&value)
225                }
226            }
227        )+
228    };
229}
230
231#[cfg(feature = "bigint")]
232impl_try_from_big! {
233    MyriadScaleBigInt, MyriadScaleOutOfRange,
234    MidScaleBigInt, MidScaleOutOfRange,
235    LongScaleBigInt, LongScaleOutOfRange,
236}