deferred_reference/
slice_pointer_index.rs

1use core::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
2
3use crate::{PointerLength, SliceLike};
4
5/// A helper trait used for indexing operations, which is modeled after the [SliceIndex](core::slice::SliceIndex) trait
6/// from the Rust core library, but which promises not to take a reference to the underlying slice.
7///
8/// # Safety
9/// Implementations of this trait have to promise that:
10/// * If the argument to get_(mut_)unchecked is a safe pointer, then so is the result.
11/// * The pointers may not be dereferenced (both pointers given as arguments as well as the returned pointers).
12pub unsafe trait SlicePointerIndex<T>/*: private_slice_index::Sealed*/
13where
14    T: SliceLike + ?Sized,
15{
16    /// The output type returned by methods.
17    type Output: ?Sized;
18
19    /// Returns a shared pointer to the output at this location, if in bounds.
20    fn get(self, slice: *const T) -> Option<*const Self::Output>;
21
22    /// Returns a mutable poiner to the output at this location, if in bounds.
23    fn get_mut(self, slice: *mut T) -> Option<*mut Self::Output>;
24
25    /// Returns a shared pointer to the output at this location, without
26    /// performing any bounds checking.
27    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
28    /// is *[undefined behavior]* even if the resulting reference is not used.
29    ///
30    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
31    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;
32
33    /// Returns a mutable pointer to the output at this location, without
34    /// performing any bounds checking.
35    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
36    /// is *[undefined behavior]* even if the resulting reference is not used.
37    ///
38    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
39    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output;
40
41    /// Returns a shared pointer to the output at this location, panicking
42    /// if out of bounds.
43    #[track_caller]
44    fn index(self, slice: *const T) -> *const Self::Output;
45
46    /// Returns a mutable pointer to the output at this location, panicking
47    /// if out of bounds.
48    #[track_caller]
49    fn index_mut(self, slice: *mut T) -> *mut Self::Output;
50}
51
52#[inline(never)]
53#[cold]
54#[track_caller]
55fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
56    panic!("range start index {} out of range for slice pointer of length {}", index, len);
57}
58
59#[inline(never)]
60#[cold]
61#[track_caller]
62fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
63    panic!("range end index {} out of range for slice pointer of length {}", index, len);
64}
65
66#[inline(never)]
67#[cold]
68#[track_caller]
69fn slice_index_order_fail(index: usize, end: usize) -> ! {
70    panic!("slice pointer index starts at {} but ends at {}", index, end);
71}
72
73// #[inline(never)]
74// #[cold]
75// #[track_caller]
76// pub(crate) fn slice_start_index_overflow_fail() -> ! {
77//     panic!("attempted to index slice pointer from after maximum usize");
78// }
79
80#[inline(never)]
81#[cold]
82#[track_caller]
83fn slice_end_index_overflow_fail() -> ! {
84    panic!("attempted to index slice pointer up to maximum usize");
85}
86
87#[inline(never)]
88#[cold]
89#[track_caller]
90fn slice_index_overflow_fail(index: usize, len: usize) -> ! {
91    panic!("index {} out of range for slice pointer of length {}", index, len);
92}
93
94unsafe impl<T> SlicePointerIndex<T> for usize
95where
96    T: SliceLike + ?Sized,
97{
98    type Output = T::Element;
99
100    #[inline]
101    fn get(self, slice: *const T) -> Option<*const Self::Output> {
102        // SAFETY: `self` is checked to be in bounds.
103        if self < PointerLength::len(slice) { unsafe { Some(self.get_unchecked(slice)) } } else { None }
104    }
105
106    #[inline]
107    fn get_mut(self, slice: *mut T) -> Option<*mut Self::Output> {
108        // SAFETY: `self` is checked to be in bounds.
109        if self < PointerLength::len(slice) { unsafe { Some(self.get_unchecked_mut(slice)) } } else { None }
110    }
111
112    #[inline]
113    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output {
114        // SAFETY: the caller guarantees that `slice` is not dangling, so it
115        // cannot be longer than `isize::MAX`. They also guarantee that
116        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
117        // so the call to `add` is safe.
118        (slice as *const T::Element).add(self)
119    }
120
121    #[inline]
122    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output {
123        // SAFETY: see comments for `get_unchecked` above.
124        (slice as *mut T::Element).add(self)
125    }
126
127    #[inline]
128    fn index(self, slice: *const T) -> *const Self::Output {
129        if self > PointerLength::len(slice) {
130            slice_index_overflow_fail(self, PointerLength::len(slice))
131        }
132        // SAFETY: this is safe, bounds are checked above
133        unsafe {
134            self.get_unchecked(slice)
135        }
136    }
137
138    #[inline]
139    fn index_mut(self, slice: *mut T) -> *mut Self::Output {
140        if self > PointerLength::len(slice) {
141            slice_index_overflow_fail(self, PointerLength::len(slice))
142        }
143        // SAFETY: this is safe, bounds are checked above
144        unsafe {
145            self.get_unchecked_mut(slice)
146        }
147    }
148}
149
150unsafe impl<T> SlicePointerIndex<T> for Range<usize>
151where
152    T: SliceLike + ?Sized,
153{
154    type Output = [T::Element];
155
156    #[inline]
157    fn get(self, slice: *const T) -> Option<*const Self::Output> {
158        if self.start > self.end || self.end > PointerLength::len(slice) {
159            None
160        } else {
161            // SAFETY: `self` is checked to be valid and in bounds above.
162            unsafe { Some(self.get_unchecked(slice)) }
163        }
164    }
165
166    #[inline]
167    fn get_mut(self, slice: *mut T) -> Option<*mut Self::Output> {
168        if self.start > self.end || self.end > PointerLength::len(slice) {
169            None
170        } else {
171            // SAFETY: `self` is checked to be valid and in bounds above.
172            unsafe { Some(self.get_unchecked_mut(slice)) }
173        }
174    }
175
176    #[inline]
177    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output {
178        // SAFETY: the caller guarantees that `slice` is not dangling, so it
179        // cannot be longer than `isize::MAX`. They also guarantee that
180        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
181        // so the call to `add` is safe.
182        core::ptr::slice_from_raw_parts((slice as *const T::Element).add(self.start), self.end - self.start)
183    }
184
185    #[inline]
186    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output {
187        // SAFETY: see comments for `get_unchecked` above.
188        core::ptr::slice_from_raw_parts_mut((slice as *mut T::Element).add(self.start), self.end - self.start)
189    }
190
191    #[inline]
192    fn index(self, slice: *const T) -> *const Self::Output {
193        if self.start > self.end {
194            slice_index_order_fail(self.start, self.end);
195        } else if self.end > PointerLength::len(slice) {
196            slice_end_index_len_fail(self.end, PointerLength::len(slice));
197        }
198        // SAFETY: `self` is checked to be valid and in bounds above.
199        unsafe { self.get_unchecked(slice) }
200    }
201
202    #[inline]
203    fn index_mut(self, slice: *mut T) -> *mut Self::Output {
204        if self.start > self.end {
205            slice_index_order_fail(self.start, self.end);
206        } else if self.end > PointerLength::len(slice) {
207            slice_end_index_len_fail(self.end, PointerLength::len(slice));
208        }
209        // SAFETY: `self` is checked to be valid and in bounds above.
210        unsafe { self.get_unchecked_mut(slice) }
211    }
212}
213
214unsafe impl<T> SlicePointerIndex<T> for RangeTo<usize>
215where
216    T: SliceLike + ?Sized,
217{
218    type Output = [T::Element];
219
220    #[inline]
221    fn get(self, slice: *const T) -> Option<*const Self::Output> {
222        (0..self.end).get(slice)
223    }
224
225    #[inline]
226    fn get_mut(self, slice: *mut T) -> Option<*mut Self::Output> {
227        (0..self.end).get_mut(slice)
228    }
229
230    #[inline]
231    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output {
232        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
233        (0..self.end).get_unchecked(slice)
234    }
235
236    #[inline]
237    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output {
238        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
239        (0..self.end).get_unchecked_mut(slice)
240    }
241
242    #[inline]
243    fn index(self, slice: *const T) -> *const Self::Output {
244        (0..self.end).index(slice)
245    }
246
247    #[inline]
248    fn index_mut(self, slice: *mut T) -> *mut Self::Output {
249        (0..self.end).index_mut(slice)
250    }
251}
252
253unsafe impl<T> SlicePointerIndex<T> for RangeFrom<usize>
254where
255    T: SliceLike + ?Sized,
256{
257    type Output = [T::Element];
258
259    #[inline]
260    fn get(self, slice: *const T) -> Option<*const Self::Output> {
261        (self.start..PointerLength::len(slice)).get(slice)
262    }
263
264    #[inline]
265    fn get_mut(self, slice: *mut T) -> Option<*mut Self::Output> {
266        (self.start..PointerLength::len(slice)).get_mut(slice)
267    }
268
269    #[inline]
270    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output {
271        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
272        (self.start..PointerLength::len(slice)).get_unchecked(slice)
273    }
274
275    #[inline]
276    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output {
277        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
278        (self.start..PointerLength::len(slice)).get_unchecked_mut(slice)
279    }
280
281    #[inline]
282    fn index(self, slice: *const T) -> *const Self::Output {
283        if self.start > PointerLength::len(slice) {
284            slice_start_index_len_fail(self.start, PointerLength::len(slice));
285        }
286        // SAFETY: `self` is checked to be valid and in bounds above.
287        unsafe { self.get_unchecked(slice) }
288    }
289
290    #[inline]
291    fn index_mut(self, slice: *mut T) -> *mut Self::Output {
292        if self.start > PointerLength::len(slice) {
293            slice_start_index_len_fail(self.start, PointerLength::len(slice));
294        }
295        // SAFETY: `self` is checked to be valid and in bounds above.
296        unsafe { self.get_unchecked_mut(slice) }
297    }
298}
299
300unsafe impl<T> SlicePointerIndex<[T]> for RangeFull {
301    type Output = [T];
302
303    #[inline]
304    fn get(self, slice: *const [T]) -> Option<*const [T]> {
305        Some(slice)
306    }
307
308    #[inline]
309    fn get_mut(self, slice: *mut [T]) -> Option<*mut [T]> {
310        Some(slice)
311    }
312
313    #[inline]
314    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
315        slice
316    }
317
318    #[inline]
319    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
320        slice
321    }
322
323    #[inline]
324    fn index(self, slice: *const [T]) -> *const [T] {
325        slice
326    }
327
328    #[inline]
329    fn index_mut(self, slice: *mut [T]) -> *mut [T] {
330        slice
331    }
332}
333
334unsafe impl<T, const N: usize> SlicePointerIndex<[T; N]> for RangeFull {
335    type Output = [T];
336
337    #[inline]
338    fn get(self, slice: *const [T; N]) -> Option<*const [T]> {
339        Some(slice)
340    }
341
342    #[inline]
343    fn get_mut(self, slice: *mut [T; N]) -> Option<*mut [T]> {
344        Some(slice)
345    }
346
347    #[inline]
348    unsafe fn get_unchecked(self, slice: *const [T; N]) -> *const [T] {
349        slice
350    }
351
352    #[inline]
353    unsafe fn get_unchecked_mut(self, slice: *mut [T; N]) -> *mut [T] {
354        slice
355    }
356
357    #[inline]
358    fn index(self, slice: *const [T; N]) -> *const [T] {
359        slice
360    }
361
362    #[inline]
363    fn index_mut(self, slice: *mut [T; N]) -> *mut [T] {
364        slice
365    }
366}
367
368/// Converts to an exclusive `Range` for `SliceIndex` implementations.
369/// The caller is responsible for dealing with `end == usize::MAX`.
370#[inline]
371fn into_slice_range(range_inclusive: RangeInclusive<usize>) -> Range<usize> {
372    // If we're not exhausted, we want to simply slice `start..end + 1`.
373    // If we are exhausted, then slicing with `end + 1..end + 1` gives us an
374    // empty range that is still subject to bounds-checks for that endpoint.
375    let exclusive_end = *range_inclusive.end() + 1;
376    let start = if range_inclusive.is_empty() { exclusive_end } else { *range_inclusive.start() };
377    start..exclusive_end
378}
379
380unsafe impl<T> SlicePointerIndex<T> for RangeInclusive<usize>
381where
382    T: SliceLike + ?Sized,
383{
384    type Output = [T::Element];
385
386    #[inline]
387    fn get(self, slice: *const T) -> Option<*const Self::Output> {
388        if *self.end() == usize::MAX { None } else { into_slice_range(self).get(slice) }
389    }
390
391    #[inline]
392    fn get_mut(self, slice: *mut T) -> Option<*mut Self::Output> {
393        if *self.end() == usize::MAX { None } else { into_slice_range(self).get_mut(slice) }
394    }
395
396    #[inline]
397    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output {
398        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
399        into_slice_range(self).get_unchecked(slice)
400    }
401
402    #[inline]
403    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output {
404        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
405        into_slice_range(self).get_unchecked_mut(slice)
406    }
407
408    #[inline]
409    fn index(self, slice: *const T) -> *const Self::Output {
410        if *self.end() == usize::MAX {
411            slice_end_index_overflow_fail();
412        }
413        into_slice_range(self).index(slice)
414    }
415
416    #[inline]
417    fn index_mut(self, slice: *mut T) -> *mut Self::Output {
418        if *self.end() == usize::MAX {
419            slice_end_index_overflow_fail();
420        }
421        into_slice_range(self).index_mut(slice)
422    }
423}
424
425unsafe impl<T> SlicePointerIndex<T> for RangeToInclusive<usize>
426where
427    T: SliceLike + ?Sized,
428{
429    type Output = [T::Element];
430
431    #[inline]
432    fn get(self, slice: *const T) -> Option<*const Self::Output> {
433        (0..=self.end).get(slice)
434    }
435
436    #[inline]
437    fn get_mut(self, slice: *mut T) -> Option<*mut Self::Output> {
438        (0..=self.end).get_mut(slice)
439    }
440
441    #[inline]
442    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output {
443        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
444        (0..=self.end).get_unchecked(slice)
445    }
446
447    #[inline]
448    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output {
449        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
450        (0..=self.end).get_unchecked_mut(slice)
451    }
452
453    #[inline]
454    fn index(self, slice: *const T) -> *const Self::Output {
455        (0..=self.end).index(slice)
456    }
457
458    #[inline]
459    fn index_mut(self, slice: *mut T) -> *mut Self::Output {
460        (0..=self.end).index_mut(slice)
461    }
462}