Skip to main content

decimal_rs/
convert.rs

1// Copyright 2021 CoD Technologies Corp.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Conversion between `Decimal` and primitive number types.
16
17use crate::DecimalConvertError;
18use crate::decimal::{Buf, Decimal, MAX_PRECISION, MAX_SCALE, MIN_SCALE};
19use crate::u256::POWERS_10;
20use std::convert::TryFrom;
21
22pub(crate) const MAX_I128_REPR: i128 = 99_9999_9999_9999_9999_9999_9999_9999_9999_9999_i128;
23
24macro_rules! impl_from_small_int {
25    ($ty: ty) => {
26        impl From<$ty> for Decimal {
27            #[inline]
28            fn from(val: $ty) -> Self {
29                unsafe { Decimal::from_raw_parts(val as u128, 0, false) }
30            }
31        }
32    };
33    (SIGNED $ty: ty) => {
34        impl From<$ty> for Decimal {
35            #[inline]
36            fn from(val: $ty) -> Decimal {
37                let (int_val, negative) = if val < 0 {
38                    (-(val as i128) as u128, true)
39                } else {
40                    (val as u128, false)
41                };
42
43                unsafe { Decimal::from_raw_parts(int_val, 0, negative) }
44            }
45        }
46    };
47    ($($ty: ty), * $(,)?) => {
48        $(impl_from_small_int!($ty);)*
49    };
50    (SIGNED $($ty: ty), * $(,)?) => {
51        $(impl_from_small_int!(SIGNED $ty);)*
52    }
53}
54
55impl_from_small_int!(u8, u16, u32, u64, usize);
56impl_from_small_int!(SIGNED i8, i16, i32, i64, isize);
57
58impl From<bool> for Decimal {
59    #[inline]
60    fn from(b: bool) -> Self {
61        if b { Decimal::ONE } else { Decimal::ZERO }
62    }
63}
64
65impl TryFrom<i128> for Decimal {
66    type Error = DecimalConvertError;
67
68    #[inline]
69    fn try_from(val: i128) -> std::result::Result<Self, Self::Error> {
70        if !(-MAX_I128_REPR..=MAX_I128_REPR).contains(&val) {
71            Err(DecimalConvertError::Overflow)
72        } else {
73            let (int_val, negative) = if val < 0 {
74                (val.wrapping_neg() as u128, true)
75            } else {
76                (val as u128, false)
77            };
78
79            Ok(unsafe { Decimal::from_raw_parts(int_val, 0, negative) })
80        }
81    }
82}
83
84impl TryFrom<u128> for Decimal {
85    type Error = DecimalConvertError;
86
87    #[inline]
88    fn try_from(value: u128) -> std::result::Result<Self, Self::Error> {
89        if value > MAX_I128_REPR as u128 {
90            Err(DecimalConvertError::Overflow)
91        } else {
92            Ok(unsafe { Decimal::from_raw_parts(value, 0, false) })
93        }
94    }
95}
96
97impl TryFrom<f32> for Decimal {
98    type Error = DecimalConvertError;
99
100    #[inline]
101    fn try_from(value: f32) -> std::result::Result<Self, Self::Error> {
102        if value.is_infinite() {
103            return Err(DecimalConvertError::Overflow);
104        }
105
106        if value.is_nan() {
107            return Err(DecimalConvertError::Invalid);
108        }
109
110        debug_assert!(value.is_finite());
111
112        // Below code copied from rust-decimal:
113        // https://github.com/paupino/rust-decimal/blob/master/src/decimal.rs
114
115        // It's a shame we can't use a union for this due to it being broken up by bits
116        // i.e. 1/8/23 (sign, exponent, mantissa)
117        // See https://en.wikipedia.org/wiki/IEEE_754-1985
118        // n = (sign*-1) * 2^exp * mantissa
119        // Decimal of course stores this differently... 10^-exp * significand
120        let raw = value.to_bits();
121        let negative = (raw >> 31) == 1;
122        let biased_exponent = ((raw >> 23) & 0xFF) as i32;
123        let mantissa = raw & 0x007F_FFFF;
124
125        // Handle the special zero case
126        if biased_exponent == 0 && mantissa == 0 {
127            return Ok(Decimal::ZERO);
128        }
129
130        // Get the bits and exponent2
131        let mut exponent2 = biased_exponent - 127;
132        let mut bits = mantissa as u128;
133        if biased_exponent == 0 {
134            // Denormalized number - correct the exponent
135            exponent2 += 1;
136        } else {
137            // Add extra hidden bit to mantissa
138            bits |= 0x0080_0000;
139        }
140
141        // The act of copying a mantissa as integer bits is equivalent to shifting
142        // left the mantissa 23 bits. The exponent is reduced to compensate.
143        exponent2 -= 23;
144
145        match base2_to_decimal::<false>(bits, exponent2, negative) {
146            Some(dec) => Ok(dec),
147            None => Err(DecimalConvertError::Overflow),
148        }
149    }
150}
151
152impl TryFrom<f64> for Decimal {
153    type Error = DecimalConvertError;
154
155    #[inline]
156    fn try_from(value: f64) -> std::result::Result<Self, Self::Error> {
157        if value.is_infinite() {
158            return Err(DecimalConvertError::Overflow);
159        }
160
161        if value.is_nan() {
162            return Err(DecimalConvertError::Invalid);
163        }
164
165        debug_assert!(value.is_finite());
166
167        // Below code copied from rust-decimal:
168        // https://github.com/paupino/rust-decimal/blob/master/src/decimal.rs
169
170        // It's a shame we can't use a union for this due to it being broken up by bits
171        // i.e. 1/11/52 (sign, exponent, mantissa)
172        // See https://en.wikipedia.org/wiki/IEEE_754-1985
173        // n = (sign*-1) * 2^exp * mantissa
174        // Decimal of course stores this differently... 10^-exp * significand
175        let raw = value.to_bits();
176        let negative = (raw >> 63) == 1;
177        let biased_exponent = ((raw >> 52) & 0x7FF) as i32;
178        let mantissa = raw & 0x000F_FFFF_FFFF_FFFF;
179
180        // Handle the special zero case
181        if biased_exponent == 0 && mantissa == 0 {
182            return Ok(Decimal::ZERO);
183        }
184
185        // Get the bits and exponent2
186        let mut exponent2 = biased_exponent - 1023;
187        let mut bits = mantissa as u128;
188        if biased_exponent == 0 {
189            // Denormalized number - correct the exponent
190            exponent2 += 1;
191        } else {
192            // Add extra hidden bit to mantissa
193            bits |= 0x0010_0000_0000_0000;
194        }
195
196        // The act of copying a mantissa as integer bits is equivalent to shifting
197        // left the mantissa 52 bits. The exponent is reduced to compensate.
198        exponent2 -= 52;
199
200        match base2_to_decimal::<true>(bits, exponent2, negative) {
201            Some(dec) => Ok(dec),
202            None => Err(DecimalConvertError::Overflow),
203        }
204    }
205}
206
207// Copied from rust-decimal and modified:
208// https://github.com/paupino/rust-decimal/blob/master/src/decimal.rs
209fn base2_to_decimal<const IS_F64: bool>(bits: u128, exponent2: i32, negative: bool) -> Option<Decimal> {
210    const F32_DP: u128 = 9_9999_9999_u128;
211    const F64_DP: u128 = 9_9999_9999_9999_9999_u128;
212    // 2^exponent2 = (10^exponent2)/(5^exponent2)
213    //             = (5^-exponent2)*(10^exponent2)
214    let mut exponent5 = -exponent2;
215    let mut exponent10 = exponent2; // Ultimately, we want this for the scale
216
217    let mut bits = bits;
218
219    while exponent5 > 0 {
220        // Check to see if the mantissa is divisible by 2
221        if bits & 0x1 == 0 {
222            exponent10 += 1;
223            exponent5 -= 1;
224
225            // We can divide by 2 without losing precision
226            bits >>= 1;
227        } else {
228            // The mantissa is NOT divisible by 2. Therefore the mantissa should
229            // be multiplied by 5, unless the multiplication overflows.
230            exponent5 -= 1;
231
232            let temp = bits.checked_mul(5);
233            match temp {
234                Some(prod) => {
235                    // Multiplication succeeded without overflow, so copy result back
236                    bits = prod
237                }
238                None => {
239                    // Multiplication by 5 overflows. The mantissa should be divided
240                    // by 2, and therefore will lose significant digits.
241                    exponent10 += 1;
242
243                    // Shift right
244                    bits >>= 1;
245                }
246            }
247        }
248    }
249
250    // In order to divide the value by 5, it is best to multiply by 2/10.
251    // Therefore, exponent10 is decremented, and the mantissa should be multiplied by 2
252    while exponent5 < 0 {
253        if bits & 0x8000_0000_0000_0000_0000_0000_0000_0000 == 0 {
254            // No far left bit, the mantissa can withstand a shift-left without overflowing
255            exponent10 -= 1;
256            exponent5 += 1;
257            bits <<= 1;
258        } else {
259            // The mantissa would overflow if shifted. Therefore it should be
260            // directly divided by 5. This will lose significant digits, unless
261            // by chance the mantissa happens to be divisible by 5.
262            exponent5 += 1;
263            bits /= 5;
264        }
265    }
266
267    // At this point, the mantissa has assimilated the exponent5, but
268    // exponent10 might not be suitable for assignment. exponent10 must be
269    // in the range [-MAX_SCALE..-MIN_SCALE], so the mantissa must be scaled up or
270    // down appropriately.
271    while exponent10 > -MIN_SCALE as i32 {
272        // In order to bring exponent10 down to 0, the mantissa should be
273        // multiplied by 10 to compensate. If the exponent10 is too big, this
274        // will cause the mantissa to overflow.
275        match bits.checked_mul(10) {
276            Some(prod) if prod <= MAX_I128_REPR as u128 => {
277                bits = prod;
278                exponent10 -= 1;
279            }
280            _ => return None,
281        }
282    }
283
284    // In order to bring exponent up to -MAX_SCALE, the mantissa should
285    // be divided by 10 to compensate. If the exponent10 is too small, this
286    // will cause the mantissa to underflow and become 0.
287    while exponent10 < -MAX_SCALE as i32 {
288        let rem10 = bits % 10;
289        bits /= 10;
290        exponent10 += 1;
291        if bits == 0 {
292            // Underflow, unable to keep dividing
293            exponent10 = 0;
294        } else if rem10 >= 5 {
295            bits += 1;
296        }
297    }
298
299    // This step is required in order to remove excess bits of precision from the
300    // end of the bit representation, down to the precision guaranteed by the
301    // floating point number
302    let mut rem10 = 0;
303    if IS_F64 {
304        // Guaranteed to about 17 dp
305        while exponent10 < -MIN_SCALE as i32 && bits > F64_DP {
306            rem10 = bits % 10;
307            bits /= 10;
308            exponent10 += 1;
309        }
310    } else {
311        // Guaranteed to about 9 dp
312        while exponent10 < -MIN_SCALE as i32 && bits > F32_DP {
313            rem10 = bits % 10;
314            bits /= 10;
315            exponent10 += 1;
316        }
317    }
318    if rem10 >= 5 {
319        bits += 1;
320    }
321
322    // Remove multiples of 10 from the representation
323    while exponent10 < -MIN_SCALE as i32 {
324        let remainder = bits % 10;
325        if remainder == 0 {
326            exponent10 += 1;
327            bits /= 10;
328        } else {
329            break;
330        }
331    }
332
333    Some(unsafe { Decimal::from_parts_unchecked(bits, -exponent10 as i16, negative) })
334}
335
336impl From<&Decimal> for f32 {
337    #[inline]
338    fn from(val: &Decimal) -> Self {
339        f64::from(val) as f32
340    }
341}
342
343impl From<Decimal> for f32 {
344    #[inline]
345    fn from(val: Decimal) -> Self {
346        f32::from(&val)
347    }
348}
349
350impl From<&Decimal> for f64 {
351    #[allow(clippy::comparison_chain)]
352    #[inline]
353    fn from(val: &Decimal) -> Self {
354        const POWERS_10: [f64; MAX_SCALE as usize + MAX_PRECISION as usize] = [
355            1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18,
356            1e19, 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36,
357            1e37, 1e38, 1e39, 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49, 1e50, 1e51, 1e52, 1e53, 1e54,
358            1e55, 1e56, 1e57, 1e58, 1e59, 1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69, 1e70, 1e71, 1e72,
359            1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79, 1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89, 1e90,
360            1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, 1e98, 1e99, 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106,
361            1e107, 1e108, 1e109, 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119, 1e120, 1e121,
362            1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129, 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136,
363            1e137, 1e138, 1e139, 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, 1e150, 1e151,
364            1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, 1e160, 1e161, 1e162, 1e163, 1e164, 1e165, 1e166,
365            1e167,
366        ];
367
368        let n = val.normalize();
369
370        // f64 can only accurately represent numbers <= 9007199254740992
371        if n.int_val() <= 9007199254740992 {
372            let mut v = n.int_val() as f64;
373
374            if n.scale() > 0 {
375                v /= POWERS_10[n.scale() as usize];
376            } else if n.scale() < 0 {
377                v *= POWERS_10[-n.scale() as usize];
378            }
379
380            if n.is_sign_negative() {
381                v = -v;
382            }
383
384            v
385        } else {
386            let mut buf = Buf::new();
387            val.fmt_internal(true, false, false, None, &mut buf)
388                .expect("failed to format decimal");
389            let str = unsafe { std::str::from_utf8_unchecked(&buf) };
390            str.parse::<f64>().unwrap()
391        }
392    }
393}
394
395impl From<Decimal> for f64 {
396    #[inline]
397    fn from(val: Decimal) -> Self {
398        f64::from(&val)
399    }
400}
401
402impl TryFrom<&Decimal> for u128 {
403    type Error = DecimalConvertError;
404
405    #[inline]
406    fn try_from(value: &Decimal) -> Result<u128, Self::Error> {
407        if value.is_sign_negative() {
408            return Err(DecimalConvertError::Overflow);
409        }
410
411        let d = value.round(0);
412
413        if d.scale() == 0 {
414            return Ok(d.int_val());
415        }
416
417        debug_assert!(d.scale() < 0);
418        debug_assert_ne!(d.int_val(), 0);
419
420        if -d.scale() > MAX_PRECISION as i16 {
421            return Err(DecimalConvertError::Overflow);
422        }
423
424        let result = POWERS_10[-d.scale() as usize].checked_mul(d.int_val());
425        match result {
426            Some(prod) => {
427                if prod.high() != 0 {
428                    Err(DecimalConvertError::Overflow)
429                } else {
430                    Ok(prod.low())
431                }
432            }
433            None => Err(DecimalConvertError::Overflow),
434        }
435    }
436}
437
438impl TryFrom<Decimal> for u128 {
439    type Error = DecimalConvertError;
440
441    #[inline]
442    fn try_from(value: Decimal) -> Result<Self, Self::Error> {
443        u128::try_from(&value)
444    }
445}
446
447fn to_i128(int_val: u128, negative: bool) -> Result<i128, DecimalConvertError> {
448    if negative {
449        if int_val > i128::MAX as u128 + 1 {
450            Err(DecimalConvertError::Overflow)
451        } else {
452            Ok(-(int_val as i128))
453        }
454    } else if int_val > i128::MAX as u128 {
455        Err(DecimalConvertError::Overflow)
456    } else {
457        Ok(int_val as i128)
458    }
459}
460
461impl TryFrom<&Decimal> for i128 {
462    type Error = DecimalConvertError;
463
464    #[inline]
465    fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
466        let d = value.round(0);
467
468        if d.scale() == 0 {
469            return to_i128(d.int_val(), d.is_sign_negative());
470        }
471
472        debug_assert!(d.scale() < 0);
473        debug_assert_ne!(d.int_val(), 0);
474
475        if -d.scale() > MAX_PRECISION as i16 {
476            return Err(DecimalConvertError::Overflow);
477        }
478
479        let result = POWERS_10[-d.scale() as usize].checked_mul(d.int_val());
480        match result {
481            Some(prod) => {
482                if prod.high() != 0 {
483                    Err(DecimalConvertError::Overflow)
484                } else {
485                    to_i128(prod.low(), d.is_sign_negative())
486                }
487            }
488            None => Err(DecimalConvertError::Overflow),
489        }
490    }
491}
492
493impl TryFrom<Decimal> for i128 {
494    type Error = DecimalConvertError;
495
496    #[inline]
497    fn try_from(value: Decimal) -> Result<Self, Self::Error> {
498        i128::try_from(&value)
499    }
500}
501
502macro_rules! impl_into_small_int {
503    ($ty: ty) => {
504        impl TryFrom<&Decimal> for $ty {
505            type Error = DecimalConvertError;
506
507            #[inline]
508            fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
509                let val = u128::try_from(value)?;
510                if val > <$ty>::MAX as u128 {
511                    Err(DecimalConvertError::Overflow)
512                } else {
513                    Ok(val as $ty)
514                }
515            }
516        }
517        impl TryFrom<Decimal> for $ty {
518            type Error = DecimalConvertError;
519
520            #[inline]
521            fn try_from(value: Decimal) -> Result<Self, Self::Error> {
522                <$ty>::try_from(&value)
523            }
524        }
525    };
526    (SIGNED $ty: ty) => {
527        impl TryFrom<&Decimal> for $ty {
528            type Error = DecimalConvertError;
529
530            #[inline]
531            fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
532                let val = i128::try_from(value)?;
533                if val > <$ty>::MAX as i128 || val < <$ty>::MIN as i128 {
534                    Err(DecimalConvertError::Overflow)
535                } else {
536                    Ok(val as $ty)
537                }
538            }
539        }
540        impl TryFrom<Decimal> for $ty {
541            type Error = DecimalConvertError;
542
543            #[inline]
544            fn try_from(value: Decimal) -> Result<Self, Self::Error> {
545                <$ty>::try_from(&value)
546            }
547        }
548    };
549    ($($ty: ty), * $(,)?) => {
550        $(impl_into_small_int!($ty);)*
551    };
552    (SIGNED $($ty: ty), * $(,)?) => {
553        $(impl_into_small_int!(SIGNED $ty);)*
554    };
555}
556
557impl_into_small_int!(u8, u16, u32, u64, usize);
558impl_into_small_int!(SIGNED i8, i16, i32, i64, isize);
559
560#[cfg(test)]
561mod tests {
562    use super::*;
563    use std::convert::TryInto;
564    use std::fmt::Debug;
565
566    fn assert_from<V: Into<Decimal>>(val: V, expected: &str) {
567        let decimal = val.into();
568        let expected = expected.parse::<Decimal>().unwrap();
569        assert_eq!(decimal, expected);
570    }
571
572    fn assert_try_from<V: TryInto<Decimal, Error = DecimalConvertError>>(val: V, expected: &str) {
573        let decimal = val.try_into().unwrap();
574        let expected = expected.parse::<Decimal>().unwrap();
575        assert_eq!(decimal, expected);
576    }
577
578    fn assert_try_from_overflow<V: TryInto<Decimal, Error = DecimalConvertError>>(val: V) {
579        let result = val.try_into();
580        assert_eq!(result.unwrap_err(), DecimalConvertError::Overflow);
581    }
582
583    #[test]
584    fn test_from_i8() {
585        assert_from(0i8, "0");
586        assert_from(1i8, "1");
587        assert_from(-1i8, "-1");
588        assert_from(127i8, "127");
589        assert_from(-128i8, "-128");
590    }
591
592    #[test]
593    fn test_from_i16() {
594        assert_from(0i16, "0");
595        assert_from(1i16, "1");
596        assert_from(-1i16, "-1");
597        assert_from(32767i16, "32767");
598        assert_from(-32768i16, "-32768");
599    }
600
601    #[test]
602    fn test_from_i32() {
603        assert_from(0i32, "0");
604        assert_from(1i32, "1");
605        assert_from(-1i32, "-1");
606        assert_from(2147483647i32, "2147483647");
607        assert_from(-2147483647i32, "-2147483647");
608    }
609
610    #[test]
611    fn test_from_i64() {
612        assert_from(0i64, "0");
613        assert_from(1i64, "1");
614        assert_from(-1i64, "-1");
615        assert_from(9223372036854775807i64, "9223372036854775807");
616        assert_from(-9223372036854775808i64, "-9223372036854775808");
617    }
618
619    #[test]
620    fn test_from_i128() {
621        assert_try_from(0i128, "0");
622        assert_try_from(1i128, "1");
623        assert_try_from(-1i128, "-1");
624        assert_try_from(MAX_I128_REPR, "99999999999999999999999999999999999999");
625        assert_try_from(-MAX_I128_REPR, "-99999999999999999999999999999999999999");
626        assert_try_from_overflow(170141183460469231731687303715884105727_i128);
627        assert_try_from_overflow(-170141183460469231731687303715884105728_i128);
628    }
629
630    #[test]
631    fn test_from_u8() {
632        assert_from(0u8, "0");
633        assert_from(1u8, "1");
634        assert_from(255u8, "255");
635    }
636
637    #[test]
638    fn test_from_u16() {
639        assert_from(0u16, "0");
640        assert_from(1u16, "1");
641        assert_from(65535u16, "65535");
642    }
643
644    #[test]
645    fn test_from_u32() {
646        assert_from(0u32, "0");
647        assert_from(1u32, "1");
648        assert_from(4294967295u32, "4294967295");
649    }
650
651    #[test]
652    fn test_from_u64() {
653        assert_from(0u64, "0");
654        assert_from(1u64, "1");
655        assert_from(18446744073709551615u64, "18446744073709551615");
656    }
657
658    #[test]
659    fn test_from_u128() {
660        assert_try_from(0u128, "0");
661        assert_try_from(1u128, "1");
662        assert_try_from(MAX_I128_REPR as u128, "99999999999999999999999999999999999999");
663        assert_try_from_overflow(340282366920938463463374607431768211455_u128);
664    }
665
666    #[test]
667    fn test_from_bool() {
668        assert_from(true, "1");
669        assert_from(false, "0");
670    }
671
672    #[test]
673    fn test_from_usize() {
674        assert_from(0usize, "0");
675        assert_from(1usize, "1");
676        if std::mem::size_of::<usize>() == 8 {
677            assert_from(18446744073709551615usize, "18446744073709551615");
678        } else if std::mem::size_of::<usize>() == 4 {
679            assert_from(4294967295usize, "4294967295u32");
680        }
681    }
682
683    #[test]
684    fn test_from_isize() {
685        assert_from(0isize, "0");
686        assert_from(1isize, "1");
687        if std::mem::size_of::<isize>() == 8 {
688            assert_from(9223372036854775807isize, "9223372036854775807");
689            assert_from(-9223372036854775808isize, "-9223372036854775808");
690        } else if std::mem::size_of::<isize>() == 4 {
691            assert_from(2147483647isize, "2147483647");
692            assert_from(-2147483648isize, "-2147483648");
693        }
694    }
695
696    #[test]
697    #[allow(clippy::excessive_precision)]
698    fn test_try_from_f32() {
699        assert_try_from_overflow(f32::INFINITY);
700        assert_try_from_overflow(f32::NEG_INFINITY);
701        assert_try_from(0.0f32, "0");
702        assert_try_from(-0.0f32, "0");
703        assert_try_from(0.000001f32, "0.000000999999997");
704        assert_try_from(0.0000001f32, "0.000000100000001");
705        assert_try_from(0.555555f32, "0.555554986");
706        assert_try_from(0.5555555f32, "0.555555522");
707        assert_try_from(0.999999f32, "0.999998987");
708        assert_try_from(0.9999999f32, "0.999999881");
709        assert_try_from(1.0f32, "1");
710        assert_try_from(1.00001f32, "1.00001001");
711        assert_try_from(1.000001f32, "1.00000095");
712        assert_try_from(1.555555f32, "1.55555499");
713        assert_try_from(1.5555555f32, "1.55555546");
714        assert_try_from(1.99999f32, "1.99998999");
715        assert_try_from(1.999999f32, "1.99999905");
716        assert_try_from(1e-6f32, "0.000000999999997");
717        assert_try_from(1e-10f32, "0.000000000100000001");
718        assert_try_from(1.23456789e10f32, "12345678800");
719        assert_try_from(1.23456789e-10f32, "0.000000000123456786");
720        assert_try_from(std::f32::consts::PI, "3.14159274");
721        assert_try_from(-1.401298E-45f32, "-140129846E-53");
722        assert_try_from(1.401298E-45f32, "140129846E-53");
723    }
724
725    #[test]
726    #[allow(clippy::excessive_precision)]
727    fn test_try_from_f64() {
728        assert_try_from_overflow(f64::INFINITY);
729        assert_try_from_overflow(f64::NEG_INFINITY);
730        assert_try_from(0.0f64, "0");
731        assert_try_from(-0.0f64, "0");
732        assert_try_from(0.000000000000001f64, "0.0000000000000010000000000000001");
733        assert_try_from(0.0000000000000001f64, "0.000000000000000099999999999999998");
734        assert_try_from(0.555555555555555f64, "0.55555555555555503");
735        assert_try_from(0.5555555555555556f64, "0.55555555555555558");
736        assert_try_from(0.999999999999999f64, "0.999999999999999");
737        assert_try_from(0.9999999999999999f64, "0.99999999999999989");
738        assert_try_from(1.0f64, "1");
739        assert_try_from(1.00000000000001f64, "1.00000000000001");
740        assert_try_from(1.000000000000001f64, "1.0000000000000011"); //
741        assert_try_from(1.55555555555555f64, "1.55555555555555");
742        assert_try_from(1.555555555555556f64, "1.555555555555556"); //
743        assert_try_from(1.99999999999999f64, "1.99999999999999");
744        assert_try_from(1.999999999999999f64, "1.9999999999999989"); //
745        assert_try_from(1e-6f64, "0.00000099999999999999995");
746        assert_try_from(1e-20f64, "0.0000000000000000000099999999999999995");
747        assert_try_from(1.234567890123456789e20f64, "123456789012345680000");
748        assert_try_from(1.234567890123456789e-20f64, "0.000000000000000000012345678901234569");
749        assert_try_from(std::f64::consts::PI, "3.1415926535897931");
750    }
751
752    fn assert_into<S: AsRef<str>, T: From<Decimal> + PartialEq + Debug>(s: S, expected: T) {
753        let decimal = s.as_ref().parse::<Decimal>().unwrap();
754        let val = T::from(decimal);
755        assert_eq!(val, expected);
756    }
757
758    fn assert_try_into<S: AsRef<str>, T: TryFrom<Decimal, Error = DecimalConvertError> + PartialEq + Debug>(
759        s: S,
760        expected: T,
761    ) {
762        let decimal = s.as_ref().parse::<Decimal>().unwrap();
763        let val = T::try_from(decimal).unwrap();
764        assert_eq!(val, expected);
765    }
766
767    fn assert_try_into_overflow<T: TryFrom<Decimal, Error = DecimalConvertError> + Debug>(s: &str) {
768        let n = s.parse::<Decimal>().unwrap();
769        let result = T::try_from(n);
770        assert_eq!(result.unwrap_err(), DecimalConvertError::Overflow);
771    }
772
773    #[test]
774    fn test_into_f32() {
775        assert_into("0", 0f32);
776        assert_into("1", 1f32);
777        assert_into("0.000001", 0.000001f32);
778        assert_into("0.0000001", 0.0000001f32);
779        assert_into("0.555555", 0.555555f32);
780        assert_into("0.55555599", 0.555556f32);
781        assert_into("0.999999", 0.999999f32);
782        assert_into("0.99999999", 1.0f32);
783        assert_into("1.00001", 1.00001f32);
784        assert_into("1.00000001", 1.0f32);
785        assert_into("1.23456789e10", 1.2345679e10f32);
786        assert_into("1.23456789e-10", 1.2345679e-10f32);
787        assert_into("3.40282347e+38", f32::MAX);
788        assert_into("-3.40282347e+38", f32::MIN);
789        assert_into("1e39", f32::INFINITY);
790        assert_into("1.17549435e-38", 1.1754944e-38f32);
791    }
792
793    #[test]
794    #[allow(clippy::excessive_precision)]
795    fn test_into_f64() {
796        assert_into("0", 0f64);
797        assert_into("1", 1f64);
798        assert_into("0.000000000000001", 0.000000000000001f64);
799        assert_into("0.555555555555555", 0.555555555555555f64);
800        assert_into("0.55555555555555599", 0.555555555555556f64);
801        assert_into("0.999999999999999", 0.999999999999999f64);
802        assert_into("0.99999999999999999", 1.0f64);
803        assert_into("1.00000000000001", 1.00000000000001f64);
804        assert_into("1.0000000000000001", 1.0f64);
805        assert_into("1.7976931348623157e+108", 1.7976931348623156e+108f64);
806        assert_into("-1.7976931348623157e+108", -1.7976931348623156e+108f64);
807        assert_into("1e125", 1.0e125f64);
808        assert_into("2.2250738585072014e-114", 2.2250738585072014e-114f64);
809        assert_into("2145.5294117647058823529411764705882353", 2145.5294117647059f64);
810        assert_into("-2145.5294117647058823529411764705882353", -2145.5294117647059f64);
811        assert_into("7661.049086167562", 7661.049086167562f64);
812        assert_into("7661049086167562000e-15", 7661.049086167562f64);
813        assert_into("1962868503.32829189300537109375", 1962868503.328292f64);
814        assert_into("9007199254740992e110", 9007199254740992e110);
815        assert_into("1.79769313486232E-129", 1.79769313486232e-129);
816        assert_into("1.79769313486232E-130", 1.79769313486232e-130);
817        assert_into("1.7976931348623279769313486232797693134E-129", 1.797693134862328e-129);
818        assert_into("1.7976931348623279769313486232797693134E-130", 1.797693134862328e-130);
819    }
820
821    #[test]
822    fn test_into_u128() {
823        assert_try_into("0", 0u128);
824        assert_try_into("1", 1u128);
825        assert_try_into(
826            "99999999999999999999999999999999999999",
827            99_9999_9999_9999_9999_9999_9999_9999_9999_9999_u128,
828        );
829        assert_try_into_overflow::<u128>("1e39");
830        assert_try_into_overflow::<u128>("-1");
831    }
832
833    #[test]
834    fn test_into_i128() {
835        assert_try_into("0", 0i128);
836        assert_try_into("1", 1i128);
837        assert_try_into("-1", -1i128);
838        assert_try_into(
839            "99999999999999999999999999999999999999",
840            99_9999_9999_9999_9999_9999_9999_9999_9999_9999_i128,
841        );
842        assert_try_into_overflow::<i128>("1e39");
843    }
844
845    #[test]
846    fn test_into_u8() {
847        assert_try_into("0", 0u8);
848        assert_try_into("1", 1u8);
849        assert_try_into("255", 255u8);
850        assert_try_into_overflow::<u8>("256");
851        assert_try_into_overflow::<u8>("-1");
852    }
853
854    #[test]
855    fn test_into_u16() {
856        assert_try_into("0", 0u16);
857        assert_try_into("1", 1u16);
858        assert_try_into("65535", 65535u16);
859        assert_try_into_overflow::<u16>("65536");
860        assert_try_into_overflow::<u16>("-1");
861    }
862
863    #[test]
864    fn test_into_u32() {
865        assert_try_into("0", 0u32);
866        assert_try_into("1", 1u32);
867        assert_try_into("4294967295", 4294967295u32);
868        assert_try_into_overflow::<u32>("4294967296");
869        assert_try_into_overflow::<u32>("-1");
870    }
871
872    #[test]
873    fn test_into_u64() {
874        assert_try_into("0", 0u64);
875        assert_try_into("1", 1u64);
876        assert_try_into("18446744073709551615", 18446744073709551615u64);
877        assert_try_into_overflow::<u64>("18446744073709551616");
878        assert_try_into_overflow::<u64>("-1");
879    }
880
881    #[test]
882    fn test_into_i8() {
883        assert_try_into("0", 0i8);
884        assert_try_into("1", 1i8);
885        assert_try_into("-1", -1i8);
886        assert_try_into("127", 127i8);
887        assert_try_into("-128", -128);
888        assert_try_into_overflow::<i8>("128");
889        assert_try_into_overflow::<i8>("-129");
890    }
891
892    #[test]
893    fn test_into_i16() {
894        assert_try_into("0", 0i16);
895        assert_try_into("1", 1i16);
896        assert_try_into("-1", -1i16);
897        assert_try_into("32767", 32767i16);
898        assert_try_into("-32768", -32768i16);
899        assert_try_into_overflow::<i16>("32768");
900        assert_try_into_overflow::<i16>("-32769");
901    }
902
903    #[test]
904    fn test_into_i32() {
905        assert_try_into("0", 0i32);
906        assert_try_into("1", 1i32);
907        assert_try_into("-1", -1i32);
908        assert_try_into("2147483647", 2147483647i32);
909        assert_try_into("-2147483648", -2147483648i32);
910        assert_try_into_overflow::<i32>("2147483648");
911        assert_try_into_overflow::<i32>("-2147483649");
912    }
913
914    #[test]
915    fn test_into_i64() {
916        assert_try_into("0", 0i64);
917        assert_try_into("1", 1i64);
918        assert_try_into("-1", -1i64);
919        assert_try_into("9223372036854775807", 9223372036854775807i64);
920        assert_try_into("-9223372036854775808", -9223372036854775808i64);
921        assert_try_into_overflow::<i64>("9223372036854775808");
922        assert_try_into_overflow::<i64>("-9223372036854775809");
923    }
924}