1#![allow(clippy::use_self)]
2
3#[cfg(not(any(
4 target_pointer_width = "16",
5 target_pointer_width = "32",
6 target_pointer_width = "64",
7)))]
8compile_error!("unsupported pointer width");
9
10use core::convert::Infallible;
11use core::fmt::{self, Display};
12
13pub fn checked_cast<T, U>(src: T) -> Result<U, T::Error>
14where
15 T: CheckedCast<U>,
16{
17 src.checked_cast()
18}
19
20pub fn wrapping_cast<T, U>(src: T) -> U
21where
22 T: WrappingCast<U>,
23{
24 src.wrapping_cast()
25}
26
27pub fn extending_cast<T, U>(src: T) -> U
28where
29 T: ExtendingCast<U>,
30{
31 src.extending_cast()
32}
33
34pub fn truncating_cast<T, U>(src: T) -> U
35where
36 T: TruncatingCast<U>,
37{
38 src.truncating_cast()
39}
40
41pub trait CheckedCast<T> {
42 type Error;
43 fn checked_cast(self) -> Result<T, Self::Error>;
44}
45
46pub trait WrappingCast<T> {
47 fn wrapping_cast(self) -> T;
48}
49
50pub trait ExtendingCast<T> {
51 fn extending_cast(self) -> T;
52}
53
54pub trait TruncatingCast<T> {
55 fn truncating_cast(self) -> T;
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub enum NumCastError {
60 Overflow,
61 Underflow,
62 Infinite,
63 NaN,
64 Fractional,
65}
66
67impl Display for NumCastError {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 let msg = match *self {
70 Self::Overflow => "Overflow during numeric conversion",
71 Self::Underflow => "Underflow during numeric conversion",
72 Self::Fractional => "Cannot store fractional value without loss",
73 Self::Infinite => "Cannot store infinite value in finite type",
74 Self::NaN => "Cannot store NaN in type which does not support it",
75 };
76
77 f.write_str(msg)
78 }
79}
80
81#[cfg(feature = "std")]
82impl std::error::Error for NumCastError {}
83
84macro_rules! check {
85 (upper $val: expr, $rhs: ty) => {
86 if $val > <$rhs>::MAX as Self {
87 return Err(NumCastError::Overflow);
88 }
89 };
90 (lower $val: expr, $rhs: ty) => {
91 if $val < <$rhs>::MIN as Self {
92 return Err(NumCastError::Underflow);
93 }
94 };
95 (both $val: expr, $rhs: ty) => {
96 check!(upper $val, $rhs);
97 check!(lower $val, $rhs);
98 };
99 (infallible $val: expr, $rhs: ty) => {}
100}
101
102macro_rules! checked_cast{
103 ($lhs:ty => $rhs:ty: upper) => {
104 impl CheckedCast<$rhs> for $lhs {
105 type Error = NumCastError;
106 fn checked_cast(self) -> Result<$rhs, Self::Error> {
107 check!(upper self, $rhs);
108 Ok(self as $rhs)
109 }
110 }
111 };
112 ($lhs:ty => $rhs:ty: lower) => {
113 impl CheckedCast<$rhs> for $lhs {
114 type Error = NumCastError;
115 fn checked_cast(self) -> Result<$rhs, Self::Error> {
116 check!(lower self, $rhs);
117 Ok(self as $rhs)
118 }
119 }
120 };
121 ($lhs:ty => $rhs:ty: both) => {
122 impl CheckedCast<$rhs> for $lhs {
123 type Error = NumCastError;
124 fn checked_cast(self) -> Result<$rhs, Self::Error> {
125 check!(both self, $rhs);
126 Ok(self as $rhs)
127 }
128 }
129 };
130 ($lhs:ty => $rhs:ty: infallible ) => {
131 impl CheckedCast<$rhs> for $lhs {
132 type Error = Infallible;
133 fn checked_cast(self) -> Result<$rhs, Self::Error> {
134 Ok(self as $rhs)
135 }
136 }
137 };
138
139 ($lhs: ty => $rhs: ty: 16:$c16:tt, 32:$c32:tt, 64:$c64:tt) => {
140 impl CheckedCast<$rhs> for $lhs {
141 type Error = NumCastError;
142
143 fn checked_cast(self) -> Result<$rhs, Self::Error> {
144 #[cfg(target_pointer_width = "16")]
145 {
146 check!($c16 self, $rhs);
147 }
148 #[cfg(target_pointer_width = "32")]
149 {
150 check!($c32 self, $rhs);
151 }
152 #[cfg(target_pointer_width = "64")]
153 {
154 check!($c64 self, $rhs);
155 }
156 Ok(self as $rhs)
157 }
158 }
159 };
160 (f32 => $rhs: ty) => {
161 impl CheckedCast<$rhs> for f32 {
162 type Error = NumCastError;
163
164 fn checked_cast(self) -> Result<$rhs, Self::Error> {
165 if self.is_nan() {
166 return Err(NumCastError::NaN);
167 }
168 if self.is_infinite() {
169 return Err(NumCastError::Infinite);
170 }
171 if self.trunc().to_bits() != self.to_bits() {
172 return Err(NumCastError::Fractional);
173 }
174 check!(both self, $rhs);
175 Ok(self as $rhs)
176 }
177 }
178 };
179 (f64 => $rhs: ty) => {
180 impl CheckedCast<$rhs> for f64 {
181 type Error = NumCastError;
182
183 fn checked_cast(self) -> Result<$rhs, Self::Error> {
184 if self.is_nan() {
185 return Err(NumCastError::NaN);
186 }
187 if self.is_infinite() {
188 return Err(NumCastError::Infinite);
189 }
190 if self.trunc().to_bits() != self.to_bits() {
191 return Err(NumCastError::Fractional);
192 }
193 check!(both self, $rhs);
194 Ok(self as $rhs)
195 }
196 }
197 }
198}
199
200checked_cast!(u8 => u8 : infallible );
202checked_cast!(u8 => u16 : infallible );
203checked_cast!(u8 => u32 : infallible );
204checked_cast!(u8 => u64 : infallible );
205checked_cast!(u8 => u128 : infallible );
206checked_cast!(u8 => i8 : upper );
207checked_cast!(u8 => i16 : infallible );
208checked_cast!(u8 => i32 : infallible );
209checked_cast!(u8 => i64 : infallible );
210checked_cast!(u8 => i128 : infallible );
211checked_cast!(u8 => usize : infallible );
212checked_cast!(u8 => isize : infallible );
213checked_cast!(u8 => f32 : infallible );
214checked_cast!(u8 => f64 : infallible );
215
216checked_cast!(u16 => u8 : upper );
218checked_cast!(u16 => u16 : infallible );
219checked_cast!(u16 => u32 : infallible );
220checked_cast!(u16 => u64 : infallible );
221checked_cast!(u16 => u128 : infallible );
222checked_cast!(u16 => i8 : upper );
223checked_cast!(u16 => i16 : upper );
224checked_cast!(u16 => i32 : infallible );
225checked_cast!(u16 => i64 : infallible );
226checked_cast!(u16 => i128 : infallible );
227checked_cast!(u16 => usize : infallible );
228checked_cast!(u16 => isize : 16: upper, 32: infallible, 64: infallible );
229checked_cast!(u16 => f32 : infallible );
230checked_cast!(u16 => f64 : infallible );
231
232checked_cast!(u32 => u8 : upper );
234checked_cast!(u32 => u16 : upper );
235checked_cast!(u32 => u32 : infallible );
236checked_cast!(u32 => u64 : infallible );
237checked_cast!(u32 => u128 : infallible );
238checked_cast!(u32 => i8 : upper );
239checked_cast!(u32 => i16 : upper );
240checked_cast!(u32 => i32 : upper );
241checked_cast!(u32 => i64 : infallible );
242checked_cast!(u32 => i128 : infallible );
243checked_cast!(u32 => usize : 16: upper, 32: infallible, 64: infallible );
244checked_cast!(u32 => isize : 16: upper, 32: upper , 64: infallible );
245
246checked_cast!(u64 => u8 : upper );
248checked_cast!(u64 => u16 : upper );
249checked_cast!(u64 => u32 : upper );
250checked_cast!(u64 => u64 : infallible );
251checked_cast!(u64 => u128 : infallible );
252checked_cast!(u64 => i8 : upper );
253checked_cast!(u64 => i16 : upper );
254checked_cast!(u64 => i32 : upper );
255checked_cast!(u64 => i64 : upper );
256checked_cast!(u64 => i128 : infallible );
257checked_cast!(u64 => usize : 16: upper, 32: upper , 64: infallible );
258checked_cast!(u64 => isize : upper );
259
260checked_cast!(u128 => u8 : upper );
262checked_cast!(u128 => u16 : upper );
263checked_cast!(u128 => u32 : upper );
264checked_cast!(u128 => u64 : upper );
265checked_cast!(u128 => u128 : infallible );
266checked_cast!(u128 => i8 : upper );
267checked_cast!(u128 => i16 : upper );
268checked_cast!(u128 => i32 : upper );
269checked_cast!(u128 => i64 : upper );
270checked_cast!(u128 => i128 : upper );
271checked_cast!(u128 => usize : upper );
272checked_cast!(u128 => isize : upper );
273
274checked_cast!(i8 => u8 : lower );
276checked_cast!(i8 => u16 : lower );
277checked_cast!(i8 => u32 : lower );
278checked_cast!(i8 => u64 : lower );
279checked_cast!(i8 => u128 : lower );
280checked_cast!(i8 => i8 : infallible );
281checked_cast!(i8 => i16 : infallible );
282checked_cast!(i8 => i32 : infallible );
283checked_cast!(i8 => i64 : infallible );
284checked_cast!(i8 => i128 : infallible );
285checked_cast!(i8 => usize : lower );
286checked_cast!(i8 => isize : infallible );
287checked_cast!(i8 => f32 : infallible );
288checked_cast!(i8 => f64 : infallible );
289
290checked_cast!(i16 => u8 : both );
292checked_cast!(i16 => u16 : lower );
293checked_cast!(i16 => u32 : lower );
294checked_cast!(i16 => u64 : lower );
295checked_cast!(i16 => u128 : lower );
296checked_cast!(i16 => i8 : both );
297checked_cast!(i16 => i16 : infallible );
298checked_cast!(i16 => i32 : infallible );
299checked_cast!(i16 => i64 : infallible );
300checked_cast!(i16 => i128 : infallible );
301checked_cast!(i16 => usize : lower );
302checked_cast!(i16 => isize : infallible );
303checked_cast!(i16 => f32 : infallible );
304checked_cast!(i16 => f64 : infallible );
305
306checked_cast!(i32 => u8 : both );
308checked_cast!(i32 => u16 : both );
309checked_cast!(i32 => u32 : lower );
310checked_cast!(i32 => u64 : lower );
311checked_cast!(i32 => u128 : lower );
312checked_cast!(i32 => i8 : both );
313checked_cast!(i32 => i16 : both );
314checked_cast!(i32 => i32 : infallible );
315checked_cast!(i32 => i64 : infallible );
316checked_cast!(i32 => i128 : infallible );
317checked_cast!(i32 => usize : 16: both, 32: lower , 64: lower );
318checked_cast!(i32 => isize : 16: both, 32: infallible , 64: infallible );
319
320checked_cast!(i64 => u8 : both );
322checked_cast!(i64 => u16 : both );
323checked_cast!(i64 => u32 : both );
324checked_cast!(i64 => u64 : lower );
325checked_cast!(i64 => u128 : lower );
326checked_cast!(i64 => i8 : both );
327checked_cast!(i64 => i16 : both );
328checked_cast!(i64 => i32 : both );
329checked_cast!(i64 => i64 : infallible );
330checked_cast!(i64 => i128 : infallible );
331checked_cast!(i64 => usize : 16: both, 32: both , 64: lower );
332checked_cast!(i64 => isize : 16: both, 32: both , 64: infallible );
333
334checked_cast!(i128 => u8 : both );
336checked_cast!(i128 => u16 : both );
337checked_cast!(i128 => u32 : both );
338checked_cast!(i128 => u64 : both );
339checked_cast!(i128 => u128 : lower );
340checked_cast!(i128 => i8 : both );
341checked_cast!(i128 => i16 : both );
342checked_cast!(i128 => i32 : both );
343checked_cast!(i128 => i64 : both );
344checked_cast!(i128 => i128 : infallible );
345checked_cast!(i128 => usize: both );
346checked_cast!(i128 => isize: both );
347
348checked_cast!(usize => u8 : upper );
350checked_cast!(usize => u16 : 16: infallible, 32: upper , 64: upper );
351checked_cast!(usize => u32 : 16: infallible, 32: infallible, 64: upper );
352checked_cast!(usize => u64 : 16: infallible, 32: infallible, 64: infallible );
353checked_cast!(usize => u128 : 16: infallible, 32: infallible, 64: infallible );
354checked_cast!(usize => i8 : upper );
355checked_cast!(usize => i16 : upper );
356checked_cast!(usize => i32 : 16: infallible, 32: upper , 64: upper );
357checked_cast!(usize => i64 : 16: infallible, 32: infallible, 64: upper );
358checked_cast!(usize => i128 : 16: infallible, 32: infallible, 64: infallible );
359checked_cast!(usize => usize: infallible );
360checked_cast!(usize => isize: upper );
361
362checked_cast!(isize => u8 : both );
364checked_cast!(isize => u16 : 16: lower , 32: both , 64: both );
365checked_cast!(isize => u32 : 16: lower , 32: lower , 64: both );
366checked_cast!(isize => u64 : lower );
367checked_cast!(isize => u128 : lower );
368checked_cast!(isize => i8 : both );
369checked_cast!(isize => i16 : 16: infallible, 32: both , 64: both );
370checked_cast!(isize => i32 : 16: infallible, 32: infallible, 64: both );
371checked_cast!(isize => i64 : 16: infallible, 32: infallible, 64: infallible );
372checked_cast!(isize => i128 : 16: infallible, 32: infallible, 64: infallible );
373checked_cast!(isize => usize: lower );
374checked_cast!(isize => isize: infallible );
375
376checked_cast!(f32 => u8);
378checked_cast!(f32 => u16);
379checked_cast!(f32 => i8);
380checked_cast!(f32 => i16);
381checked_cast!(f32 => f32: infallible);
382checked_cast!(f32 => f64: infallible);
383
384checked_cast!(f64 => u8);
386checked_cast!(f64 => u16);
387checked_cast!(f64 => i8);
388checked_cast!(f64 => i16);
389checked_cast!(f64 => f64: infallible);
390
391macro_rules! wrapping_cast {
392 ($lhs: ty=>$rhs:ty) => {
393 impl WrappingCast<$rhs> for $lhs {
394 fn wrapping_cast(self) -> $rhs {
395 self as $rhs
396 }
397 }
398 };
399}
400
401wrapping_cast!(u8 => i8 );
402wrapping_cast!(u16 => i16 );
403wrapping_cast!(u32 => i32 );
404wrapping_cast!(u64 => i64 );
405wrapping_cast!(u128 => i128 );
406wrapping_cast!(usize => isize);
407wrapping_cast!(i8 => u8 );
408wrapping_cast!(i16 => u16 );
409wrapping_cast!(i32 => u32 );
410wrapping_cast!(i64 => u64 );
411wrapping_cast!(i128 => u128 );
412wrapping_cast!(isize => usize);
413
414macro_rules! extending_cast {
415 ($lhs: ty=>$rhs:ty) => {
416 impl ExtendingCast<$rhs> for $lhs {
417 fn extending_cast(self) -> $rhs {
418 self as $rhs
419 }
420 }
421 };
422}
423
424extending_cast!(u8 => u16 );
425extending_cast!(u8 => u32 );
426extending_cast!(u8 => u64 );
427extending_cast!(u8 => u128 );
428extending_cast!(u16 => u32 );
429extending_cast!(u16 => u64 );
430extending_cast!(u16 => u128 );
431extending_cast!(u32 => u64 );
432extending_cast!(u32 => u128 );
433extending_cast!(u64 => u128 );
434extending_cast!(i8 => i16 );
435extending_cast!(i8 => i32 );
436extending_cast!(i8 => i64 );
437extending_cast!(i8 => i128 );
438extending_cast!(i16 => i32 );
439extending_cast!(i16 => i64 );
440extending_cast!(i16 => i128 );
441extending_cast!(i32 => i64 );
442extending_cast!(i32 => i128 );
443extending_cast!(i64 => i128 );
444
445macro_rules! truncating_cast {
446 ($lhs: ty=>$rhs:ty) => {
447 impl TruncatingCast<$rhs> for $lhs {
448 fn truncating_cast(self) -> $rhs {
449 self as $rhs
450 }
451 }
452 };
453}
454
455truncating_cast!(u16 => u8 );
456truncating_cast!(u32 => u8 );
457truncating_cast!(u64 => u8 );
458truncating_cast!(u128 => u8 );
459truncating_cast!(u32 => u16 );
460truncating_cast!(u64 => u16 );
461truncating_cast!(u128 => u16 );
462truncating_cast!(u64 => u32 );
463truncating_cast!(u128 => u32 );
464truncating_cast!(u128 => u64 );
465truncating_cast!(i16 => i8 );
466truncating_cast!(i32 => i8 );
467truncating_cast!(i64 => i8 );
468truncating_cast!(i128 => i8 );
469truncating_cast!(i32 => i16 );
470truncating_cast!(i64 => i16 );
471truncating_cast!(i128 => i16 );
472truncating_cast!(i64 => i32 );
473truncating_cast!(i128 => i32 );
474truncating_cast!(i128 => i64 );