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
21// We define a little more than what we need, but I'd rather just have
22// everything via a consistent and uniform API then have holes.
23#![allow(dead_code)]
24
25pub(crate) trait U8 {
26 fn as_usize(self) -> usize;
27}
28
29impl U8 for u8 {
30 fn as_usize(self) -> usize {
31 usize::from(self)
32 }
33}
34
35pub(crate) trait U16 {
36 fn as_usize(self) -> usize;
37 fn low_u8(self) -> u8;
38 fn high_u8(self) -> u8;
39}
40
41impl U16 for u16 {
42 fn as_usize(self) -> usize {
43 usize::from(self)
44 }
45
46 fn low_u8(self) -> u8 {
47 self as u8
48 }
49
50 fn high_u8(self) -> u8 {
51 (self >> 8) as u8
52 }
53}
54
55pub(crate) trait U32 {
56 fn as_usize(self) -> usize;
57 fn low_u8(self) -> u8;
58 fn low_u16(self) -> u16;
59 fn high_u16(self) -> u16;
60}
61
62impl U32 for u32 {
63 #[inline]
64 fn as_usize(self) -> usize {
65 #[cfg(debug_assertions)]
66 {
67 usize::try_from(self).expect("u32 overflowed usize")
68 }
69 #[cfg(not(debug_assertions))]
70 {
71 self as usize
72 }
73 }
74
75 fn low_u8(self) -> u8 {
76 self as u8
77 }
78
79 fn low_u16(self) -> u16 {
80 self as u16
81 }
82
83 fn high_u16(self) -> u16 {
84 (self >> 16) as u16
85 }
86}
87
88pub(crate) trait U64 {
89 fn as_usize(self) -> usize;
90 fn low_u8(self) -> u8;
91 fn low_u16(self) -> u16;
92 fn low_u32(self) -> u32;
93 fn high_u32(self) -> u32;
94}
95
96impl U64 for u64 {
97 fn as_usize(self) -> usize {
98 #[cfg(debug_assertions)]
99 {
100 usize::try_from(self).expect("u64 overflowed usize")
101 }
102 #[cfg(not(debug_assertions))]
103 {
104 self as usize
105 }
106 }
107
108 fn low_u8(self) -> u8 {
109 self as u8
110 }
111
112 fn low_u16(self) -> u16 {
113 self as u16
114 }
115
116 fn low_u32(self) -> u32 {
117 self as u32
118 }
119
120 fn high_u32(self) -> u32 {
121 (self >> 32) as u32
122 }
123}
124
125pub(crate) trait I8 {
126 fn as_usize(self) -> usize;
127 fn to_bits(self) -> u8;
128 fn from_bits(n: u8) -> i8;
129}
130
131impl I8 for i8 {
132 fn as_usize(self) -> usize {
133 #[cfg(debug_assertions)]
134 {
135 usize::try_from(self).expect(msg:"i8 overflowed usize")
136 }
137 #[cfg(not(debug_assertions))]
138 {
139 self as usize
140 }
141 }
142
143 fn to_bits(self) -> u8 {
144 self as u8
145 }
146
147 fn from_bits(n: u8) -> i8 {
148 n as i8
149 }
150}
151
152pub(crate) trait I32 {
153 fn as_usize(self) -> usize;
154 fn to_bits(self) -> u32;
155 fn from_bits(n: u32) -> i32;
156}
157
158impl I32 for i32 {
159 fn as_usize(self) -> usize {
160 #[cfg(debug_assertions)]
161 {
162 usize::try_from(self).expect(msg:"i32 overflowed usize")
163 }
164 #[cfg(not(debug_assertions))]
165 {
166 self as usize
167 }
168 }
169
170 fn to_bits(self) -> u32 {
171 self as u32
172 }
173
174 fn from_bits(n: u32) -> i32 {
175 n as i32
176 }
177}
178
179pub(crate) trait I64 {
180 fn as_usize(self) -> usize;
181 fn to_bits(self) -> u64;
182 fn from_bits(n: u64) -> i64;
183}
184
185impl I64 for i64 {
186 fn as_usize(self) -> usize {
187 #[cfg(debug_assertions)]
188 {
189 usize::try_from(self).expect(msg:"i64 overflowed usize")
190 }
191 #[cfg(not(debug_assertions))]
192 {
193 self as usize
194 }
195 }
196
197 fn to_bits(self) -> u64 {
198 self as u64
199 }
200
201 fn from_bits(n: u64) -> i64 {
202 n as i64
203 }
204}
205
206pub(crate) trait Usize {
207 fn as_u8(self) -> u8;
208 fn as_u16(self) -> u16;
209 fn as_u32(self) -> u32;
210 fn as_u64(self) -> u64;
211}
212
213impl Usize for usize {
214 fn as_u8(self) -> u8 {
215 #[cfg(debug_assertions)]
216 {
217 u8::try_from(self).expect("usize overflowed u8")
218 }
219 #[cfg(not(debug_assertions))]
220 {
221 self as u8
222 }
223 }
224
225 fn as_u16(self) -> u16 {
226 #[cfg(debug_assertions)]
227 {
228 u16::try_from(self).expect("usize overflowed u16")
229 }
230 #[cfg(not(debug_assertions))]
231 {
232 self as u16
233 }
234 }
235
236 fn as_u32(self) -> u32 {
237 #[cfg(debug_assertions)]
238 {
239 u32::try_from(self).expect("usize overflowed u32")
240 }
241 #[cfg(not(debug_assertions))]
242 {
243 self as u32
244 }
245 }
246
247 fn as_u64(self) -> u64 {
248 #[cfg(debug_assertions)]
249 {
250 u64::try_from(self).expect("usize overflowed u64")
251 }
252 #[cfg(not(debug_assertions))]
253 {
254 self as u64
255 }
256 }
257}
258
259// Pointers aren't integers, but we convert pointers to integers to perform
260// offset arithmetic in some places. (And no, we don't convert the integers
261// back to pointers.) So add 'as_usize' conversions here too for completeness.
262//
263// These 'as' casts are actually okay because they're always non-lossy. But the
264// idea here is to just try and remove as much 'as' as possible, particularly
265// in this crate where we are being really paranoid about offsets and making
266// sure we don't panic on inputs that might be untrusted. This way, the 'as'
267// casts become easier to audit if they're all in one place, even when some of
268// them are actually okay 100% of the time.
269
270pub(crate) trait Pointer {
271 fn as_usize(self) -> usize;
272}
273
274impl<T> Pointer for *const T {
275 fn as_usize(self) -> usize {
276 self as usize
277 }
278}
279

Provided by KDAB

Privacy Policy