1use crate::binary::{NumericDigit, NUMERIC_NEG, NUMERIC_POS};
18use crate::data::NumericData;
19use crate::error::NumericTryFromError;
20use crate::num::{Numeric, NumericBuf};
21use crate::var::{NumericVar, NBASE};
22use std::convert::{TryFrom, TryInto};
23use std::ffi::CStr;
24use std::mem::MaybeUninit;
25
26trait Zero: Copy + PartialEq {
28 const ZERO: Self;
29
30 #[inline]
31 fn is_zero(self) -> bool {
32 self == Self::ZERO
33 }
34}
35
36macro_rules! impl_zero {
37 ($t: ty) => {
38 impl Zero for $t {
39 const ZERO: Self = 0;
40 }
41 };
42}
43
44impl_zero!(i8);
45impl_zero!(i16);
46impl_zero!(i32);
47impl_zero!(i64);
48impl_zero!(i128);
49impl_zero!(u8);
50impl_zero!(u16);
51impl_zero!(u32);
52impl_zero!(u64);
53impl_zero!(u128);
54
55trait Unsigned: Copy + Zero {
57 const MAX_NDIGITS: usize;
58
59 fn next_digit(self) -> (NumericDigit, Self);
60
61 fn from_numeric_digit(n: NumericDigit) -> Self;
62 fn from_u64(i: u64) -> Self;
63 fn overflowing_mul(self, rhs: Self) -> (Self, bool);
64 fn overflowing_add(self, rhs: Self) -> (Self, bool);
65}
66
67macro_rules! impl_unsigned {
68 ($t: ty, $ndigits: expr) => {
69 impl Unsigned for $t {
70 const MAX_NDIGITS: usize = $ndigits;
71
72 #[inline]
73 fn next_digit(self) -> (NumericDigit, Self) {
74 let new_val = self / NBASE as Self;
75 let digit = (self - new_val * NBASE as Self) as NumericDigit;
76 (digit, new_val)
77 }
78
79 #[inline]
80 fn from_numeric_digit(n: NumericDigit) -> Self {
81 n as Self
82 }
83
84 #[inline]
85 fn from_u64(i: u64) -> Self {
86 i as Self
87 }
88
89 #[inline]
90 fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
91 self.overflowing_mul(rhs)
92 }
93
94 #[inline]
95 fn overflowing_add(self, rhs: Self) -> (Self, bool) {
96 self.overflowing_add(rhs)
97 }
98 }
99 };
100}
101
102impl_unsigned!(u16, 2);
103impl_unsigned!(u32, 3);
104impl_unsigned!(u64, 5);
105impl_unsigned!(u128, 10);
106
107impl Unsigned for u8 {
108 const MAX_NDIGITS: usize = 1;
109
110 #[inline]
111 fn next_digit(self) -> (NumericDigit, Self) {
112 (self as NumericDigit, 0)
113 }
114
115 fn from_numeric_digit(_n: i16) -> Self {
116 panic!("should not use this associate function")
117 }
118
119 fn from_u64(_i: u64) -> Self {
120 panic!("should not use this associate function")
121 }
122
123 fn overflowing_mul(self, _rhs: Self) -> (Self, bool) {
124 panic!("should not use this associate function")
125 }
126
127 fn overflowing_add(self, _rhs: Self) -> (Self, bool) {
128 panic!("should not use this associate function")
129 }
130}
131
132trait Signed: Copy + PartialOrd + Zero {
134 type AbsType: Unsigned;
135
136 const MIN_VALUE: Self;
137
138 fn from_numeric_digit(n: NumericDigit) -> Self;
139 fn from_i64(i: i64) -> Self;
140 fn is_negative(self) -> bool;
141 fn negative(self) -> Self;
142 fn abs(self) -> Self::AbsType;
143 fn overflowing_mul(self, rhs: Self) -> (Self, bool);
144 fn overflowing_sub(self, rhs: Self) -> (Self, bool);
145}
146
147macro_rules! impl_signed {
148 ($t: ty, $abs_ty: ty) => {
149 impl Signed for $t {
150 type AbsType = $abs_ty;
151
152 const MIN_VALUE: Self = Self::min_value();
153
154 #[inline]
155 fn from_numeric_digit(n: NumericDigit) -> Self {
156 debug_assert!(n as i128 <= Self::max_value() as i128);
157 debug_assert!(n as i128 >= Self::min_value() as i128);
158 n as Self
159 }
160
161 #[inline]
162 fn from_i64(i: i64) -> Self {
163 debug_assert!(i as i128 <= Self::max_value() as i128);
164 debug_assert!(i as i128 >= Self::min_value() as i128);
165 i as Self
166 }
167
168 #[inline]
169 fn is_negative(self) -> bool {
170 self < 0
171 }
172
173 #[inline]
174 fn negative(self) -> Self {
175 -self
176 }
177
178 #[inline]
179 fn abs(self) -> $abs_ty {
180 if self >= 0 {
181 self as $abs_ty
182 } else {
183 -(self + 1) as $abs_ty + 1
184 }
185 }
186
187 #[inline]
188 fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
189 self.overflowing_mul(rhs)
190 }
191
192 #[inline]
193 fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
194 self.overflowing_sub(rhs)
195 }
196 }
197 };
198}
199
200impl_signed!(i8, u8);
201impl_signed!(i16, u16);
202impl_signed!(i32, u32);
203impl_signed!(i64, u64);
204impl_signed!(i128, u128);
205
206#[inline]
208fn from_signed<T: Signed>(val: T) -> NumericVar<'static> {
209 if val.is_zero() {
210 return NumericVar::zero();
211 }
212
213 let sign = if val.is_negative() {
214 NUMERIC_NEG
215 } else {
216 NUMERIC_POS
217 };
218
219 unsigned_to_var(val.abs(), sign)
220}
221
222#[inline]
224fn from_unsigned<T: Unsigned>(val: T) -> NumericVar<'static> {
225 if val.is_zero() {
226 return NumericVar::zero();
227 }
228
229 unsigned_to_var(val, NUMERIC_POS)
230}
231
232fn unsigned_to_var<T: Unsigned>(val: T, sign: u16) -> NumericVar<'static> {
233 let mut data = NumericData::with_ndigits(T::MAX_NDIGITS as i32);
234
235 let mut u_val = val;
236 let digits = data.digits_mut(T::MAX_NDIGITS as i32);
237 let mut ndigits = 0;
238 let mut i = digits.len();
239 loop {
240 i -= 1;
241 ndigits += 1;
242
243 let (digit, new_u_val) = u_val.next_digit();
244
245 digits[i] = digit;
246 u_val = new_u_val;
247
248 if u_val.is_zero() {
249 break;
250 }
251 }
252 data.offset_set(data.len() - ndigits as u32);
253
254 NumericVar::owned(ndigits, ndigits - 1, 0, sign, data)
255}
256
257trait Floating: Copy {
259 const PRECISION: usize;
260
261 fn is_nan(self) -> bool;
262 fn is_infinite(self) -> bool;
263 fn as_f64(self) -> f64;
264}
265
266macro_rules! impl_floating {
267 ($t: ty, $precision: expr) => {
268 impl Floating for $t {
269 const PRECISION: usize = $precision;
270
271 #[inline]
272 fn is_nan(self) -> bool {
273 self.is_nan()
274 }
275
276 #[inline]
277 fn is_infinite(self) -> bool {
278 self.is_infinite()
279 }
280
281 #[inline]
282 fn as_f64(self) -> f64 {
283 self as f64
284 }
285 }
286 };
287}
288
289impl_floating!(f32, 6);
290impl_floating!(f64, 15);
291
292extern "C" {
293 fn snprintf(dest: *mut u8, size: usize, format: *const u8, ...);
295}
296
297fn from_floating<T: Floating>(f: T) -> Result<NumericBuf, NumericTryFromError> {
299 if f.is_nan() {
300 return Ok(NumericBuf::nan());
301 }
302
303 if f.is_infinite() {
304 return Err(NumericTryFromError::invalid());
305 }
306
307 const BUF_SIZE: usize = 128;
308
309 unsafe {
310 let mut buf: [MaybeUninit<u8>; BUF_SIZE] = MaybeUninit::uninit().assume_init();
311 snprintf(
312 buf.as_mut_ptr() as *mut u8,
313 BUF_SIZE,
314 "%.*g\0".as_ptr(),
315 T::PRECISION,
316 f.as_f64(),
317 );
318 let s = CStr::from_ptr(buf.as_ptr() as *const i8).to_string_lossy();
319 let n = s.parse::<NumericBuf>()?;
320 Ok(n)
321 }
322}
323
324macro_rules! impl_from_signed {
325 ($t: ty) => {
326 impl From<$t> for NumericBuf {
327 #[inline]
328 fn from(val: $t) -> Self {
329 from_signed(val).make_result_no_overflow()
330 }
331 }
332 };
333}
334
335macro_rules! impl_from_unsigned {
336 ($t: ty) => {
337 impl From<$t> for NumericBuf {
338 #[inline]
339 fn from(val: $t) -> Self {
340 from_unsigned(val).make_result_no_overflow()
341 }
342 }
343 };
344}
345
346impl_from_signed!(i8);
347impl_from_signed!(i16);
348impl_from_signed!(i32);
349impl_from_signed!(i64);
350impl_from_signed!(i128);
351impl_from_unsigned!(u8);
352impl_from_unsigned!(u16);
353impl_from_unsigned!(u32);
354impl_from_unsigned!(u64);
355impl_from_unsigned!(u128);
356
357impl From<bool> for NumericBuf {
358 #[inline]
359 fn from(b: bool) -> Self {
360 let val = if b { 1u8 } else { 0u8 };
361 val.into()
362 }
363}
364
365impl From<usize> for NumericBuf {
366 #[inline]
367 fn from(u: usize) -> Self {
368 if std::mem::size_of::<usize>() == 8 {
369 (u as u64).into()
370 } else if std::mem::size_of::<usize>() == 4 {
371 (u as u32).into()
372 } else {
373 panic!("invalid usize size")
374 }
375 }
376}
377
378impl From<isize> for NumericBuf {
379 #[inline]
380 fn from(i: isize) -> Self {
381 if std::mem::size_of::<isize>() == 8 {
382 (i as i64).into()
383 } else if std::mem::size_of::<isize>() == 4 {
384 (i as i32).into()
385 } else {
386 panic!("invalid isize size")
387 }
388 }
389}
390
391impl<'a> From<i64> for NumericVar<'a> {
392 #[inline]
393 fn from(val: i64) -> Self {
394 from_signed(val)
395 }
396}
397
398macro_rules! impl_try_from_floating {
399 ($t: ty) => {
400 impl TryFrom<$t> for NumericBuf {
401 type Error = NumericTryFromError;
402
403 #[inline]
404 fn try_from(f: $t) -> Result<Self, Self::Error> {
405 from_floating(f)
406 }
407 }
408 };
409}
410
411impl_try_from_floating!(f32);
412impl_try_from_floating!(f64);
413
414fn into_signed<T: Signed>(var: &mut NumericVar) -> Result<T, NumericTryFromError> {
416 debug_assert!(std::mem::size_of::<T>() >= std::mem::size_of::<NumericDigit>());
418
419 if var.is_nan() {
420 return Err(NumericTryFromError::invalid());
421 }
422
423 var.round_common(0);
425
426 var.strip();
428 let ndigits = var.ndigits();
429 if ndigits == 0 {
430 return Ok(T::ZERO);
431 }
432
433 let weight = var.weight();
436 debug_assert!(weight >= 0);
437 debug_assert!(ndigits <= weight + 1);
438
439 let digits = var.digits();
443 let mut val = T::from_numeric_digit(digits[0]).negative();
444 for i in 1..=weight {
445 let (new_val, overflowing) = val.overflowing_mul(T::from_i64(NBASE as i64));
446 if overflowing {
447 return Err(NumericTryFromError::overflow());
448 }
449 val = new_val;
450
451 if i < ndigits {
452 let (new_val, overflowing) =
453 val.overflowing_sub(T::from_numeric_digit(digits[i as usize]));
454 if overflowing {
455 return Err(NumericTryFromError::overflow());
456 }
457 val = new_val;
458 }
459 }
460
461 if !var.is_negative() {
462 if val == T::MIN_VALUE {
463 return Err(NumericTryFromError::overflow());
464 }
465
466 val = val.negative();
467 }
468
469 Ok(val)
470}
471
472fn into_unsigned<T: Unsigned>(var: &mut NumericVar) -> Result<T, NumericTryFromError> {
474 debug_assert!(std::mem::size_of::<T>() >= std::mem::size_of::<NumericDigit>());
476
477 if var.is_nan() {
478 return Err(NumericTryFromError::invalid());
479 }
480
481 var.round_common(0);
483
484 var.strip();
486 let ndigits = var.ndigits();
487 if ndigits == 0 {
488 return Ok(T::ZERO);
489 }
490
491 if var.is_negative() {
492 return Err(NumericTryFromError::overflow());
493 }
494
495 let weight = var.weight();
498 debug_assert!(weight >= 0);
499 debug_assert!(ndigits <= weight + 1);
500
501 let digits = var.digits();
503 let mut val = T::from_numeric_digit(digits[0]);
504 for i in 1..=weight {
505 let (new_val, overflowing) = val.overflowing_mul(T::from_u64(NBASE as u64));
506 if overflowing {
507 return Err(NumericTryFromError::overflow());
508 }
509 val = new_val;
510
511 if i < ndigits {
512 let (new_val, overflowing) =
513 val.overflowing_add(T::from_numeric_digit(digits[i as usize]));
514 if overflowing {
515 return Err(NumericTryFromError::overflow());
516 }
517 val = new_val;
518 }
519 }
520
521 Ok(val)
522}
523
524macro_rules! impl_try_from_var_for_signed {
525 ($t: ty) => {
526 impl<'a> TryFrom<NumericVar<'a>> for $t {
527 type Error = NumericTryFromError;
528
529 #[inline]
530 fn try_from(mut value: NumericVar<'a>) -> Result<Self, Self::Error> {
531 into_signed(&mut value)
532 }
533 }
534 };
535}
536
537macro_rules! impl_try_from_var_for_unsigned {
538 ($t: ty) => {
539 impl<'a> TryFrom<NumericVar<'a>> for $t {
540 type Error = NumericTryFromError;
541
542 #[inline]
543 fn try_from(mut value: NumericVar) -> Result<Self, Self::Error> {
544 into_unsigned(&mut value)
545 }
546 }
547 };
548}
549
550impl_try_from_var_for_signed!(i16);
551impl_try_from_var_for_signed!(i32);
552impl_try_from_var_for_signed!(i64);
553impl_try_from_var_for_signed!(i128);
554
555impl_try_from_var_for_unsigned!(u16);
556impl_try_from_var_for_unsigned!(u32);
557impl_try_from_var_for_unsigned!(u64);
558impl_try_from_var_for_unsigned!(u128);
559
560impl<'a> TryFrom<NumericVar<'a>> for i8 {
561 type Error = NumericTryFromError;
562
563 #[inline]
564 fn try_from(value: NumericVar<'a>) -> Result<Self, Self::Error> {
565 let val = TryInto::<i16>::try_into(value)?;
566 if val > i8::max_value() as i16 || val < i8::min_value() as i16 {
567 Err(NumericTryFromError::overflow())
568 } else {
569 Ok(val as i8)
570 }
571 }
572}
573
574impl<'a> TryFrom<NumericVar<'a>> for u8 {
575 type Error = NumericTryFromError;
576
577 #[inline]
578 fn try_from(value: NumericVar<'a>) -> Result<Self, Self::Error> {
579 let val = TryInto::<u16>::try_into(value)?;
580 if val > u8::max_value() as u16 {
581 Err(NumericTryFromError::overflow())
582 } else {
583 Ok(val as u8)
584 }
585 }
586}
587
588impl<'a> TryFrom<NumericVar<'a>> for usize {
589 type Error = NumericTryFromError;
590
591 #[inline]
592 fn try_from(value: NumericVar<'a>) -> Result<Self, Self::Error> {
593 if std::mem::size_of::<usize>() == 8 {
594 let val = TryInto::<u64>::try_into(value)?;
595 Ok(val as usize)
596 } else if std::mem::size_of::<usize>() == 4 {
597 let val = TryInto::<u32>::try_into(value)?;
598 Ok(val as usize)
599 } else {
600 panic!("invalid usize size")
601 }
602 }
603}
604
605impl<'a> TryFrom<NumericVar<'a>> for isize {
606 type Error = NumericTryFromError;
607
608 #[inline]
609 fn try_from(value: NumericVar<'a>) -> Result<Self, Self::Error> {
610 if std::mem::size_of::<isize>() == 8 {
611 let val = TryInto::<i64>::try_into(value)?;
612 Ok(val as isize)
613 } else if std::mem::size_of::<isize>() == 4 {
614 let val = TryInto::<i32>::try_into(value)?;
615 Ok(val as isize)
616 } else {
617 panic!("invalid usize size")
618 }
619 }
620}
621
622impl<'a> TryFrom<&NumericVar<'a>> for f32 {
623 type Error = NumericTryFromError;
624
625 #[inline]
626 fn try_from(value: &NumericVar<'a>) -> Result<Self, Self::Error> {
627 use std::fmt::Write;
628 if value.is_nan() {
629 return Ok(std::f32::NAN);
630 }
631 let mut buf = String::with_capacity(32);
632 buf.write_fmt(format_args!("{}", value))
633 .expect("returned an error unexpectedly");
634
635 match strtod::strtod(&buf) {
636 Some(val) => {
637 let f = val as f32;
638 if (f.is_infinite() && !val.is_infinite()) || (f == 0.0 && val != 0.0) {
639 return Err(NumericTryFromError::overflow());
640 }
641 Ok(f)
642 }
643 None => Err(NumericTryFromError::overflow()),
644 }
645 }
646}
647
648impl<'a> TryFrom<&NumericVar<'a>> for f64 {
649 type Error = NumericTryFromError;
650
651 #[inline]
652 fn try_from(value: &NumericVar<'a>) -> Result<Self, Self::Error> {
653 use std::fmt::Write;
654 if value.is_nan() {
655 return Ok(std::f64::NAN);
656 }
657 let mut buf = String::with_capacity(32);
658 buf.write_fmt(format_args!("{}", value))
659 .expect("returned an error unexpectedly");
660
661 match strtod::strtod(&buf) {
662 Some(f) => Ok(f),
663 None => Err(NumericTryFromError::overflow()),
664 }
665 }
666}
667
668macro_rules! impl_try_from_numeric_to_integer {
669 ($t: ty) => {
670 impl TryFrom<NumericBuf> for $t {
671 type Error = NumericTryFromError;
672
673 #[inline]
674 fn try_from(value: NumericBuf) -> Result<Self, Self::Error> {
675 TryFrom::try_from(value.into_var())
676 }
677 }
678 impl TryFrom<&NumericBuf> for $t {
679 type Error = NumericTryFromError;
680
681 #[inline]
682 fn try_from(value: &NumericBuf) -> Result<Self, Self::Error> {
683 let var = value.as_var().clone();
684 TryFrom::try_from(var)
685 }
686 }
687 impl TryFrom<&Numeric> for $t {
688 type Error = NumericTryFromError;
689
690 #[inline]
691 fn try_from(value: &Numeric) -> Result<Self, Self::Error> {
692 let var = value.as_var().clone();
693 TryFrom::try_from(var)
694 }
695 }
696 impl<'a> TryFrom<&NumericVar<'a>> for $t {
697 type Error = NumericTryFromError;
698
699 #[inline]
700 fn try_from(value: &NumericVar<'a>) -> Result<Self, Self::Error> {
701 let var = value.clone();
702 TryFrom::try_from(var)
703 }
704 }
705 };
706}
707
708macro_rules! impl_try_from_numeric_to_floating {
709 ($t: ty) => {
710 impl TryFrom<NumericBuf> for $t {
711 type Error = NumericTryFromError;
712
713 #[inline]
714 fn try_from(value: NumericBuf) -> Result<Self, Self::Error> {
715 TryFrom::try_from(&value.into_var())
716 }
717 }
718 impl TryFrom<&NumericBuf> for $t {
719 type Error = NumericTryFromError;
720
721 #[inline]
722 fn try_from(value: &NumericBuf) -> Result<Self, Self::Error> {
723 TryFrom::try_from(&value.as_var())
724 }
725 }
726 impl TryFrom<&Numeric> for $t {
727 type Error = NumericTryFromError;
728
729 #[inline]
730 fn try_from(value: &Numeric) -> Result<Self, Self::Error> {
731 TryFrom::try_from(&value.as_var())
732 }
733 }
734 };
735}
736
737impl_try_from_numeric_to_integer!(i8);
738impl_try_from_numeric_to_integer!(i16);
739impl_try_from_numeric_to_integer!(i32);
740impl_try_from_numeric_to_integer!(i64);
741impl_try_from_numeric_to_integer!(i128);
742impl_try_from_numeric_to_integer!(u8);
743impl_try_from_numeric_to_integer!(u16);
744impl_try_from_numeric_to_integer!(u32);
745impl_try_from_numeric_to_integer!(u64);
746impl_try_from_numeric_to_integer!(u128);
747impl_try_from_numeric_to_integer!(isize);
748impl_try_from_numeric_to_integer!(usize);
749
750impl_try_from_numeric_to_floating!(f32);
751impl_try_from_numeric_to_floating!(f64);
752
753#[cfg(test)]
754mod tests {
755 use super::*;
756 use crate::Numeric;
757 use std::convert::TryInto;
758 use std::fmt::Debug;
759 use std::ops::Deref;
760
761 fn transform(val: &NumericBuf) -> &Numeric {
763 val.deref()
764 }
765
766 fn assert_from<V: Into<NumericBuf>, E: AsRef<str>>(val: V, expected: E) {
767 let numeric = val.into();
768 assert_eq!(transform(&numeric).to_string(), expected.as_ref());
769 }
770
771 #[test]
772 fn from_i8() {
773 assert_from(0i8, "0");
774 assert_from(1i8, "1");
775 assert_from(-1i8, "-1");
776 assert_from(127i8, "127");
777 assert_from(-128i8, "-128");
778 }
779
780 #[test]
781 fn from_i16() {
782 assert_from(0i16, "0");
783 assert_from(1i16, "1");
784 assert_from(-1i16, "-1");
785 assert_from(32767i16, "32767");
786 assert_from(-32768i16, "-32768");
787 }
788
789 #[test]
790 fn from_i32() {
791 assert_from(0i32, "0");
792 assert_from(1i32, "1");
793 assert_from(-1i32, "-1");
794 assert_from(2147483647i32, "2147483647");
795 assert_from(-2147483647i32, "-2147483647");
796 }
797
798 #[test]
799 fn from_i64() {
800 assert_from(0i64, "0");
801 assert_from(1i64, "1");
802 assert_from(-1i64, "-1");
803 assert_from(9223372036854775807i64, "9223372036854775807");
804 assert_from(-9223372036854775808i64, "-9223372036854775808");
805 }
806
807 #[test]
808 fn from_i128() {
809 assert_from(0i128, "0");
810 assert_from(1i128, "1");
811 assert_from(-1i128, "-1");
812 assert_from(
813 170141183460469231731687303715884105727i128,
814 "170141183460469231731687303715884105727",
815 );
816 assert_from(
817 -170141183460469231731687303715884105728i128,
818 "-170141183460469231731687303715884105728",
819 );
820 }
821
822 #[test]
823 fn from_u8() {
824 assert_from(0u8, "0");
825 assert_from(1u8, "1");
826 assert_from(255u8, "255");
827 }
828
829 #[test]
830 fn from_u16() {
831 assert_from(0u16, "0");
832 assert_from(1u16, "1");
833 assert_from(65535u16, "65535");
834 }
835
836 #[test]
837 fn from_u32() {
838 assert_from(0u32, "0");
839 assert_from(1u32, "1");
840 assert_from(4294967295u32, "4294967295");
841 }
842
843 #[test]
844 fn from_u64() {
845 assert_from(0u64, "0");
846 assert_from(1u64, "1");
847 assert_from(18446744073709551615u64, "18446744073709551615");
848 }
849
850 #[test]
851 fn from_u128() {
852 assert_from(0u128, "0");
853 assert_from(1u128, "1");
854 assert_from(
855 340282366920938463463374607431768211455u128,
856 "340282366920938463463374607431768211455",
857 );
858 }
859
860 #[test]
861 fn from_bool() {
862 assert_from(true, "1");
863 assert_from(false, "0");
864 }
865
866 #[test]
867 fn from_usize() {
868 assert_from(0usize, "0");
869 assert_from(1usize, "1");
870 if std::mem::size_of::<usize>() == 8 {
871 assert_from(18446744073709551615usize, "18446744073709551615");
872 } else if std::mem::size_of::<usize>() == 4 {
873 assert_from(4294967295usize, "4294967295u32");
874 }
875 }
876
877 #[test]
878 fn from_isize() {
879 assert_from(0isize, "0");
880 assert_from(1isize, "1");
881 if std::mem::size_of::<isize>() == 8 {
882 assert_from(9223372036854775807isize, "9223372036854775807");
883 assert_from(-9223372036854775808isize, "-9223372036854775808");
884 } else if std::mem::size_of::<isize>() == 4 {
885 assert_from(2147483647isize, "2147483647");
886 assert_from(-2147483648isize, "-2147483648");
887 }
888 }
889
890 fn assert_try_from<V: TryInto<NumericBuf, Error = NumericTryFromError>, E: AsRef<str>>(
891 val: V,
892 expected: E,
893 ) {
894 let numeric = val.try_into().unwrap();
895 assert_eq!(transform(&numeric).to_string(), expected.as_ref());
896 }
897
898 fn assert_try_from_invalid<V: TryInto<NumericBuf, Error = NumericTryFromError>>(val: V) {
899 let result = val.try_into();
900 assert_eq!(result.unwrap_err(), NumericTryFromError::invalid());
901 }
902
903 #[test]
904 fn try_from_f32() {
905 assert_try_from_invalid(std::f32::INFINITY);
906 assert_try_from_invalid(std::f32::NEG_INFINITY);
907 assert_try_from(std::f32::NAN, "NaN");
908 assert_try_from(0.0f32, "0");
909 assert_try_from(-0.0f32, "0");
910 assert_try_from(0.000001f32, "0.000001");
911 assert_try_from(0.0000001f32, "0.0000001");
912 assert_try_from(0.555555f32, "0.555555");
913 assert_try_from(0.5555555f32, "0.555556");
914 assert_try_from(0.999999f32, "0.999999");
915 assert_try_from(0.9999999f32, "1");
916 assert_try_from(1.0f32, "1");
917 assert_try_from(1.00001f32, "1.00001");
918 assert_try_from(1.000001f32, "1");
919 assert_try_from(1.555555f32, "1.55555");
920 assert_try_from(1.5555555f32, "1.55556");
921 assert_try_from(1.99999f32, "1.99999");
922 assert_try_from(1.999999f32, "2");
923 assert_try_from(1e-6f32, "0.000001");
924 assert_try_from(1e-10f32, "0.0000000001");
925 assert_try_from(1.23456789e10f32, "12345700000");
926 assert_try_from(1.23456789e-10f32, "0.000000000123457");
927 }
928
929 #[test]
930 fn try_from_f64() {
931 assert_try_from_invalid(std::f64::INFINITY);
932 assert_try_from_invalid(std::f64::NEG_INFINITY);
933 assert_try_from(std::f64::NAN, "NaN");
934 assert_try_from(0.0f64, "0");
935 assert_try_from(-0.0f64, "0");
936 assert_try_from(0.000000000000001f64, "0.000000000000001");
937 assert_try_from(0.0000000000000001f64, "0.0000000000000001");
938 assert_try_from(0.555555555555555f64, "0.555555555555555");
939 assert_try_from(0.5555555555555556f64, "0.555555555555556");
940 assert_try_from(0.999999999999999f64, "0.999999999999999");
941 assert_try_from(0.9999999999999999f64, "1");
942 assert_try_from(1.0f64, "1");
943 assert_try_from(1.00000000000001f64, "1.00000000000001");
944 assert_try_from(1.000000000000001f64, "1");
945 assert_try_from(1.55555555555555f64, "1.55555555555555");
946 assert_try_from(1.555555555555556f64, "1.55555555555556");
947 assert_try_from(1.99999999999999f64, "1.99999999999999");
948 assert_try_from(1.999999999999999f64, "2");
949 assert_try_from(1e-6f64, "0.000001");
950 assert_try_from(1e-20f64, "0.00000000000000000001");
951 assert_try_from(1.234567890123456789e20f64, "123456789012346000000");
952 assert_try_from(
953 1.234567890123456789e-20f64,
954 "0.0000000000000000000123456789012346",
955 );
956 }
957
958 fn try_into<S: AsRef<str>, T: TryFrom<NumericBuf, Error = NumericTryFromError>>(s: S) -> T {
959 let n = s.as_ref().parse::<NumericBuf>().unwrap();
960 let val = TryInto::<T>::try_into(n).unwrap();
961 val
962 }
963
964 fn assert_try_into<
965 S: AsRef<str>,
966 T: TryFrom<NumericBuf, Error = NumericTryFromError> + PartialEq + Debug,
967 >(
968 s: S,
969 expected: T,
970 ) {
971 let val = try_into::<S, T>(s);
972 assert_eq!(val, expected);
973 }
974
975 fn assert_try_into_overflow<T: TryFrom<NumericBuf, Error = NumericTryFromError> + Debug>(
976 s: &str,
977 ) {
978 let n = s.parse::<NumericBuf>().unwrap();
979 let result = TryInto::<T>::try_into(n);
980 assert_eq!(result.unwrap_err(), NumericTryFromError::overflow());
981 }
982
983 fn assert_try_into_invalid<T: TryFrom<NumericBuf, Error = NumericTryFromError> + Debug>(
984 s: &str,
985 ) {
986 let n = s.parse::<NumericBuf>().unwrap();
987 let result = TryInto::<T>::try_into(n);
988 assert_eq!(result.unwrap_err(), NumericTryFromError::invalid());
989 }
990
991 #[test]
992 fn into_i8() {
993 assert_try_into("0", 0i8);
994 assert_try_into("1", 1i8);
995 assert_try_into("-1", -1i8);
996 assert_try_into("127", 127i8);
997 assert_try_into("-128", -128);
998 assert_try_into_overflow::<i8>("128");
999 assert_try_into_overflow::<i8>("-129");
1000 assert_try_into_invalid::<i8>("NaN");
1001 }
1002
1003 #[test]
1004 fn into_i16() {
1005 assert_try_into("0", 0i16);
1006 assert_try_into("1", 1i16);
1007 assert_try_into("-1", -1i16);
1008 assert_try_into("32767", 32767i16);
1009 assert_try_into("-32768", -32768i16);
1010 assert_try_into_overflow::<i16>("32768");
1011 assert_try_into_overflow::<i16>("-32769");
1012 assert_try_into_invalid::<i16>("NaN");
1013 }
1014
1015 #[test]
1016 fn into_i32() {
1017 assert_try_into("0", 0i32);
1018 assert_try_into("1", 1i32);
1019 assert_try_into("-1", -1i32);
1020 assert_try_into("2147483647", 2147483647i32);
1021 assert_try_into("-2147483648", -2147483648i32);
1022 assert_try_into_overflow::<i32>("2147483648");
1023 assert_try_into_overflow::<i32>("-2147483649");
1024 assert_try_into_invalid::<i32>("NaN");
1025 }
1026
1027 #[test]
1028 fn into_i64() {
1029 assert_try_into("0", 0i64);
1030 assert_try_into("1", 1i64);
1031 assert_try_into("-1", -1i64);
1032 assert_try_into("9223372036854775807", 9223372036854775807i64);
1033 assert_try_into("-9223372036854775808", -9223372036854775808i64);
1034 assert_try_into_overflow::<i64>("9223372036854775808");
1035 assert_try_into_overflow::<i64>("-9223372036854775809");
1036 assert_try_into_invalid::<i64>("NaN");
1037 }
1038
1039 #[test]
1040 fn into_i128() {
1041 assert_try_into("0", 0i128);
1042 assert_try_into("1", 1i128);
1043 assert_try_into("-1", -1i128);
1044 assert_try_into(
1045 "170141183460469231731687303715884105727",
1046 170141183460469231731687303715884105727i128,
1047 );
1048 assert_try_into(
1049 "-170141183460469231731687303715884105728",
1050 -170141183460469231731687303715884105728i128,
1051 );
1052 assert_try_into_overflow::<i128>("170141183460469231731687303715884105728");
1053 assert_try_into_overflow::<i128>("-170141183460469231731687303715884105729");
1054 assert_try_into_invalid::<i128>("NaN");
1055 }
1056
1057 #[test]
1058 fn into_u8() {
1059 assert_try_into("0", 0u8);
1060 assert_try_into("1", 1u8);
1061 assert_try_into("255", 255u8);
1062 assert_try_into_overflow::<u8>("256");
1063 assert_try_into_overflow::<u8>("-1");
1064 assert_try_into_invalid::<u8>("NaN");
1065 }
1066
1067 #[test]
1068 fn into_u16() {
1069 assert_try_into("0", 0u16);
1070 assert_try_into("1", 1u16);
1071 assert_try_into("65535", 65535u16);
1072 assert_try_into_overflow::<u16>("65536");
1073 assert_try_into_overflow::<u16>("-1");
1074 assert_try_into_invalid::<u16>("NaN");
1075 }
1076
1077 #[test]
1078 fn into_u32() {
1079 assert_try_into("0", 0u32);
1080 assert_try_into("1", 1u32);
1081 assert_try_into("4294967295", 4294967295u32);
1082 assert_try_into_overflow::<u32>("4294967296");
1083 assert_try_into_overflow::<u32>("-1");
1084 assert_try_into_invalid::<u32>("NaN");
1085 }
1086
1087 #[test]
1088 fn into_u64() {
1089 assert_try_into("0", 0u64);
1090 assert_try_into("1", 1u64);
1091 assert_try_into("18446744073709551615", 18446744073709551615u64);
1092 assert_try_into_overflow::<u64>("18446744073709551616");
1093 assert_try_into_overflow::<u64>("-1");
1094 assert_try_into_invalid::<u64>("NaN");
1095 }
1096
1097 #[test]
1098 fn into_u128() {
1099 assert_try_into("0", 0u128);
1100 assert_try_into("1", 1u128);
1101 assert_try_into(
1102 "340282366920938463463374607431768211455",
1103 340282366920938463463374607431768211455u128,
1104 );
1105 assert_try_into_overflow::<u128>("340282366920938463463374607431768211456");
1106 assert_try_into_overflow::<u128>("-1");
1107 assert_try_into_invalid::<u128>("NaN");
1108 }
1109
1110 #[test]
1111 fn into_usize() {
1112 assert_try_into("0", 0usize);
1113 assert_try_into("1", 1usize);
1114 if std::mem::size_of::<usize>() == 8 {
1115 assert_try_into("18446744073709551615", 18446744073709551615usize);
1116 assert_try_into_overflow::<usize>("18446744073709551616");
1117 assert_try_into_overflow::<usize>("-1");
1118 } else if std::mem::size_of::<usize>() == 4 {
1119 assert_try_into("4294967295", 4294967295usize);
1120 assert_try_into_overflow::<usize>("4294967296");
1121 assert_try_into_overflow::<usize>("-1");
1122 }
1123 assert_try_into_invalid::<usize>("NaN");
1124 }
1125
1126 #[test]
1127 fn into_isize() {
1128 assert_try_into("0", 0isize);
1129 assert_try_into("1", 1isize);
1130 assert_try_into("-1", -1isize);
1131 if std::mem::size_of::<isize>() == 8 {
1132 assert_try_into("9223372036854775807", 9223372036854775807isize);
1133 assert_try_into("-9223372036854775808", -9223372036854775808isize);
1134 assert_try_into_overflow::<isize>("9223372036854775808");
1135 assert_try_into_overflow::<isize>("-9223372036854775809");
1136 } else if std::mem::size_of::<isize>() == 4 {
1137 assert_try_into("2147483647", 2147483647isize);
1138 assert_try_into("-2147483648", -2147483648isize);
1139 assert_try_into_overflow::<isize>("2147483648");
1140 assert_try_into_overflow::<isize>("-2147483649");
1141 }
1142 assert_try_into_invalid::<isize>("NaN");
1143 }
1144
1145 #[test]
1146 fn into_f32() {
1147 assert_try_into("0", 0f32);
1148 assert_try_into("1", 1f32);
1149 assert_try_into("0.000001", 0.000001f32);
1150 assert_try_into("0.0000001", 0.0000001f32);
1151 assert_try_into("0.555555", 0.555555f32);
1152 assert_try_into("0.55555599", 0.555556f32);
1153 assert_try_into("0.999999", 0.999999f32);
1154 assert_try_into("0.99999999", 1.0f32);
1155 assert_try_into("1.00001", 1.00001f32);
1156 assert_try_into("1.00000001", 1.0f32);
1157 assert_try_into("1.23456789e10", 1.23456789e10f32);
1158 assert_try_into("1.23456789e-10", 1.23456789e-10f32);
1159 assert_try_into("3.40282347e+38", std::f32::MAX);
1160 assert_try_into("-3.40282347e+38", std::f32::MIN);
1161 assert_try_into_overflow::<f32>("1e39");
1162 assert_try_into("1.17549435e-38", std::f32::MIN_POSITIVE);
1163 assert!(try_into::<&str, f32>("NaN").is_nan());
1164 }
1165
1166 #[test]
1167 fn into_f64() {
1168 assert_try_into("0", 0f64);
1169 assert_try_into("1", 1f64);
1170 assert_try_into("0.000000000000001", 0.000000000000001f64);
1171 assert_try_into("0.555555555555555", 0.555555555555555f64);
1172 assert_try_into("0.55555555555555599", 0.555555555555556f64);
1173 assert_try_into("0.999999999999999", 0.999999999999999f64);
1174 assert_try_into("0.99999999999999999", 1.0f64);
1175 assert_try_into("1.00000000000001", 1.00000000000001f64);
1176 assert_try_into("1.0000000000000001", 1.0f64);
1177 assert_try_into("1.7976931348623157e+308", std::f64::MAX);
1178 assert_try_into("-1.7976931348623157e+308", std::f64::MIN);
1179 assert_try_into("1e309", std::f64::INFINITY);
1180 assert_try_into("2.2250738585072014e-308", std::f64::MIN_POSITIVE);
1181 assert!(try_into::<&str, f64>("NaN").is_nan());
1182 }
1183}