Skip to main content

qrcode_core/
cast.rs

1//! Checked narrowing conversions and truncation helpers used across the encoder.
2
3/// Truncate a value to u8 by masking the lower 8 bits.
4pub trait Truncate {
5    /// Truncates this value to its low 8 bits as a `u8`.
6    fn truncate_as_u8(self) -> u8;
7}
8
9impl Truncate for u16 {
10    #[allow(clippy::cast_possible_truncation)]
11    fn truncate_as_u8(self) -> u8 {
12        (self & 0xff) as u8
13    }
14}
15
16/// Checked narrowing conversions with debug-mode overflow assertions.
17///
18/// In debug builds, these use `TryFrom` + `unwrap()` to catch overflow bugs.
19/// In release builds, they compile to plain `as` casts (zero cost).
20///
21/// Standard traits can't replace this: `From` only supports lossless widening,
22/// `TryFrom` returns `Result` which would require changing all call sites.
23#[allow(clippy::wrong_self_convention)]
24pub trait As {
25    /// Narrows to `u16` (panics on overflow in debug, `as` in release).
26    fn as_u16(self) -> u16;
27    /// Narrows to `i16` (panics on overflow in debug, `as` in release).
28    fn as_i16(self) -> i16;
29    /// Widens/narrows to `u32` (panics on overflow in debug, `as` in release).
30    fn as_u32(self) -> u32;
31    /// Widens/narrows to `usize` (panics on overflow in debug, `as` in release).
32    fn as_usize(self) -> usize;
33    /// Widens/narrows to `isize` (panics on overflow in debug, `as` in release).
34    fn as_isize(self) -> isize;
35}
36
37macro_rules! impl_as {
38    ($ty:ty) => {
39        #[cfg(debug_assertions)]
40        impl As for $ty {
41            fn as_u16(self) -> u16 {
42                u16::try_from(self).unwrap()
43            }
44
45            fn as_i16(self) -> i16 {
46                i16::try_from(self).unwrap()
47            }
48
49            fn as_u32(self) -> u32 {
50                u32::try_from(self).unwrap()
51            }
52
53            fn as_usize(self) -> usize {
54                usize::try_from(self).unwrap()
55            }
56
57            fn as_isize(self) -> isize {
58                isize::try_from(self).unwrap()
59            }
60        }
61
62        #[cfg(not(debug_assertions))]
63        impl As for $ty {
64            fn as_u16(self) -> u16 {
65                self as u16
66            }
67            fn as_i16(self) -> i16 {
68                self as i16
69            }
70            fn as_u32(self) -> u32 {
71                self as u32
72            }
73            fn as_usize(self) -> usize {
74                self as usize
75            }
76            fn as_isize(self) -> isize {
77                self as isize
78            }
79        }
80    };
81}
82
83impl_as!(i16);
84impl_as!(u32);
85impl_as!(usize);
86impl_as!(isize);