1/*!
2This module provides several integer oriented traits for converting between
3both fixed size integers and integers whose size varies based on the target
4(like `usize`).
5
6The main design principle for this module is to centralize all uses of `as`.
7The thinking here is that `as` makes it very easy to perform accidental lossy
8conversions, and if we centralize all its uses here under more descriptive
9higher level operations, its use and correctness becomes easier to audit.
10
11This was copied mostly wholesale from `regex-automata`.
12
13NOTE: for simplicity, we don't take target pointer width into account here for
14`usize` conversions. Since we currently only panic in debug mode, skipping the
15check when it can be proven it isn't needed at compile time doesn't really
16matter. Now, if we wind up wanting to do as many checks as possible in release
17mode, then we would want to skip those when we know the conversions are always
18non-lossy.
19*/
20
21pub(crate) trait U8 {
22 fn as_usize(self) -> usize;
23}
24
25impl U8 for u8 {
26 fn as_usize(self) -> usize {
27 usize::from(self)
28 }
29}
30
31pub(crate) trait U16 {
32 fn as_usize(self) -> usize;
33 fn low_u8(self) -> u8;
34 fn high_u8(self) -> u8;
35}
36
37impl U16 for u16 {
38 fn as_usize(self) -> usize {
39 usize::from(self)
40 }
41
42 fn low_u8(self) -> u8 {
43 self as u8
44 }
45
46 fn high_u8(self) -> u8 {
47 (self >> 8) as u8
48 }
49}
50
51pub(crate) trait U32 {
52 fn as_usize(self) -> usize;
53 fn low_u8(self) -> u8;
54 fn low_u16(self) -> u16;
55 fn high_u16(self) -> u16;
56}
57
58impl U32 for u32 {
59 #[inline]
60 fn as_usize(self) -> usize {
61 #[cfg(debug_assertions)]
62 {
63 usize::try_from(self).expect("u32 overflowed usize")
64 }
65 #[cfg(not(debug_assertions))]
66 {
67 self as usize
68 }
69 }
70
71 fn low_u8(self) -> u8 {
72 self as u8
73 }
74
75 fn low_u16(self) -> u16 {
76 self as u16
77 }
78
79 fn high_u16(self) -> u16 {
80 (self >> 16) as u16
81 }
82}
83
84pub(crate) trait U64 {
85 fn as_usize(self) -> usize;
86 fn low_u8(self) -> u8;
87 fn low_u16(self) -> u16;
88 fn low_u32(self) -> u32;
89 fn high_u32(self) -> u32;
90}
91
92impl U64 for u64 {
93 fn as_usize(self) -> usize {
94 #[cfg(debug_assertions)]
95 {
96 usize::try_from(self).expect("u64 overflowed usize")
97 }
98 #[cfg(not(debug_assertions))]
99 {
100 self as usize
101 }
102 }
103
104 fn low_u8(self) -> u8 {
105 self as u8
106 }
107
108 fn low_u16(self) -> u16 {
109 self as u16
110 }
111
112 fn low_u32(self) -> u32 {
113 self as u32
114 }
115
116 fn high_u32(self) -> u32 {
117 (self >> 32) as u32
118 }
119}
120
121pub(crate) trait I32 {
122 fn as_usize(self) -> usize;
123 fn to_bits(self) -> u32;
124 fn from_bits(n: u32) -> i32;
125}
126
127impl I32 for i32 {
128 fn as_usize(self) -> usize {
129 #[cfg(debug_assertions)]
130 {
131 usize::try_from(self).expect(msg:"i32 overflowed usize")
132 }
133 #[cfg(not(debug_assertions))]
134 {
135 self as usize
136 }
137 }
138
139 fn to_bits(self) -> u32 {
140 self as u32
141 }
142
143 fn from_bits(n: u32) -> i32 {
144 n as i32
145 }
146}
147
148pub(crate) trait Usize {
149 fn as_u8(self) -> u8;
150 fn as_u16(self) -> u16;
151 fn as_u32(self) -> u32;
152 fn as_u64(self) -> u64;
153}
154
155impl Usize for usize {
156 fn as_u8(self) -> u8 {
157 #[cfg(debug_assertions)]
158 {
159 u8::try_from(self).expect("usize overflowed u8")
160 }
161 #[cfg(not(debug_assertions))]
162 {
163 self as u8
164 }
165 }
166
167 fn as_u16(self) -> u16 {
168 #[cfg(debug_assertions)]
169 {
170 u16::try_from(self).expect("usize overflowed u16")
171 }
172 #[cfg(not(debug_assertions))]
173 {
174 self as u16
175 }
176 }
177
178 fn as_u32(self) -> u32 {
179 #[cfg(debug_assertions)]
180 {
181 u32::try_from(self).expect("usize overflowed u32")
182 }
183 #[cfg(not(debug_assertions))]
184 {
185 self as u32
186 }
187 }
188
189 fn as_u64(self) -> u64 {
190 #[cfg(debug_assertions)]
191 {
192 u64::try_from(self).expect("usize overflowed u64")
193 }
194 #[cfg(not(debug_assertions))]
195 {
196 self as u64
197 }
198 }
199}
200
201// Pointers aren't integers, but we convert pointers to integers to perform
202// offset arithmetic in some places. (And no, we don't convert the integers
203// back to pointers.) So add 'as_usize' conversions here too for completeness.
204//
205// These 'as' casts are actually okay because they're always non-lossy. But the
206// idea here is to just try and remove as much 'as' as possible, particularly
207// in this crate where we are being really paranoid about offsets and making
208// sure we don't panic on inputs that might be untrusted. This way, the 'as'
209// casts become easier to audit if they're all in one place, even when some of
210// them are actually okay 100% of the time.
211
212pub(crate) trait Pointer {
213 fn as_usize(self) -> usize;
214}
215
216impl<T> Pointer for *const T {
217 fn as_usize(self) -> usize {
218 self as usize
219 }
220}
221
222pub(crate) trait PointerMut {
223 fn as_usize(self) -> usize;
224}
225
226impl<T> PointerMut for *mut T {
227 fn as_usize(self) -> usize {
228 self as usize
229 }
230}
231