1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! Panic-free casting between numeric types.

/// Backend implementation trait for panic-free casting between numeric types.

#[cfg_attr(feature = "nightly", const_trait)]
pub trait CastFrom<T> {
    fn cast_from(from: T) -> Self;
}

#[cfg_attr(feature = "nightly", const_trait)]
pub(crate) trait CastTo<U> {
    fn cast_to(self) -> U;
}

macro_rules! as_trait_doc {
	() => {
"Trait which allows panic-free casting between numeric types.

The 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."
	};
}

macro_rules! as_method_doc {
	() => {
"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.

# Examples
 
```
use bnum::types::{U256, I512, I256, U1024};
use bnum::cast::As;
 
// Cast `u64` to `U256`:
let a = 399872465243u64;
let b: U256 = a.as_();
assert_eq!(a.as_::<u16>(), b.as_());

// Cast `i128` to `I512`:
let c = -2098409234529234584094i128;
let d = c.as_::<I512>();
//assert_eq!(c.as::<I256>(), d.as_());

// Cast `I512` to `U1024` (result will be sign-extended with leading ones):
let e: U1024 = d.as_();
assert_eq!(d, e.as_());

// Cast `U256` to `f64` and back:
let f: f64 = b.as_();
assert_eq!(b, f.as_());
```"
	};
}

#[cfg(feature = "nightly")]
macro_rules! as_trait {
    () => {
        impl<T, U> const CastTo<U> for T
        where
            U: ~const CastFrom<T>,
        {
            fn cast_to(self) -> U {
                U::cast_from(self)
            }
        }

        #[doc = as_trait_doc!()]
		#[const_trait]
        pub trait As {
            #[doc = as_method_doc!()]
            fn as_<T>(self) -> T
            where
                T: CastFrom<Self>,
                Self: Sized;
        }

        impl<U> const As for U {
            #[inline]
            fn as_<T>(self) -> T
            where
                T: ~const CastFrom<Self>,
                Self: Sized,
            {
                T::cast_from(self)
            }
        }
    };
}

#[cfg(not(feature = "nightly"))]
macro_rules! as_trait {
    () => {
        impl<T, U> CastTo<U> for T
        where
            U: CastFrom<T>,
        {
            fn cast_to(self) -> U {
                U::cast_from(self)
            }
        }

        #[doc = as_trait_doc!()]
        pub trait As {
            #[doc = as_method_doc!()]
            fn as_<T>(self) -> T
            where
                T: CastFrom<Self>,
                Self: Sized;
        }

        impl<U> As for U {
            #[inline]
            fn as_<T>(self) -> T
            where
                T: CastFrom<Self>,
                Self: Sized,
            {
                T::cast_from(self)
            }
        }
    };
}

as_trait!();

macro_rules! primitive_cast_impl {
    ($from: ty as [$($ty: ty), *]) => {
        $(crate::nightly::impl_const! {
            impl const CastFrom<$from> for $ty {
                #[inline]
                fn cast_from(from: $from) -> Self {
                    from as Self
                }
            }
		})*
    };
}

macro_rules! multiple_impls {
    ($($from: ty), *) => {
        $(
            primitive_cast_impl!($from as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64]);
        )*
    };
}

primitive_cast_impl!(bool as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, bool]);
primitive_cast_impl!(char as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, char]);
primitive_cast_impl!(u8 as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, char]);
multiple_impls!(u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64);