Skip to main content

const_num_traits/
cast.rs

1use core::mem::size_of;
2use core::num::Wrapping;
3use core::num::{
4    NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
5    NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
6};
7
8c0nst::c0nst! {
9/// A generic trait for converting a value to a number.
10///
11/// A value can be represented by the target type when it lies within
12/// the range of scalars supported by the target type.
13/// For example, a negative integer cannot be represented by an unsigned
14/// integer type, and an `i64` with a very high magnitude might not be
15/// convertible to an `i32`.
16/// On the other hand, conversions with possible precision loss or truncation
17/// are admitted, like an `f32` with a decimal part to an integer type, or
18/// even a large `f64` saturating to `f32` infinity.
19pub c0nst trait ToPrimitive {
20    /// Converts the value of `self` to an `isize`. If the value cannot be
21    /// represented by an `isize`, then `None` is returned.
22    fn to_isize(&self) -> Option<isize> {
23        match self.to_i64() { Some(v) => crate::CheckedCast::<isize>::checked_cast(v), None => None }
24    }
25
26    /// Converts the value of `self` to an `i8`. If the value cannot be
27    /// represented by an `i8`, then `None` is returned.
28    fn to_i8(&self) -> Option<i8> {
29        match self.to_i64() { Some(v) => crate::CheckedCast::<i8>::checked_cast(v), None => None }
30    }
31
32    /// Converts the value of `self` to an `i16`. If the value cannot be
33    /// represented by an `i16`, then `None` is returned.
34    fn to_i16(&self) -> Option<i16> {
35        match self.to_i64() { Some(v) => crate::CheckedCast::<i16>::checked_cast(v), None => None }
36    }
37
38    /// Converts the value of `self` to an `i32`. If the value cannot be
39    /// represented by an `i32`, then `None` is returned.
40    fn to_i32(&self) -> Option<i32> {
41        match self.to_i64() { Some(v) => crate::CheckedCast::<i32>::checked_cast(v), None => None }
42    }
43
44    /// Converts the value of `self` to an `i64`. If the value cannot be
45    /// represented by an `i64`, then `None` is returned.
46    fn to_i64(&self) -> Option<i64>;
47
48    /// Converts the value of `self` to an `i128`. If the value cannot be
49    /// represented by an `i128`, then `None` is returned.
50    fn to_i128(&self) -> Option<i128> {
51        // Fall back to `to_u64` so values in `(i64::MAX, u64::MAX]` (which
52        // `to_i64` rejects but `i128` represents exactly) still convert.
53        match self.to_i64() {
54            Some(i) => Some(i as i128),
55            None => match self.to_u64() {
56                Some(u) => Some(u as i128),
57                None => None,
58            },
59        }
60    }
61
62    /// Converts the value of `self` to a `usize`. If the value cannot be
63    /// represented by a `usize`, then `None` is returned.
64    fn to_usize(&self) -> Option<usize> {
65        match self.to_u64() { Some(v) => crate::CheckedCast::<usize>::checked_cast(v), None => None }
66    }
67
68    /// Converts the value of `self` to a `u8`. If the value cannot be
69    /// represented by a `u8`, then `None` is returned.
70    fn to_u8(&self) -> Option<u8> {
71        match self.to_u64() { Some(v) => crate::CheckedCast::<u8>::checked_cast(v), None => None }
72    }
73
74    /// Converts the value of `self` to a `u16`. If the value cannot be
75    /// represented by a `u16`, then `None` is returned.
76    fn to_u16(&self) -> Option<u16> {
77        match self.to_u64() { Some(v) => crate::CheckedCast::<u16>::checked_cast(v), None => None }
78    }
79
80    /// Converts the value of `self` to a `u32`. If the value cannot be
81    /// represented by a `u32`, then `None` is returned.
82    fn to_u32(&self) -> Option<u32> {
83        match self.to_u64() { Some(v) => crate::CheckedCast::<u32>::checked_cast(v), None => None }
84    }
85
86    /// Converts the value of `self` to a `u64`. If the value cannot be
87    /// represented by a `u64`, then `None` is returned.
88    fn to_u64(&self) -> Option<u64>;
89
90    /// Converts the value of `self` to a `u128`. If the value cannot be
91    /// represented by a `u128`, then `None` is returned.
92    fn to_u128(&self) -> Option<u128> {
93        match self.to_u64() { Some(u) => Some(u as u128), None => None }
94    }
95
96    /// Converts the value of `self` to an `f32`. Overflows may map to positive
97    /// or negative infinity, otherwise `None` is returned if the value cannot
98    /// be represented by an `f32`.
99    fn to_f32(&self) -> Option<f32> {
100        // `f64 as f32` is total: in-range values round, overflow saturates to
101        // ±inf (an admitted conversion, per the doc above), NaN stays NaN. So
102        // this is `None` only when `to_f64` is.
103        match self.to_f64() {
104            Some(v) => Some(v as f32),
105            None => None,
106        }
107    }
108
109    /// Converts the value of `self` to an `f64`. Overflows may map to positive
110    /// or negative infinity, otherwise `None` is returned if the value cannot
111    /// be represented by an `f64`.
112    fn to_f64(&self) -> Option<f64> {
113        match self.to_i64() {
114            Some(i) => Some(i as f64),
115            None => match self.to_u64() { Some(u) => Some(u as f64), None => None },
116        }
117    }
118}
119}
120
121macro_rules! impl_to_primitive_int_to_int {
122    ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$(
123        #[inline]
124        fn $method(&self) -> Option<$DstT> {
125            let min = $DstT::MIN as $SrcT;
126            let max = $DstT::MAX as $SrcT;
127            if size_of::<$SrcT>() <= size_of::<$DstT>() || (min <= *self && *self <= max) {
128                Some(*self as $DstT)
129            } else {
130                None
131            }
132        }
133    )*}
134}
135
136macro_rules! impl_to_primitive_int_to_uint {
137    ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$(
138        #[inline]
139        fn $method(&self) -> Option<$DstT> {
140            let max = $DstT::MAX as $SrcT;
141            if 0 <= *self && (size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max) {
142                Some(*self as $DstT)
143            } else {
144                None
145            }
146        }
147    )*}
148}
149
150macro_rules! impl_to_primitive_int {
151    ($T:ident) => {
152        c0nst::c0nst! {
153        c0nst impl ToPrimitive for $T {
154            impl_to_primitive_int_to_int! { $T:
155                fn to_isize -> isize;
156                fn to_i8 -> i8;
157                fn to_i16 -> i16;
158                fn to_i32 -> i32;
159                fn to_i64 -> i64;
160                fn to_i128 -> i128;
161            }
162
163            impl_to_primitive_int_to_uint! { $T:
164                fn to_usize -> usize;
165                fn to_u8 -> u8;
166                fn to_u16 -> u16;
167                fn to_u32 -> u32;
168                fn to_u64 -> u64;
169                fn to_u128 -> u128;
170            }
171
172            #[inline]
173            fn to_f32(&self) -> Option<f32> {
174                Some(*self as f32)
175            }
176            #[inline]
177            fn to_f64(&self) -> Option<f64> {
178                Some(*self as f64)
179            }
180        }
181        }
182    };
183}
184
185impl_to_primitive_int!(isize);
186impl_to_primitive_int!(i8);
187impl_to_primitive_int!(i16);
188impl_to_primitive_int!(i32);
189impl_to_primitive_int!(i64);
190impl_to_primitive_int!(i128);
191
192macro_rules! impl_to_primitive_uint_to_int {
193    ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$(
194        #[inline]
195        fn $method(&self) -> Option<$DstT> {
196            let max = $DstT::MAX as $SrcT;
197            if size_of::<$SrcT>() < size_of::<$DstT>() || *self <= max {
198                Some(*self as $DstT)
199            } else {
200                None
201            }
202        }
203    )*}
204}
205
206macro_rules! impl_to_primitive_uint_to_uint {
207    ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$(
208        #[inline]
209        fn $method(&self) -> Option<$DstT> {
210            let max = $DstT::MAX as $SrcT;
211            if size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max {
212                Some(*self as $DstT)
213            } else {
214                None
215            }
216        }
217    )*}
218}
219
220macro_rules! impl_to_primitive_uint {
221    ($T:ident) => {
222        c0nst::c0nst! {
223        c0nst impl ToPrimitive for $T {
224            impl_to_primitive_uint_to_int! { $T:
225                fn to_isize -> isize;
226                fn to_i8 -> i8;
227                fn to_i16 -> i16;
228                fn to_i32 -> i32;
229                fn to_i64 -> i64;
230                fn to_i128 -> i128;
231            }
232
233            impl_to_primitive_uint_to_uint! { $T:
234                fn to_usize -> usize;
235                fn to_u8 -> u8;
236                fn to_u16 -> u16;
237                fn to_u32 -> u32;
238                fn to_u64 -> u64;
239                fn to_u128 -> u128;
240            }
241
242            #[inline]
243            fn to_f32(&self) -> Option<f32> {
244                Some(*self as f32)
245            }
246            #[inline]
247            fn to_f64(&self) -> Option<f64> {
248                Some(*self as f64)
249            }
250        }
251        }
252    };
253}
254
255impl_to_primitive_uint!(usize);
256impl_to_primitive_uint!(u8);
257impl_to_primitive_uint!(u16);
258impl_to_primitive_uint!(u32);
259impl_to_primitive_uint!(u64);
260impl_to_primitive_uint!(u128);
261
262macro_rules! impl_to_primitive_nonzero_to_method {
263    ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$(
264        #[inline]
265        fn $method(&self) -> Option<$DstT> {
266            self.get().$method()
267        }
268    )*}
269}
270
271macro_rules! impl_to_primitive_nonzero {
272    ($T:ident) => {
273        c0nst::c0nst! {
274        c0nst impl ToPrimitive for $T {
275            impl_to_primitive_nonzero_to_method! { $T:
276                fn to_isize -> isize;
277                fn to_i8 -> i8;
278                fn to_i16 -> i16;
279                fn to_i32 -> i32;
280                fn to_i64 -> i64;
281                fn to_i128 -> i128;
282
283                fn to_usize -> usize;
284                fn to_u8 -> u8;
285                fn to_u16 -> u16;
286                fn to_u32 -> u32;
287                fn to_u64 -> u64;
288                fn to_u128 -> u128;
289
290                fn to_f32 -> f32;
291                fn to_f64 -> f64;
292            }
293        }
294        }
295    };
296}
297
298impl_to_primitive_nonzero!(NonZeroUsize);
299impl_to_primitive_nonzero!(NonZeroU8);
300impl_to_primitive_nonzero!(NonZeroU16);
301impl_to_primitive_nonzero!(NonZeroU32);
302impl_to_primitive_nonzero!(NonZeroU64);
303impl_to_primitive_nonzero!(NonZeroU128);
304
305impl_to_primitive_nonzero!(NonZeroIsize);
306impl_to_primitive_nonzero!(NonZeroI8);
307impl_to_primitive_nonzero!(NonZeroI16);
308impl_to_primitive_nonzero!(NonZeroI32);
309impl_to_primitive_nonzero!(NonZeroI64);
310impl_to_primitive_nonzero!(NonZeroI128);
311
312macro_rules! impl_to_primitive_float_to_float {
313    ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$(
314        #[inline]
315        fn $method(&self) -> Option<$DstT> {
316            // We can safely cast all values, whether NaN, +-inf, or finite.
317            // Finite values that are reducing size may saturate to +-inf.
318            Some(*self as $DstT)
319        }
320    )*}
321}
322
323macro_rules! float_to_int_unchecked {
324    // The range check above already guarantees the value is representable.
325    // `to_int_unchecked` would be slightly faster but isn't const yet; the
326    // saturating `as` cast gives the same answer for in-range inputs.
327    ($float:expr => $int:ty) => {
328        $float as $int
329    };
330}
331
332macro_rules! impl_to_primitive_float_to_signed_int {
333    ($f:ident : $( fn $method:ident -> $i:ident ; )*) => {$(
334        #[inline]
335        fn $method(&self) -> Option<$i> {
336            // Float as int truncates toward zero, so we want to allow values
337            // in the exclusive range `(MIN-1, MAX+1)`.
338            if size_of::<$f>() > size_of::<$i>() {
339                // With a larger size, we can represent the range exactly.
340                const MIN_M1: $f = $i::MIN as $f - 1.0;
341                const MAX_P1: $f = $i::MAX as $f + 1.0;
342                if *self > MIN_M1 && *self < MAX_P1 {
343                    return Some(float_to_int_unchecked!(*self => $i));
344                }
345            } else {
346                // We can't represent `MIN-1` exactly, but there's no fractional part
347                // at this magnitude, so we can just use a `MIN` inclusive boundary.
348                const MIN: $f = $i::MIN as $f;
349                // We can't represent `MAX` exactly, but it will round up to exactly
350                // `MAX+1` (a power of two) when we cast it.
351                const MAX_P1: $f = $i::MAX as $f;
352                if *self >= MIN && *self < MAX_P1 {
353                    return Some(float_to_int_unchecked!(*self => $i));
354                }
355            }
356            None
357        }
358    )*}
359}
360
361macro_rules! impl_to_primitive_float_to_unsigned_int {
362    ($f:ident : $( fn $method:ident -> $u:ident ; )*) => {$(
363        #[inline]
364        fn $method(&self) -> Option<$u> {
365            // Float as int truncates toward zero, so we want to allow values
366            // in the exclusive range `(-1, MAX+1)`.
367            if size_of::<$f>() > size_of::<$u>() {
368                // With a larger size, we can represent the range exactly.
369                const MAX_P1: $f = $u::MAX as $f + 1.0;
370                if *self > -1.0 && *self < MAX_P1 {
371                    return Some(float_to_int_unchecked!(*self => $u));
372                }
373            } else {
374                // We can't represent `MAX` exactly, but it will round up to exactly
375                // `MAX+1` (a power of two) when we cast it.
376                // (`u128::MAX as f32` is infinity, but this is still ok.)
377                const MAX_P1: $f = $u::MAX as $f;
378                if *self > -1.0 && *self < MAX_P1 {
379                    return Some(float_to_int_unchecked!(*self => $u));
380                }
381            }
382            None
383        }
384    )*}
385}
386
387macro_rules! impl_to_primitive_float {
388    ($T:ident) => {
389        c0nst::c0nst! {
390        c0nst impl ToPrimitive for $T {
391            impl_to_primitive_float_to_signed_int! { $T:
392                fn to_isize -> isize;
393                fn to_i8 -> i8;
394                fn to_i16 -> i16;
395                fn to_i32 -> i32;
396                fn to_i64 -> i64;
397                fn to_i128 -> i128;
398            }
399
400            impl_to_primitive_float_to_unsigned_int! { $T:
401                fn to_usize -> usize;
402                fn to_u8 -> u8;
403                fn to_u16 -> u16;
404                fn to_u32 -> u32;
405                fn to_u64 -> u64;
406                fn to_u128 -> u128;
407            }
408
409            impl_to_primitive_float_to_float! { $T:
410                fn to_f32 -> f32;
411                fn to_f64 -> f64;
412            }
413        }
414        }
415    };
416}
417
418impl_to_primitive_float!(f32);
419impl_to_primitive_float!(f64);
420
421c0nst::c0nst! {
422/// A generic trait for converting a number to a value.
423///
424/// A value can be represented by the target type when it lies within
425/// the range of scalars supported by the target type.
426/// For example, a negative integer cannot be represented by an unsigned
427/// integer type, and an `i64` with a very high magnitude might not be
428/// convertible to an `i32`.
429/// On the other hand, conversions with possible precision loss or truncation
430/// are admitted, like an `f32` with a decimal part to an integer type, or
431/// even a large `f64` saturating to `f32` infinity.
432pub c0nst trait FromPrimitive: Sized {
433    /// Converts an `isize` to return an optional value of this type. If the
434    /// value cannot be represented by this type, then `None` is returned.
435    fn from_isize(n: isize) -> Option<Self> { Self::from_i64(n as i64) }
436
437    /// Converts an `i8` to return an optional value of this type. If the
438    /// value cannot be represented by this type, then `None` is returned.
439    fn from_i8(n: i8) -> Option<Self> { Self::from_i64(n as i64) }
440
441    /// Converts an `i16` to return an optional value of this type. If the
442    /// value cannot be represented by this type, then `None` is returned.
443    fn from_i16(n: i16) -> Option<Self> { Self::from_i64(n as i64) }
444
445    /// Converts an `i32` to return an optional value of this type. If the
446    /// value cannot be represented by this type, then `None` is returned.
447    fn from_i32(n: i32) -> Option<Self> { Self::from_i64(n as i64) }
448
449    /// Converts an `i64` to return an optional value of this type. If the
450    /// value cannot be represented by this type, then `None` is returned.
451    fn from_i64(n: i64) -> Option<Self>;
452
453    /// Converts an `i128` to return an optional value of this type. If the
454    /// value cannot be represented by this type, then `None` is returned.
455    fn from_i128(n: i128) -> Option<Self> {
456        // Route non-negative values through `from_u128` so the full
457        // `(i64::MAX, u64::MAX]` range stays reachable; negatives go through
458        // `from_i64`.
459        if n >= 0 {
460            Self::from_u128(n as u128)
461        } else if n >= i64::MIN as i128 {
462            Self::from_i64(n as i64)
463        } else {
464            None
465        }
466    }
467
468    /// Converts a `usize` to return an optional value of this type. If the
469    /// value cannot be represented by this type, then `None` is returned.
470    fn from_usize(n: usize) -> Option<Self> { Self::from_u64(n as u64) }
471
472    /// Converts an `u8` to return an optional value of this type. If the
473    /// value cannot be represented by this type, then `None` is returned.
474    fn from_u8(n: u8) -> Option<Self> { Self::from_u64(n as u64) }
475
476    /// Converts an `u16` to return an optional value of this type. If the
477    /// value cannot be represented by this type, then `None` is returned.
478    fn from_u16(n: u16) -> Option<Self> { Self::from_u64(n as u64) }
479
480    /// Converts an `u32` to return an optional value of this type. If the
481    /// value cannot be represented by this type, then `None` is returned.
482    fn from_u32(n: u32) -> Option<Self> { Self::from_u64(n as u64) }
483
484    /// Converts an `u64` to return an optional value of this type. If the
485    /// value cannot be represented by this type, then `None` is returned.
486    fn from_u64(n: u64) -> Option<Self>;
487
488    /// Converts an `u128` to return an optional value of this type. If the
489    /// value cannot be represented by this type, then `None` is returned.
490    fn from_u128(n: u128) -> Option<Self> {
491        if n <= u64::MAX as u128 { Self::from_u64(n as u64) } else { None }
492    }
493
494    /// Converts a `f32` to return an optional value of this type. If the
495    /// value cannot be represented by this type, then `None` is returned.
496    fn from_f32(n: f32) -> Option<Self> { Self::from_f64(n as f64) }
497
498    /// Converts a `f64` to return an optional value of this type. If the
499    /// value cannot be represented by this type, then `None` is returned.
500    fn from_f64(n: f64) -> Option<Self> {
501        match crate::ToPrimitive::to_i64(&n) {
502            Some(i) => Self::from_i64(i),
503            None => match crate::ToPrimitive::to_u64(&n) { Some(u) => Self::from_u64(u), None => None },
504        }
505    }
506}
507}
508
509macro_rules! impl_from_primitive {
510    ($T:ty, $to_ty:ident) => {
511        c0nst::c0nst! {
512        c0nst impl FromPrimitive for $T {
513            #[inline]
514            fn from_isize(n: isize) -> Option<$T> {
515                n.$to_ty()
516            }
517            #[inline]
518            fn from_i8(n: i8) -> Option<$T> {
519                n.$to_ty()
520            }
521            #[inline]
522            fn from_i16(n: i16) -> Option<$T> {
523                n.$to_ty()
524            }
525            #[inline]
526            fn from_i32(n: i32) -> Option<$T> {
527                n.$to_ty()
528            }
529            #[inline]
530            fn from_i64(n: i64) -> Option<$T> {
531                n.$to_ty()
532            }
533            #[inline]
534            fn from_i128(n: i128) -> Option<$T> {
535                n.$to_ty()
536            }
537
538            #[inline]
539            fn from_usize(n: usize) -> Option<$T> {
540                n.$to_ty()
541            }
542            #[inline]
543            fn from_u8(n: u8) -> Option<$T> {
544                n.$to_ty()
545            }
546            #[inline]
547            fn from_u16(n: u16) -> Option<$T> {
548                n.$to_ty()
549            }
550            #[inline]
551            fn from_u32(n: u32) -> Option<$T> {
552                n.$to_ty()
553            }
554            #[inline]
555            fn from_u64(n: u64) -> Option<$T> {
556                n.$to_ty()
557            }
558            #[inline]
559            fn from_u128(n: u128) -> Option<$T> {
560                n.$to_ty()
561            }
562
563            #[inline]
564            fn from_f32(n: f32) -> Option<$T> {
565                n.$to_ty()
566            }
567            #[inline]
568            fn from_f64(n: f64) -> Option<$T> {
569                n.$to_ty()
570            }
571        }
572        }
573    };
574}
575
576impl_from_primitive!(isize, to_isize);
577impl_from_primitive!(i8, to_i8);
578impl_from_primitive!(i16, to_i16);
579impl_from_primitive!(i32, to_i32);
580impl_from_primitive!(i64, to_i64);
581impl_from_primitive!(i128, to_i128);
582impl_from_primitive!(usize, to_usize);
583impl_from_primitive!(u8, to_u8);
584impl_from_primitive!(u16, to_u16);
585impl_from_primitive!(u32, to_u32);
586impl_from_primitive!(u64, to_u64);
587impl_from_primitive!(u128, to_u128);
588impl_from_primitive!(f32, to_f32);
589impl_from_primitive!(f64, to_f64);
590
591// `Option::and_then` is not yet a const fn; written as `match` to stay
592// const-friendly while preserving semantics.
593macro_rules! impl_from_primitive_nonzero_one {
594    ($t:ty, $T:ty, $to_ty:ident, $method:ident) => {
595        #[inline]
596        fn $method(n: $t) -> Option<$T> {
597            match n.$to_ty() {
598                Some(v) => Self::new(v),
599                None => None,
600            }
601        }
602    };
603}
604
605macro_rules! impl_from_primitive_nonzero {
606    ($T:ty, $to_ty:ident) => {
607        c0nst::c0nst! {
608        c0nst impl FromPrimitive for $T {
609            impl_from_primitive_nonzero_one!(isize, $T, $to_ty, from_isize);
610            impl_from_primitive_nonzero_one!(i8,    $T, $to_ty, from_i8);
611            impl_from_primitive_nonzero_one!(i16,   $T, $to_ty, from_i16);
612            impl_from_primitive_nonzero_one!(i32,   $T, $to_ty, from_i32);
613            impl_from_primitive_nonzero_one!(i64,   $T, $to_ty, from_i64);
614            impl_from_primitive_nonzero_one!(i128,  $T, $to_ty, from_i128);
615
616            impl_from_primitive_nonzero_one!(usize, $T, $to_ty, from_usize);
617            impl_from_primitive_nonzero_one!(u8,    $T, $to_ty, from_u8);
618            impl_from_primitive_nonzero_one!(u16,   $T, $to_ty, from_u16);
619            impl_from_primitive_nonzero_one!(u32,   $T, $to_ty, from_u32);
620            impl_from_primitive_nonzero_one!(u64,   $T, $to_ty, from_u64);
621            impl_from_primitive_nonzero_one!(u128,  $T, $to_ty, from_u128);
622
623            impl_from_primitive_nonzero_one!(f32, $T, $to_ty, from_f32);
624            impl_from_primitive_nonzero_one!(f64, $T, $to_ty, from_f64);
625        }
626        }
627    };
628}
629
630impl_from_primitive_nonzero!(NonZeroIsize, to_isize);
631impl_from_primitive_nonzero!(NonZeroI8, to_i8);
632impl_from_primitive_nonzero!(NonZeroI16, to_i16);
633impl_from_primitive_nonzero!(NonZeroI32, to_i32);
634impl_from_primitive_nonzero!(NonZeroI64, to_i64);
635impl_from_primitive_nonzero!(NonZeroI128, to_i128);
636impl_from_primitive_nonzero!(NonZeroUsize, to_usize);
637impl_from_primitive_nonzero!(NonZeroU8, to_u8);
638impl_from_primitive_nonzero!(NonZeroU16, to_u16);
639impl_from_primitive_nonzero!(NonZeroU32, to_u32);
640impl_from_primitive_nonzero!(NonZeroU64, to_u64);
641impl_from_primitive_nonzero!(NonZeroU128, to_u128);
642
643macro_rules! impl_to_primitive_wrapping {
644    ($( fn $method:ident -> $i:ident ; )*) => {$(
645        #[inline]
646        fn $method(&self) -> Option<$i> {
647            (self.0).$method()
648        }
649    )*}
650}
651
652c0nst::c0nst! {
653c0nst impl<T: [c0nst] ToPrimitive> ToPrimitive for Wrapping<T> {
654    impl_to_primitive_wrapping! {
655        fn to_isize -> isize;
656        fn to_i8 -> i8;
657        fn to_i16 -> i16;
658        fn to_i32 -> i32;
659        fn to_i64 -> i64;
660        fn to_i128 -> i128;
661
662        fn to_usize -> usize;
663        fn to_u8 -> u8;
664        fn to_u16 -> u16;
665        fn to_u32 -> u32;
666        fn to_u64 -> u64;
667        fn to_u128 -> u128;
668
669        fn to_f32 -> f32;
670        fn to_f64 -> f64;
671    }
672}
673}
674
675macro_rules! impl_from_primitive_wrapping {
676    ($( fn $method:ident ( $i:ident ); )*) => {$(
677        #[inline]
678        fn $method(n: $i) -> Option<Self> {
679            // Hand-rolled match — `Option::map` is not yet a const fn.
680            match T::$method(n) {
681                Some(v) => Some(Wrapping(v)),
682                None => None,
683            }
684        }
685    )*}
686}
687
688c0nst::c0nst! {
689c0nst impl<T: [c0nst] FromPrimitive + [c0nst] Destruct> FromPrimitive for Wrapping<T> {
690    impl_from_primitive_wrapping! {
691        fn from_isize(isize);
692        fn from_i8(i8);
693        fn from_i16(i16);
694        fn from_i32(i32);
695        fn from_i64(i64);
696        fn from_i128(i128);
697
698        fn from_usize(usize);
699        fn from_u8(u8);
700        fn from_u16(u16);
701        fn from_u32(u32);
702        fn from_u64(u64);
703        fn from_u128(u128);
704
705        fn from_f32(f32);
706        fn from_f64(f64);
707    }
708}
709}
710
711c0nst::c0nst! {
712/// Cast from one machine scalar to another.
713///
714/// # Examples
715///
716/// ```
717/// # use const_num_traits as num;
718/// let twenty: f32 = num::cast(0x14).unwrap();
719/// assert_eq!(twenty, 20f32);
720/// ```
721///
722#[inline]
723pub c0nst fn cast<T: [c0nst] NumCast + [c0nst] Destruct, U: [c0nst] NumCast>(n: T) -> Option<U> {
724    NumCast::from(n)
725}
726}
727
728c0nst::c0nst! {
729/// An interface for casting between machine scalars.
730pub c0nst trait NumCast: Sized + [c0nst] ToPrimitive {
731    /// Creates a number from another value that can be converted into
732    /// a primitive via the `ToPrimitive` trait. If the source value cannot be
733    /// represented by the target type, then `None` is returned.
734    ///
735    /// A value can be represented by the target type when it lies within
736    /// the range of scalars supported by the target type.
737    /// For example, a negative integer cannot be represented by an unsigned
738    /// integer type, and an `i64` with a very high magnitude might not be
739    /// convertible to an `i32`.
740    /// On the other hand, conversions with possible precision loss or truncation
741    /// are admitted, like an `f32` with a decimal part to an integer type, or
742    /// even a large `f64` saturating to `f32` infinity.
743    fn from<T: [c0nst] ToPrimitive + [c0nst] Destruct>(n: T) -> Option<Self>;
744}
745}
746
747macro_rules! impl_num_cast {
748    ($T:ty, $conv:ident) => {
749        c0nst::c0nst! {
750        c0nst impl NumCast for $T {
751            #[inline]
752            fn from<N: [c0nst] ToPrimitive + [c0nst] Destruct>(n: N) -> Option<$T> {
753                n.$conv()
754            }
755        }
756        }
757    };
758}
759
760impl_num_cast!(u8, to_u8);
761impl_num_cast!(u16, to_u16);
762impl_num_cast!(u32, to_u32);
763impl_num_cast!(u64, to_u64);
764impl_num_cast!(u128, to_u128);
765impl_num_cast!(usize, to_usize);
766impl_num_cast!(i8, to_i8);
767impl_num_cast!(i16, to_i16);
768impl_num_cast!(i32, to_i32);
769impl_num_cast!(i64, to_i64);
770impl_num_cast!(i128, to_i128);
771impl_num_cast!(isize, to_isize);
772impl_num_cast!(f32, to_f32);
773impl_num_cast!(f64, to_f64);
774
775macro_rules! impl_num_cast_nonzero {
776    ($T:ty, $conv:ident) => {
777        c0nst::c0nst! {
778        c0nst impl NumCast for $T {
779            #[inline]
780            fn from<N: [c0nst] ToPrimitive + [c0nst] Destruct>(n: N) -> Option<$T> {
781                // `Option::and_then` isn't a const fn yet — hand-roll as match.
782                match n.$conv() {
783                    Some(v) => Self::new(v),
784                    None => None,
785                }
786            }
787        }
788        }
789    };
790}
791
792impl_num_cast_nonzero!(NonZeroUsize, to_usize);
793impl_num_cast_nonzero!(NonZeroU8, to_u8);
794impl_num_cast_nonzero!(NonZeroU16, to_u16);
795impl_num_cast_nonzero!(NonZeroU32, to_u32);
796impl_num_cast_nonzero!(NonZeroU64, to_u64);
797impl_num_cast_nonzero!(NonZeroU128, to_u128);
798
799impl_num_cast_nonzero!(NonZeroIsize, to_isize);
800impl_num_cast_nonzero!(NonZeroI8, to_i8);
801impl_num_cast_nonzero!(NonZeroI16, to_i16);
802impl_num_cast_nonzero!(NonZeroI32, to_i32);
803impl_num_cast_nonzero!(NonZeroI64, to_i64);
804impl_num_cast_nonzero!(NonZeroI128, to_i128);
805
806c0nst::c0nst! {
807c0nst impl<T: [c0nst] NumCast + [c0nst] Destruct> NumCast for Wrapping<T> {
808    fn from<U: [c0nst] ToPrimitive + [c0nst] Destruct>(n: U) -> Option<Self> {
809        // Hand-rolled match — `Option::map` is not yet a const fn.
810        match T::from(n) {
811            Some(v) => Some(Wrapping(v)),
812            None => None,
813        }
814    }
815}
816}
817
818c0nst::c0nst! {
819/// A generic interface for casting between machine scalars with the
820/// `as` operator, which admits narrowing and precision loss.
821/// Implementers of this trait `AsPrimitive` should behave like a primitive
822/// numeric type (e.g. a newtype around another primitive), and the
823/// intended conversion must never fail.
824///
825/// # Examples
826///
827/// ```
828/// # use const_num_traits::AsPrimitive;
829/// let three: i32 = (3.14159265f32).as_();
830/// assert_eq!(three, 3);
831/// ```
832///
833/// # Safety
834///
835/// **In Rust versions before 1.45.0**, some uses of the `as` operator were not entirely safe.
836/// In particular, it was undefined behavior if
837/// a truncated floating point value could not fit in the target integer
838/// type ([#10184](https://github.com/rust-lang/rust/issues/10184)).
839///
840/// ```ignore
841/// # use const_num_traits::AsPrimitive;
842/// let x: u8 = (1.04E+17).as_(); // UB
843/// ```
844///
845pub c0nst trait AsPrimitive<T>: 'static + Copy
846where
847    T: 'static + Copy,
848{
849    /// Convert a value to another, using the `as` operator.
850    fn as_(self) -> T;
851}
852}
853
854macro_rules! impl_as_primitive {
855    (@ $T: ty =>  impl $U: ty ) => {
856        c0nst::c0nst! {
857        c0nst impl AsPrimitive<$U> for $T {
858            #[inline] fn as_(self) -> $U { self as $U }
859        }
860        }
861    };
862    (@ $T: ty => { $( $U: ty ),* } ) => {$(
863        impl_as_primitive!(@ $T => impl $U);
864    )*};
865    ($T: ty => { $( $U: ty ),* } ) => {
866        impl_as_primitive!(@ $T => { $( $U ),* });
867        impl_as_primitive!(@ $T => { u8, u16, u32, u64, u128, usize });
868        impl_as_primitive!(@ $T => { i8, i16, i32, i64, i128, isize });
869    };
870}
871
872impl_as_primitive!(u8 => { char, f32, f64 });
873impl_as_primitive!(i8 => { f32, f64 });
874impl_as_primitive!(u16 => { f32, f64 });
875impl_as_primitive!(i16 => { f32, f64 });
876impl_as_primitive!(u32 => { f32, f64 });
877impl_as_primitive!(i32 => { f32, f64 });
878impl_as_primitive!(u64 => { f32, f64 });
879impl_as_primitive!(i64 => { f32, f64 });
880impl_as_primitive!(u128 => { f32, f64 });
881impl_as_primitive!(i128 => { f32, f64 });
882impl_as_primitive!(usize => { f32, f64 });
883impl_as_primitive!(isize => { f32, f64 });
884impl_as_primitive!(f32 => { f32, f64 });
885impl_as_primitive!(f64 => { f32, f64 });
886impl_as_primitive!(char => { char });
887impl_as_primitive!(bool => {});
888
889/// Implements [`ToPrimitive`] from just a `to_i64` and a `to_u64`
890/// conversion, deriving the other twelve methods the way the original
891/// num-traits default methods did.
892///
893/// Lets a downstream type override only `to_i64`/`to_u64` and derive the rest,
894/// the "minimal impl" pattern. The generated impl is a plain (non-const) impl
895/// of the const trait — exactly what a stable downstream crate gets anyway.
896///
897/// Caveats inherited from the upstream defaults: `to_i128`/`to_u128` route
898/// through the 64-bit methods (types with real 128-bit range should
899/// implement `ToPrimitive` by hand), and `to_f64` is exact only for values
900/// representable in 64 bits.
901///
902/// ```
903/// use const_num_traits::ToPrimitive;
904///
905/// struct MyInt(i32);
906///
907/// const_num_traits::impl_to_primitive_minimal! {
908///     impl ToPrimitive for MyInt {
909///         to_i64 = |s: &MyInt| Some(s.0 as i64),
910///         to_u64 = |s: &MyInt| if s.0 >= 0 { Some(s.0 as u64) } else { None },
911///     }
912/// }
913///
914/// assert_eq!(MyInt(-5).to_i8(), Some(-5i8));
915/// assert_eq!(MyInt(-5).to_u32(), None);
916/// assert_eq!(MyInt(300).to_u8(), None);
917/// assert_eq!(MyInt(300).to_f64(), Some(300.0));
918/// ```
919#[macro_export]
920macro_rules! impl_to_primitive_minimal {
921    (impl ToPrimitive for $t:ty {
922        to_i64 = $to_i64:expr,
923        to_u64 = $to_u64:expr $(,)?
924    }) => {
925        impl $crate::ToPrimitive for $t {
926            #[inline]
927            fn to_i64(&self) -> Option<i64> {
928                ($to_i64)(self)
929            }
930
931            #[inline]
932            fn to_u64(&self) -> Option<u64> {
933                ($to_u64)(self)
934            }
935
936            #[inline]
937            fn to_isize(&self) -> Option<isize> {
938                self.to_i64()
939                    .and_then(|v| $crate::CheckedCast::<isize>::checked_cast(v))
940            }
941
942            #[inline]
943            fn to_i8(&self) -> Option<i8> {
944                self.to_i64()
945                    .and_then(|v| $crate::CheckedCast::<i8>::checked_cast(v))
946            }
947
948            #[inline]
949            fn to_i16(&self) -> Option<i16> {
950                self.to_i64()
951                    .and_then(|v| $crate::CheckedCast::<i16>::checked_cast(v))
952            }
953
954            #[inline]
955            fn to_i32(&self) -> Option<i32> {
956                self.to_i64()
957                    .and_then(|v| $crate::CheckedCast::<i32>::checked_cast(v))
958            }
959
960            #[inline]
961            fn to_i128(&self) -> Option<i128> {
962                match self.to_i64() {
963                    Some(i) => Some(i128::from(i)),
964                    None => self.to_u64().map(i128::from),
965                }
966            }
967
968            #[inline]
969            fn to_usize(&self) -> Option<usize> {
970                self.to_u64()
971                    .and_then(|v| $crate::CheckedCast::<usize>::checked_cast(v))
972            }
973
974            #[inline]
975            fn to_u8(&self) -> Option<u8> {
976                self.to_u64()
977                    .and_then(|v| $crate::CheckedCast::<u8>::checked_cast(v))
978            }
979
980            #[inline]
981            fn to_u16(&self) -> Option<u16> {
982                self.to_u64()
983                    .and_then(|v| $crate::CheckedCast::<u16>::checked_cast(v))
984            }
985
986            #[inline]
987            fn to_u32(&self) -> Option<u32> {
988                self.to_u64()
989                    .and_then(|v| $crate::CheckedCast::<u32>::checked_cast(v))
990            }
991
992            #[inline]
993            fn to_u128(&self) -> Option<u128> {
994                self.to_u64().map(u128::from)
995            }
996
997            #[inline]
998            fn to_f32(&self) -> Option<f32> {
999                // Overflow saturates to ±inf (an admitted conversion); `None`
1000                // only when `to_f64` is.
1001                self.to_f64().map(|v| v as f32)
1002            }
1003
1004            #[inline]
1005            fn to_f64(&self) -> Option<f64> {
1006                match self.to_i64() {
1007                    Some(i) => Some(i as f64),
1008                    None => self.to_u64().map(|u| u as f64),
1009                }
1010            }
1011        }
1012    };
1013}
1014
1015/// Implements [`FromPrimitive`] from just a `from_i64` and a `from_u64`
1016/// conversion, deriving the other twelve methods the way the original
1017/// num-traits default methods did.
1018///
1019/// See [`impl_to_primitive_minimal!`] for why this exists and the caveats
1020/// (`from_i128`/`from_u128` route through 64 bits; the generated impl is a
1021/// plain, non-const impl of the const trait).
1022///
1023/// ```
1024/// use const_num_traits::FromPrimitive;
1025///
1026/// #[derive(Debug, PartialEq)]
1027/// struct MyInt(i32);
1028///
1029/// const_num_traits::impl_from_primitive_minimal! {
1030///     impl FromPrimitive for MyInt {
1031///         from_i64 = |n: i64| i32::try_from(n).ok().map(MyInt),
1032///         from_u64 = |n: u64| i32::try_from(n).ok().map(MyInt),
1033///     }
1034/// }
1035///
1036/// assert_eq!(MyInt::from_i8(-5), Some(MyInt(-5)));
1037/// assert_eq!(MyInt::from_u64(u64::MAX), None);
1038/// assert_eq!(MyInt::from_f64(300.7), Some(MyInt(300)));
1039/// ```
1040#[macro_export]
1041macro_rules! impl_from_primitive_minimal {
1042    (impl FromPrimitive for $t:ty {
1043        from_i64 = $from_i64:expr,
1044        from_u64 = $from_u64:expr $(,)?
1045    }) => {
1046        impl $crate::FromPrimitive for $t {
1047            #[inline]
1048            fn from_i64(n: i64) -> Option<Self> {
1049                ($from_i64)(n)
1050            }
1051
1052            #[inline]
1053            fn from_u64(n: u64) -> Option<Self> {
1054                ($from_u64)(n)
1055            }
1056
1057            #[inline]
1058            fn from_isize(n: isize) -> Option<Self> {
1059                Self::from_i64(n as i64)
1060            }
1061
1062            #[inline]
1063            fn from_i8(n: i8) -> Option<Self> {
1064                Self::from_i64(i64::from(n))
1065            }
1066
1067            #[inline]
1068            fn from_i16(n: i16) -> Option<Self> {
1069                Self::from_i64(i64::from(n))
1070            }
1071
1072            #[inline]
1073            fn from_i32(n: i32) -> Option<Self> {
1074                Self::from_i64(i64::from(n))
1075            }
1076
1077            #[inline]
1078            fn from_i128(n: i128) -> Option<Self> {
1079                if n >= 0 {
1080                    u64::try_from(n).ok().and_then(Self::from_u64)
1081                } else {
1082                    i64::try_from(n).ok().and_then(Self::from_i64)
1083                }
1084            }
1085
1086            #[inline]
1087            fn from_usize(n: usize) -> Option<Self> {
1088                Self::from_u64(n as u64)
1089            }
1090
1091            #[inline]
1092            fn from_u8(n: u8) -> Option<Self> {
1093                Self::from_u64(u64::from(n))
1094            }
1095
1096            #[inline]
1097            fn from_u16(n: u16) -> Option<Self> {
1098                Self::from_u64(u64::from(n))
1099            }
1100
1101            #[inline]
1102            fn from_u32(n: u32) -> Option<Self> {
1103                Self::from_u64(u64::from(n))
1104            }
1105
1106            #[inline]
1107            fn from_u128(n: u128) -> Option<Self> {
1108                u64::try_from(n).ok().and_then(Self::from_u64)
1109            }
1110
1111            #[inline]
1112            fn from_f32(n: f32) -> Option<Self> {
1113                Self::from_f64(f64::from(n))
1114            }
1115
1116            #[inline]
1117            fn from_f64(n: f64) -> Option<Self> {
1118                match $crate::ToPrimitive::to_i64(&n) {
1119                    Some(i) => Self::from_i64(i),
1120                    None => $crate::ToPrimitive::to_u64(&n).and_then(Self::from_u64),
1121                }
1122            }
1123        }
1124    };
1125}
1126
1127#[cfg(test)]
1128mod default_tests {
1129    use crate::{FromPrimitive, ToPrimitive};
1130
1131    // The "minimal impl" pattern (override only the i64/u64 fundamentals,
1132    // inherit the other 12 via the restored defaults) — float8's shape.
1133    #[derive(Debug, PartialEq)]
1134    struct N(i32);
1135
1136    impl ToPrimitive for N {
1137        fn to_i64(&self) -> Option<i64> {
1138            Some(self.0 as i64)
1139        }
1140        fn to_u64(&self) -> Option<u64> {
1141            if self.0 >= 0 {
1142                Some(self.0 as u64)
1143            } else {
1144                None
1145            }
1146        }
1147    }
1148    impl FromPrimitive for N {
1149        fn from_i64(n: i64) -> Option<Self> {
1150            if n >= i32::MIN as i64 && n <= i32::MAX as i64 {
1151                Some(N(n as i32))
1152            } else {
1153                None
1154            }
1155        }
1156        fn from_u64(n: u64) -> Option<Self> {
1157            if n <= i32::MAX as u64 {
1158                Some(N(n as i32))
1159            } else {
1160                None
1161            }
1162        }
1163    }
1164
1165    #[test]
1166    fn minimal_impl_inherits_defaults() {
1167        // derived to_* defaults
1168        assert_eq!(N(-5).to_i8(), Some(-5i8));
1169        assert_eq!(N(-5).to_u32(), None);
1170        assert_eq!(N(300).to_u8(), None);
1171        assert_eq!(N(300).to_i128(), Some(300i128));
1172        assert_eq!(N(300).to_f64(), Some(300.0));
1173        assert_eq!(N(300).to_f32(), Some(300.0));
1174        // derived from_* defaults
1175        assert_eq!(N::from_i8(-5), Some(N(-5)));
1176        assert_eq!(N::from_u128(u128::MAX), None);
1177        assert_eq!(N::from_i128(-7), Some(N(-7)));
1178        assert_eq!(N::from_f64(300.7), Some(N(300)));
1179        assert_eq!(N::from_f32(42.0), Some(N(42)));
1180    }
1181
1182    // A `u64`-backed minimal type, to exercise the `(i64::MAX, u64::MAX]` range
1183    // that `N` (i32-backed) can't reach. Manual impl inherits the trait defaults.
1184    #[derive(Debug, PartialEq)]
1185    struct U(u64);
1186    impl ToPrimitive for U {
1187        fn to_i64(&self) -> Option<i64> {
1188            if self.0 <= i64::MAX as u64 {
1189                Some(self.0 as i64)
1190            } else {
1191                None
1192            }
1193        }
1194        fn to_u64(&self) -> Option<u64> {
1195            Some(self.0)
1196        }
1197    }
1198    impl FromPrimitive for U {
1199        fn from_i64(n: i64) -> Option<Self> {
1200            if n >= 0 { Some(U(n as u64)) } else { None }
1201        }
1202        fn from_u64(n: u64) -> Option<Self> {
1203            Some(U(n))
1204        }
1205    }
1206
1207    // Same shape, but generated by the minimal *macros* (covers their i128 paths).
1208    #[derive(Debug, PartialEq)]
1209    struct UM(u64);
1210    crate::impl_to_primitive_minimal! {
1211        impl ToPrimitive for UM {
1212            to_i64 = |s: &UM| if s.0 <= i64::MAX as u64 { Some(s.0 as i64) } else { None },
1213            to_u64 = |s: &UM| Some(s.0),
1214        }
1215    }
1216    crate::impl_from_primitive_minimal! {
1217        impl FromPrimitive for UM {
1218            from_i64 = |n: i64| if n >= 0 { Some(UM(n as u64)) } else { None },
1219            from_u64 = |n: u64| Some(UM(n)),
1220        }
1221    }
1222
1223    #[test]
1224    fn i128_conversions_cover_high_u64_range() {
1225        let big = 1u64 << 63; // > i64::MAX, but fits u64 and i128 exactly
1226        let big_i = big as i128;
1227
1228        // trait defaults (U): to_i128 falls back to to_u64; from_i128 routes
1229        // non-negative through from_u64.
1230        assert_eq!(U(big).to_i128(), Some(big_i));
1231        assert_eq!(U::from_i128(big_i), Some(U(big)));
1232        // minimal macros (UM): same paths
1233        assert_eq!(UM(big).to_i128(), Some(big_i));
1234        assert_eq!(UM::from_i128(big_i), Some(UM(big)));
1235
1236        // ordinary ranges and rejections still hold
1237        assert_eq!(U(5).to_i128(), Some(5));
1238        assert_eq!(U::from_i128(-1), None); // unsigned-backed
1239        assert_eq!(UM::from_i128(u64::MAX as i128 + 1), None); // exceeds u64
1240    }
1241
1242    // A type whose `to_f64` overflows the `f32` range, to check the inherited
1243    // `to_f32` default saturates rather than returning `None`.
1244    #[derive(Debug, PartialEq)]
1245    struct HugeF;
1246    impl ToPrimitive for HugeF {
1247        fn to_i64(&self) -> Option<i64> {
1248            None
1249        }
1250        fn to_u64(&self) -> Option<u64> {
1251            None
1252        }
1253        fn to_f64(&self) -> Option<f64> {
1254            Some(f64::MAX)
1255        }
1256    }
1257
1258    #[test]
1259    fn default_to_f32_saturates_overflow() {
1260        // f64::MAX exceeds f32 range; the inherited default must saturate to
1261        // +inf (an admitted conversion), not return None.
1262        assert_eq!(HugeF.to_f32(), Some(f32::INFINITY));
1263    }
1264}