polkavm_common/
cast.rs

1//! This module defines an explicit casting facility to replace Rust's built-in `as` casts.
2//! The general idea is:
3//!   * Casts should be usable everywhere, including in `const fn`s (which means we can't use traits).
4//!   * Casts should fail to compile if a) the source or the target type changes, and b) the cast between the new pair of types would now be incorrect.
5//!   * `usize` is assumed to be always at least 32-bit.
6
7#[allow(non_camel_case_types)]
8#[repr(transparent)]
9pub struct cast<T>(pub T);
10
11impl cast<i8> {
12    #[inline(always)]
13    pub const fn to_unsigned(self) -> u8 {
14        self.0 as u8
15    }
16
17    #[inline(always)]
18    pub const fn to_i32_sign_extend(self) -> i32 {
19        self.0 as i32
20    }
21
22    #[inline(always)]
23    pub const fn to_i64_sign_extend(self) -> i64 {
24        self.0 as i64
25    }
26}
27
28impl cast<i16> {
29    #[inline(always)]
30    pub const fn to_unsigned(self) -> u16 {
31        self.0 as u16
32    }
33
34    #[inline(always)]
35    pub const fn to_i32_sign_extend(self) -> i32 {
36        self.0 as i32
37    }
38
39    #[inline(always)]
40    pub const fn to_i64_sign_extend(self) -> i64 {
41        self.0 as i64
42    }
43}
44
45impl cast<i32> {
46    #[inline(always)]
47    pub const fn to_unsigned(self) -> u32 {
48        self.0 as u32
49    }
50
51    #[inline(always)]
52    pub const fn to_i64_sign_extend(self) -> i64 {
53        self.0 as i64
54    }
55
56    #[inline(always)]
57    pub const fn to_u64_sign_extend(self) -> u64 {
58        self.0 as u64
59    }
60}
61
62impl cast<i64> {
63    #[inline(always)]
64    pub const fn to_unsigned(self) -> u64 {
65        self.0 as u64
66    }
67}
68
69impl cast<u8> {
70    #[inline(always)]
71    pub const fn to_signed(self) -> i8 {
72        self.0 as i8
73    }
74
75    #[inline(always)]
76    pub const fn to_u64(self) -> u64 {
77        self.0 as u64
78    }
79}
80
81impl cast<u16> {
82    #[inline(always)]
83    pub const fn to_u64(self) -> u64 {
84        self.0 as u64
85    }
86}
87
88impl cast<u16> {
89    #[inline(always)]
90    pub const fn to_signed(self) -> i16 {
91        self.0 as i16
92    }
93
94    #[inline(always)]
95    pub const fn to_u32(self) -> u32 {
96        self.0 as u32
97    }
98}
99
100impl cast<u32> {
101    #[inline(always)]
102    pub const fn to_signed(self) -> i32 {
103        self.0 as i32
104    }
105
106    #[inline(always)]
107    pub const fn to_u64(self) -> u64 {
108        self.0 as u64
109    }
110
111    #[inline(always)]
112    pub const fn to_u64_sign_extend(self) -> u64 {
113        cast(self.0 as i32).to_u64_sign_extend()
114    }
115
116    #[inline(always)]
117    pub const fn to_usize(self) -> usize {
118        self.0 as usize
119    }
120
121    #[inline(always)]
122    pub const fn truncate_to_u8(self) -> u8 {
123        self.0 as u8
124    }
125
126    #[inline(always)]
127    pub const fn truncate_to_u16(self) -> u16 {
128        self.0 as u16
129    }
130}
131
132impl cast<u64> {
133    #[inline(always)]
134    pub const fn assert_always_fits_in_u32(self) -> u32 {
135        debug_assert!(self.0 <= u32::MAX as u64);
136        self.0 as u32
137    }
138
139    #[inline(always)]
140    pub const fn to_signed(self) -> i64 {
141        self.0 as i64
142    }
143
144    #[inline(always)]
145    pub const fn truncate_to_u8(self) -> u8 {
146        self.0 as u8
147    }
148
149    #[inline(always)]
150    pub const fn truncate_to_u16(self) -> u16 {
151        self.0 as u16
152    }
153
154    #[inline(always)]
155    pub const fn truncate_to_u32(self) -> u32 {
156        self.0 as u32
157    }
158}
159
160impl cast<usize> {
161    #[inline(always)]
162    pub const fn assert_always_fits_in_u32(self) -> u32 {
163        debug_assert!(self.0 <= u32::MAX as usize);
164        self.0 as u32
165    }
166
167    #[inline(always)]
168    pub const fn to_u64(self) -> u64 {
169        self.0 as u64
170    }
171}