rust_fixed_point_decimal/
from_int.rs1use std::convert::TryFrom;
11
12use rust_fixed_point_decimal_core::{checked_mul_pow_ten, ten_pow};
13
14use crate::{errors::DecimalError, Decimal, PrecLimitCheck, True, MAX_PREC};
15
16macro_rules! impl_from_int {
17 () => {
18 impl_from_int!(u8, i8, u16, i16, u32, i32, u64, i64);
19 };
20 ($($t:ty),*) => {
21 $(
22 impl<const P: u8> From<$t> for Decimal<P>
23 where
24 PrecLimitCheck<{ P <= crate::MAX_PREC }>: True,
25 {
26 #[inline]
27 fn from(i: $t) -> Self
28 {
29 Decimal { coeff: i as i128 * ten_pow(P) as i128 }
30 }
31 }
32 )*
33 }
34}
35
36impl_from_int!();
37
38impl<const P: u8> TryFrom<i128> for Decimal<P>
39where
40 PrecLimitCheck<{ P <= MAX_PREC }>: True,
41{
42 type Error = DecimalError;
43
44 #[inline]
45 fn try_from(i: i128) -> Result<Self, Self::Error> {
46 match checked_mul_pow_ten(i, P) {
47 None => Err(DecimalError::MaxValueExceeded),
48 Some(coeff) => Ok(Decimal { coeff }),
49 }
50 }
51}
52
53impl<const P: u8> TryFrom<u128> for Decimal<P>
54where
55 PrecLimitCheck<{ P <= MAX_PREC }>: True,
56{
57 type Error = DecimalError;
58
59 #[inline]
60 fn try_from(i: u128) -> Result<Self, Self::Error> {
61 match i128::try_from(i) {
62 Err(_) => Err(DecimalError::MaxValueExceeded),
63 Ok(i) => Self::try_from(i),
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use std::convert::TryInto;
71
72 use super::*;
73
74 fn check_from_int<const P: u8, T>(numbers: &[T])
75 where
76 PrecLimitCheck<{ P <= MAX_PREC }>: True,
77 T: Into<i128> + Copy,
78 Decimal<P>: From<T>,
79 {
80 for n in numbers {
81 let d = Decimal::<P>::from(*n);
82 assert_eq!(d.coeff / ten_pow(P), (*n).into());
83 assert_eq!(d.precision(), P);
84 }
85 }
86
87 #[test]
88 fn test_from_u8() {
89 let numbers: [u8; 4] = [0, 1, 28, 255];
90 check_from_int::<2, u8>(&numbers);
91 }
92
93 #[test]
94 fn test_from_i8() {
95 let numbers: [i8; 7] = [-128, -38, -1, 0, 1, 28, 127];
96 check_from_int::<0, i8>(&numbers);
97 }
98
99 #[test]
100 fn test_from_u64() {
101 let numbers: [u64; 4] = [0, 1, 2128255, u64::MAX];
102 check_from_int::<9, u64>(&numbers);
103 }
104
105 #[test]
106 fn test_from_i64() {
107 let numbers: [i64; 4] = [0, -1, 2128255, i64::MIN];
108 check_from_int::<3, i64>(&numbers);
109 }
110
111 fn check_try_from_int_ok<const P: u8, T>(numbers: &[T])
112 where
113 PrecLimitCheck<{ P <= MAX_PREC }>: True,
114 T: TryInto<i128> + Copy,
115 Decimal<P>: TryFrom<T>,
116 {
117 for n in numbers {
118 match Decimal::<P>::try_from(*n) {
119 Err(_) => panic!("Mismatched test value!"),
120 Ok(d) => match (*n).try_into() {
121 Err(_) => panic!("Should never happen!"),
122 Ok(i) => {
123 assert_eq!(d.coeff / ten_pow(P), i);
124 assert_eq!(d.precision(), P);
125 }
126 },
127 }
128 }
129 }
130
131 #[test]
132 fn test_from_u128_ok() {
133 let numbers: [u128; 4] =
134 [0, 1, 2128255, 170141183460469231731687303715884105727u128];
135 check_try_from_int_ok::<0, u128>(&numbers);
136 }
137
138 #[test]
139 fn test_from_i128_ok() {
140 let numbers: [i128; 7] = [
141 -170141183460469231731687303715884105728,
142 -3830009274,
143 -1,
144 0,
145 1,
146 2829773566410082,
147 170141183460469231731687303715884105727,
148 ];
149 check_try_from_int_ok::<0, i128>(&numbers);
150 }
151
152 #[test]
153 fn test_from_i128_err() {
154 let numbers: [i128; 2] = [
155 -170141183460469231731687303715884105728,
156 170141183460469231731687303715884105727,
157 ];
158 for i in numbers {
159 let res = Decimal::<1>::try_from(i);
160 assert_eq!(res.unwrap_err(), DecimalError::MaxValueExceeded);
161 }
162 }
163
164 #[test]
165 fn test_from_u128_err() {
166 let i = 170141183460469231731687303715884105728u128;
167 let res = Decimal::<0>::try_from(i);
168 assert_eq!(res.unwrap_err(), DecimalError::MaxValueExceeded);
169 let i = 17014118346046923173168730371588410572u128;
170 let res = Decimal::<3>::try_from(i);
171 assert_eq!(res.unwrap_err(), DecimalError::MaxValueExceeded);
172 }
173
174 #[test]
175 fn test_from() {
176 let di32 = Decimal::<3>::from(-358i32);
177 assert_eq!(di32.coeff, -358000i128);
178 let i = 38i64.pow(12);
179 let di64 = Decimal::<0>::from(i);
180 assert_eq!(di64.coeff, i as i128);
181 }
182
183 #[test]
184 fn test_into() {
185 let du8: Decimal<9> = 38u8.into();
186 assert_eq!(du8.coeff, 38000000000);
187 let i = -1234567890123456789i64;
188 let di64: Decimal<0> = i.into();
189 assert_eq!(di64.coeff, i as i128);
190 }
191}