aho_corasick/util/
int.rs

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("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("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("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}