reweb3_num/
cast.rs

1//! Panic-free casting between numeric types.
2
3/// Backend implementation trait for panic-free casting between numeric types.
4
5pub trait CastFrom<T> {
6    fn cast_from(from: T) -> Self;
7}
8
9pub trait CastTo<U> {
10    fn cast_to(self) -> U;
11}
12
13macro_rules! as_trait_doc {
14    () => {
15"Trait which allows panic-free casting between numeric types.
16
17The behavior matches the behavior of the `as` conversion operator between primitive integers. This trait can be used to convert between bnum's integer types, as well as between bnum's integer types and Rust's primitive integers. Conversions between Rust's primitive integers themselves are also defined for consistency."
18    };
19}
20
21macro_rules! as_method_doc {
22    () => {
23"Casts `self` to type `T`. The [semantics of numeric casting](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics) with the `as` operator are followed, so `<T as As>::as_::<U>` can be used in the same way as `T as U` for numeric conversions.
24
25# Examples
26 
27```
28use reweb3_num::types::{U256, I512, I256, U1024};
29use reweb3_num::cast::As;
30 
31// Cast `u64` to `U256`:
32let a = 399872465243u64;
33let b: U256 = a.as_();
34assert_eq!(a.as_::<u16>(), b.as_());
35
36// Cast `i128` to `I512`:
37let c = -2098409234529234584094i128;
38let d = c.as_::<I512>();
39//assert_eq!(c.as::<I256>(), d.as_());
40
41// Cast `I512` to `U1024` (result will be sign-extended with leading ones):
42let e: U1024 = d.as_();
43assert_eq!(d, e.as_());
44
45// Cast `U256` to `f64` and back:
46let f: f64 = b.as_();
47assert_eq!(b, f.as_());
48```"
49    };
50}
51
52macro_rules! as_trait {
53    () => {
54        impl<T, U> CastTo<U> for T
55        where
56            U: CastFrom<T>,
57        {
58            fn cast_to(self) -> U {
59                U::cast_from(self)
60            }
61        }
62
63        #[doc = as_trait_doc!()]
64        pub trait As {
65            #[doc = as_method_doc!()]
66            fn as_<T>(self) -> T
67            where
68                T: CastFrom<Self>,
69                Self: Sized;
70        }
71
72        impl<U> As for U {
73            #[inline]
74            fn as_<T>(self) -> T
75            where
76                T: CastFrom<Self>,
77                Self: Sized,
78            {
79                T::cast_from(self)
80            }
81        }
82    };
83}
84
85as_trait!();
86
87macro_rules! primitive_cast_impl {
88    ($from: ty as [$($ty: ty), *]) => {
89        $(crate::nightly::const_impl! {
90            impl const CastFrom<$from> for $ty {
91                #[inline]
92                fn cast_from(from: $from) -> Self {
93                    from as Self
94                }
95            }
96        })*
97    };
98}
99
100macro_rules! multiple_impls {
101    ($($from: ty), *) => {
102        $(
103            primitive_cast_impl!($from as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64]);
104        )*
105    };
106}
107
108primitive_cast_impl!(bool as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, bool]);
109primitive_cast_impl!(char as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, char]);
110primitive_cast_impl!(u8 as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, char]);
111multiple_impls!(u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64);