1use super::*;
11use core::mem::size_of;
12
13macro_rules! impl_via_as_neg_check {
14 ($x:ty: $y:ty) => {
15 impl Conv<$x> for $y {
16 #[inline]
17 fn conv(x: $x) -> $y {
18 #[cfg(any(debug_assertions, feature = "assert_int"))]
19 assert!(
20 x >= 0,
21 "cast x: {} to {}: expected x >= 0, found x = {}",
22 stringify!($x), stringify!($y), x
23 );
24 x as $y
25 }
26 #[inline]
27 fn try_conv(x: $x) -> Result<Self> {
28 if x >= 0 {
29 Ok(x as $y)
30 } else {
31 Err(Error::Range)
32 }
33 }
34 }
35 };
36 ($x:ty: $y:ty, $($yy:ty),+) => {
37 impl_via_as_neg_check!($x: $y);
38 impl_via_as_neg_check!($x: $($yy),+);
39 };
40}
41
42impl_via_as_neg_check!(i8: u8, u16, u32, u64, u128);
43impl_via_as_neg_check!(i16: u16, u32, u64, u128);
44impl_via_as_neg_check!(i32: u32, u64, u128);
45impl_via_as_neg_check!(i64: u64, u128);
46impl_via_as_neg_check!(i128: u128);
47
48macro_rules! impl_via_as_max_check {
50 ($x:ty: $y:tt) => {
51 impl Conv<$x> for $y {
52 #[inline]
53 fn conv(x: $x) -> $y {
54 #[cfg(any(debug_assertions, feature = "assert_int"))]
55 assert!(
56 x <= $y::MAX as $x,
57 "cast x: {} to {}: expected x <= {}, found x = {}",
58 stringify!($x), stringify!($y), $y::MAX, x
59 );
60 x as $y
61 }
62 #[inline]
63 fn try_conv(x: $x) -> Result<Self> {
64 if x <= $y::MAX as $x {
65 Ok(x as $y)
66 } else {
67 Err(Error::Range)
68 }
69 }
70 }
71 };
72 ($x:ty: $y:tt, $($yy:tt),+) => {
73 impl_via_as_max_check!($x: $y);
74 impl_via_as_max_check!($x: $($yy),+);
75 };
76}
77
78impl_via_as_max_check!(u8: i8);
79impl_via_as_max_check!(u16: i8, i16, u8);
80impl_via_as_max_check!(u32: i8, i16, i32, u8, u16);
81impl_via_as_max_check!(u64: i8, i16, i32, i64, u8, u16, u32);
82impl_via_as_max_check!(u128: i8, i16, i32, i64, i128);
83impl_via_as_max_check!(u128: u8, u16, u32, u64);
84
85macro_rules! impl_via_as_range_check {
87 ($x:ty: $y:tt) => {
88 impl Conv<$x> for $y {
89 #[inline]
90 fn conv(x: $x) -> $y {
91 #[cfg(any(debug_assertions, feature = "assert_int"))]
92 assert!(
93 $y::MIN as $x <= x && x <= $y::MAX as $x,
94 "cast x: {} to {}: expected {} <= x <= {}, found x = {}",
95 stringify!($x), stringify!($y), $y::MIN, $y::MAX, x
96 );
97 x as $y
98 }
99 #[inline]
100 fn try_conv(x: $x) -> Result<Self> {
101 if $y::MIN as $x <= x && x <= $y::MAX as $x {
102 Ok(x as $y)
103 } else {
104 Err(Error::Range)
105 }
106 }
107 }
108 };
109 ($x:ty: $y:tt, $($yy:tt),+) => {
110 impl_via_as_range_check!($x: $y);
111 impl_via_as_range_check!($x: $($yy),+);
112 };
113}
114
115impl_via_as_range_check!(i16: i8, u8);
116impl_via_as_range_check!(i32: i8, i16, u8, u16);
117impl_via_as_range_check!(i64: i8, i16, i32, u8, u16, u32);
118impl_via_as_range_check!(i128: i8, i16, i32, i64, u8, u16, u32, u64);
119
120macro_rules! impl_int_generic {
121 ($x:tt: $y:tt) => {
122 impl Conv<$x> for $y {
123 #[allow(unused_comparisons)]
124 #[inline]
125 fn conv(x: $x) -> $y {
126 let src_is_signed = $x::MIN != 0;
127 let dst_is_signed = $y::MIN != 0;
128 if size_of::<$x>() < size_of::<$y>() {
129 if !dst_is_signed {
130 #[cfg(any(debug_assertions, feature = "assert_int"))]
131 assert!(
132 x >= 0,
133 "cast x: {} to {}: expected x >= 0, found x = {}",
134 stringify!($x), stringify!($y), x
135 );
136 }
137 } else if size_of::<$x>() == size_of::<$y>() {
138 if dst_is_signed {
139 #[cfg(any(debug_assertions, feature = "assert_int"))]
140 assert!(
141 x <= $y::MAX as $x,
142 "cast x: {} to {}: expected x <= {}, found x = {}",
143 stringify!($x), stringify!($y), $y::MAX, x
144 );
145 } else if src_is_signed {
146 #[cfg(any(debug_assertions, feature = "assert_int"))]
147 assert!(
148 x >= 0,
149 "cast x: {} to {}: expected x >= 0, found x = {}",
150 stringify!($x), stringify!($y), x
151 );
152 }
153 } else {
154 if src_is_signed {
156 #[cfg(any(debug_assertions, feature = "assert_int"))]
157 assert!(
158 $y::MIN as $x <= x && x <= $y::MAX as $x,
159 "cast x: {} to {}: expected {} <= x <= {}, found x = {}",
160 stringify!($x), stringify!($y), $y::MIN, $y::MAX, x
161 );
162 } else {
163 #[cfg(any(debug_assertions, feature = "assert_int"))]
164 assert!(
165 x <= $y::MAX as $x,
166 "cast x: {} to {}: expected x <= {}, found x = {}",
167 stringify!($x), stringify!($y), $y::MAX, x
168 );
169 }
170 }
171 x as $y
172 }
173 #[allow(unused_comparisons)]
174 #[inline]
175 fn try_conv(x: $x) -> Result<Self> {
176 let src_is_signed = $x::MIN != 0;
177 let dst_is_signed = $y::MIN != 0;
178 if size_of::<$x>() < size_of::<$y>() {
179 if dst_is_signed || x >= 0 {
180 return Ok(x as $y);
181 }
182 } else if size_of::<$x>() == size_of::<$y>() {
183 if dst_is_signed {
184 if x <= $y::MAX as $x {
185 return Ok(x as $y);
186 }
187 } else if src_is_signed {
188 if x >= 0 {
189 return Ok(x as $y);
190 }
191 } else {
192 return Ok(x as $y);
194 }
195 } else {
196 if src_is_signed {
198 if $y::MIN as $x <= x && x <= $y::MAX as $x {
199 return Ok(x as $y);
200 }
201 } else {
202 if x <= $y::MAX as $x {
203 return Ok(x as $y);
204 }
205 }
206 }
207 Err(Error::Range)
208 }
209 }
210 };
211 ($x:tt: $y:tt, $($yy:tt),+) => {
212 impl_int_generic!($x: $y);
213 impl_int_generic!($x: $($yy),+);
214 };
215}
216
217impl_int_generic!(i8: isize, usize);
218impl_int_generic!(i16: isize, usize);
219impl_int_generic!(i32: isize, usize);
220impl_int_generic!(i64: isize, usize);
221impl_int_generic!(i128: isize, usize);
222impl_int_generic!(u8: isize, usize);
223impl_int_generic!(u16: isize, usize);
224impl_int_generic!(u32: isize, usize);
225impl_int_generic!(u64: isize, usize);
226impl_int_generic!(u128: isize, usize);
227impl_int_generic!(isize: i8, i16, i32, i64, i128);
228impl_int_generic!(usize: i8, i16, i32, i64, i128, isize);
229impl_int_generic!(isize: u8, u16, u32, u64, u128, usize);
230impl_int_generic!(usize: u8, u16, u32, u64, u128);
231
232macro_rules! impl_via_digits_check {
233 ($x:ty: $y:tt) => {
234 impl Conv<$x> for $y {
235 #[inline]
236 fn conv(x: $x) -> Self {
237 if cfg!(any(debug_assertions, feature = "assert_digits")) {
238 Self::try_conv(x).unwrap_or_else(|_| {
239 panic!(
240 "cast x: {} to {}: inexact for x = {}",
241 stringify!($x), stringify!($y), x
242 )
243 })
244 } else {
245 x as $y
246 }
247 }
248 #[inline]
249 fn try_conv(x: $x) -> Result<Self> {
250 let src_ty_bits = (size_of::<$x>() * 8) as u32;
251 let src_digits = src_ty_bits.saturating_sub(x.leading_zeros() + x.trailing_zeros());
252 let dst_digits = $y::MANTISSA_DIGITS;
253 if src_digits <= dst_digits {
254 Ok(x as $y)
255 } else {
256 Err(Error::Inexact)
257 }
258 }
259 }
260 };
261 ($x:ty: $y:tt, $($yy:tt),+) => {
262 impl_via_digits_check!($x: $y);
263 impl_via_digits_check!($x: $($yy),+);
264 };
265}
266
267macro_rules! impl_via_digits_check_signed {
268 ($x:ty: $y:tt) => {
269 impl Conv<$x> for $y {
270 #[inline]
271 fn conv(x: $x) -> Self {
272 if cfg!(any(debug_assertions, feature = "assert_digits")) {
273 Self::try_conv(x).unwrap_or_else(|_| {
274 panic!(
275 "cast x: {} to {}: inexact for x = {}",
276 stringify!($x), stringify!($y), x
277 )
278 })
279 } else {
280 x as $y
281 }
282 }
283 #[inline]
284 fn try_conv(x: $x) -> Result<Self> {
285 let src_ty_bits = (size_of::<$x>() * 8) as u32;
286 let src_digits = x.checked_abs()
287 .map(|y| src_ty_bits.saturating_sub(y.leading_zeros() + y.trailing_zeros()))
288 .unwrap_or(1 );
289 let dst_digits = $y::MANTISSA_DIGITS;
290 if src_digits <= dst_digits {
291 Ok(x as $y)
292 } else {
293 Err(Error::Inexact)
294 }
295 }
296 }
297 };
298 ($x:ty: $y:tt, $($yy:tt),+) => {
299 impl_via_digits_check_signed!($x: $y);
300 impl_via_digits_check_signed!($x: $($yy),+);
301 };
302}
303
304impl_via_digits_check!(u32: f32);
305impl_via_digits_check!(u64: f32, f64);
306impl_via_digits_check!(u128: f32, f64);
307impl_via_digits_check!(usize: f32, f64);
308
309impl_via_digits_check_signed!(i32: f32);
310impl_via_digits_check_signed!(i64: f32, f64);
311impl_via_digits_check_signed!(i128: f32, f64);
312impl_via_digits_check_signed!(isize: f32, f64);