sel4_abstract_ptr/
core_ext.rs

1//
2// Copyright 2024, Colias Group, LLC
3//
4// SPDX-License-Identifier: MIT OR Apache-2.0
5//
6
7use core::{
8    ops::{self, Bound, Range, RangeBounds, RangeTo},
9    ptr::{self, NonNull},
10    slice::SliceIndex,
11};
12
13pub(crate) fn non_null_slice_len<T>(p: NonNull<[T]>) -> usize {
14    mut_ptr_slice_len(p.as_ptr())
15}
16
17pub(crate) fn mut_ptr_slice_len<T>(p: *mut [T]) -> usize {
18    ptr_meta::metadata(p)
19}
20
21pub(crate) fn non_null_slice_as_mut_ptr<T>(p: NonNull<[T]>) -> *mut T {
22    mut_ptr_slice_as_mut_ptr(p.as_ptr())
23}
24
25pub(crate) fn mut_ptr_slice_as_mut_ptr<T>(p: *mut [T]) -> *mut T {
26    p as *mut T
27}
28
29pub(crate) fn non_null_index<I, T>(
30    p: NonNull<[T]>,
31    index: I,
32) -> NonNull<<I as SliceIndex<[T]>>::Output>
33where
34    I: AbstractPtrSliceIndex<[T]> + SliceIndex<[()]> + Clone,
35{
36    NonNull::new(index.abstract_ptr_slice_index(p.as_ptr())).unwrap()
37}
38
39pub(crate) fn range<R>(range: R, bounds: RangeTo<usize>) -> Range<usize>
40where
41    R: RangeBounds<usize>,
42{
43    let len = bounds.end;
44
45    let start = match range.start_bound() {
46        Bound::Included(&start) => start,
47        Bound::Excluded(start) => start
48            .checked_add(1)
49            .unwrap_or_else(|| panic!("attempted to index slice from after maximum usize")),
50        Bound::Unbounded => 0,
51    };
52
53    let end = match range.end_bound() {
54        Bound::Included(end) => end
55            .checked_add(1)
56            .unwrap_or_else(|| panic!("attempted to index slice up to maximum usize")),
57        Bound::Excluded(&end) => end,
58        Bound::Unbounded => len,
59    };
60
61    if start > end {
62        panic!("slice index starts at {start} but ends at {end}",)
63    }
64    if end > len {
65        panic!("range end index {end} out of range for slice of length {len}",)
66    }
67
68    Range { start, end }
69}
70
71#[allow(private_bounds)]
72pub trait AbstractPtrSliceIndex<T: ?Sized>:
73    SliceIndex<T> + AbstractPtrSliceIndexInternal<T>
74{
75}
76
77pub(crate) trait AbstractPtrSliceIndexInternal<T: ?Sized>: SliceIndex<T> {
78    fn abstract_ptr_slice_index(self, slice: *mut T) -> *mut Self::Output;
79}
80
81impl<T> AbstractPtrSliceIndex<[T]> for usize {}
82
83impl<T> AbstractPtrSliceIndexInternal<[T]> for usize {
84    fn abstract_ptr_slice_index(self, slice: *mut [T]) -> *mut Self::Output {
85        bounds_check(mut_ptr_slice_len(slice), self);
86        mut_ptr_slice_as_mut_ptr(slice).wrapping_offset(self.try_into().unwrap())
87    }
88}
89
90impl<T> AbstractPtrSliceIndex<[T]> for Range<usize> {}
91
92impl<T> AbstractPtrSliceIndexInternal<[T]> for Range<usize> {
93    fn abstract_ptr_slice_index(self, slice: *mut [T]) -> *mut Self::Output {
94        bounds_check(mut_ptr_slice_len(slice), self.clone());
95        ptr::slice_from_raw_parts_mut(self.start.abstract_ptr_slice_index(slice), self.len())
96    }
97}
98
99macro_rules! slice_index_impl {
100    ($t:ty) => {
101        impl<T> AbstractPtrSliceIndex<[T]> for $t {}
102
103        impl<T> AbstractPtrSliceIndexInternal<[T]> for $t {
104            fn abstract_ptr_slice_index(self, slice: *mut [T]) -> *mut Self::Output {
105                range(self, ..mut_ptr_slice_len(slice)).abstract_ptr_slice_index(slice)
106            }
107        }
108    };
109}
110
111slice_index_impl!((Bound<usize>, Bound<usize>));
112slice_index_impl!(ops::RangeFrom<usize>);
113slice_index_impl!(ops::RangeFull);
114slice_index_impl!(ops::RangeInclusive<usize>);
115slice_index_impl!(ops::RangeTo<usize>);
116slice_index_impl!(ops::RangeToInclusive<usize>);
117
118fn bounds_check(len: usize, index: impl SliceIndex<[()]>) {
119    const MAX_ARRAY: [(); usize::MAX] = [(); usize::MAX];
120
121    let bound_check_slice = &MAX_ARRAY[..len];
122    let _ = &bound_check_slice[index];
123}