@@ -26,14 +26,14 @@ impl From<OutOfBound> for Error {
2626///
2727/// # Safety
2828///
29- /// For a given input pointer `slice` and return value `output`, the implementation of `build_index`
30- /// and `get` (if [`Some`] is returned) must ensure that:
29+ /// For a given input pointer `slice` and return value `output`, the implementation of `index`,
30+ /// `build_index` and `get` (if [`Some`] is returned) must ensure that:
3131/// - `output` has the same provenance as `slice`;
3232/// - `output.byte_offset_from(slice)` is between 0 to
3333/// `KnownSize::size(slice) - KnownSize::size(output)`.
3434///
35- /// This means that if the input pointer is valid, then the pointer returned by `get` or
36- /// `build_index` is also valid.
35+ /// This means that if the input pointer is valid, then the pointer returned by `get`, `index`
36+ /// or `build_index` is also valid.
3737#[ diagnostic:: on_unimplemented( message = "`{Self}` cannot be used to index `{T}`" ) ]
3838#[ doc( hidden) ]
3939pub unsafe trait ProjectIndex < T : ?Sized > : Sized {
@@ -42,6 +42,9 @@ pub unsafe trait ProjectIndex<T: ?Sized>: Sized {
4242 /// Returns an index-projected pointer, if in bounds.
4343 fn get ( self , slice : * mut T ) -> Option < * mut Self :: Output > ;
4444
45+ /// Returns an index-projected pointer; panic if out of bounds.
46+ fn index ( self , slice : * mut T ) -> * mut Self :: Output ;
47+
4548 /// Returns an index-projected pointer; fail the build if it cannot be proved to be in bounds.
4649 #[ inline( always) ]
4750 fn build_index ( self , slice : * mut T ) -> * mut Self :: Output {
6669 <I as ProjectIndex < [ T ] > >:: get ( self , slice)
6770 }
6871
72+ #[ inline( always) ]
73+ fn index ( self , slice : * mut [ T ; N ] ) -> * mut Self :: Output {
74+ <I as ProjectIndex < [ T ] > >:: index ( self , slice)
75+ }
76+
6977 #[ inline( always) ]
7078 fn build_index ( self , slice : * mut [ T ; N ] ) -> * mut Self :: Output {
7179 <I as ProjectIndex < [ T ] > >:: build_index ( self , slice)
@@ -85,6 +93,16 @@ unsafe impl<T> ProjectIndex<[T]> for usize {
8593 Some ( slice. cast :: < T > ( ) . wrapping_add ( self ) )
8694 }
8795 }
96+
97+ #[ inline( always) ]
98+ fn index ( self , slice : * mut [ T ] ) -> * mut T {
99+ // Leverage Rust built-in operators for bounds checking.
100+ // SAFETY: All non-null and aligned pointers are valid for ZST read.
101+ let zst_slice =
102+ unsafe { core:: slice:: from_raw_parts :: < ( ) > ( core:: ptr:: dangling ( ) , slice. len ( ) ) } ;
103+ let ( ) = zst_slice[ self ] ;
104+ slice. cast :: < T > ( ) . wrapping_add ( self )
105+ }
88106}
89107
90108// SAFETY: `get`-returned pointer has the same provenance as `slice` and the offset is checked to
@@ -103,6 +121,18 @@ unsafe impl<T> ProjectIndex<[T]> for core::ops::Range<usize> {
103121 new_len,
104122 ) )
105123 }
124+
125+ #[ inline( always) ]
126+ fn index ( self , slice : * mut [ T ] ) -> * mut [ T ] {
127+ // Leverage Rust built-in operators for bounds checking.
128+ // SAFETY: All non-null and aligned pointers are valid for ZST read.
129+ let zst_slice =
130+ unsafe { core:: slice:: from_raw_parts :: < ( ) > ( core:: ptr:: dangling ( ) , slice. len ( ) ) } ;
131+ _ = zst_slice[ self . clone ( ) ] ;
132+
133+ // SAFETY: Bounds checked.
134+ unsafe { self . get ( slice) . unwrap_unchecked ( ) }
135+ }
106136}
107137
108138// SAFETY: Safety requirement guaranteed by the forwarded impl.
@@ -113,6 +143,11 @@ unsafe impl<T> ProjectIndex<[T]> for core::ops::RangeTo<usize> {
113143 fn get ( self , slice : * mut [ T ] ) -> Option < * mut [ T ] > {
114144 ( 0 ..self . end ) . get ( slice)
115145 }
146+
147+ #[ inline( always) ]
148+ fn index ( self , slice : * mut [ T ] ) -> * mut [ T ] {
149+ ( 0 ..self . end ) . index ( slice)
150+ }
116151}
117152
118153// SAFETY: Safety requirement guaranteed by the forwarded impl.
@@ -123,6 +158,11 @@ unsafe impl<T> ProjectIndex<[T]> for core::ops::RangeFrom<usize> {
123158 fn get ( self , slice : * mut [ T ] ) -> Option < * mut [ T ] > {
124159 ( self . start ..slice. len ( ) ) . get ( slice)
125160 }
161+
162+ #[ inline( always) ]
163+ fn index ( self , slice : * mut [ T ] ) -> * mut [ T ] {
164+ ( self . start ..slice. len ( ) ) . index ( slice)
165+ }
126166}
127167
128168// SAFETY: `get` returned the pointer as is, so it always has the same provenance and offset of 0.
@@ -133,6 +173,11 @@ unsafe impl<T> ProjectIndex<[T]> for core::ops::RangeFull {
133173 fn get ( self , slice : * mut [ T ] ) -> Option < * mut [ T ] > {
134174 Some ( slice)
135175 }
176+
177+ #[ inline( always) ]
178+ fn index ( self , slice : * mut [ T ] ) -> * mut [ T ] {
179+ slice
180+ }
136181}
137182
138183/// A helper trait to perform field projection.
@@ -210,10 +255,13 @@ unsafe impl<T: Deref> ProjectField<true> for T {
210255/// If a mutable pointer is needed, the macro input can be prefixed with the `mut` keyword, i.e.
211256/// `kernel::ptr::project!(mut ptr, projection)`. By default, a const pointer is created.
212257///
213- /// `ptr::project!` macro can perform both fallible indexing and build-time checked indexing.
214- /// `[index]` form performs build-time bounds checking; if compiler fails to prove `[index]` is in
215- /// bounds, compilation will fail. `[index]?` can be used to perform runtime bounds checking;
216- /// `OutOfBound` error is raised via `?` if the index is out of bounds.
258+ /// The `ptr::project!` macro can perform both fallible indexing and build-time checked indexing.
259+ /// The syntax is of the form `[<flavor>: index]` where `flavor` indicates the way of handling
260+ /// index out-of-bounds errors.
261+ /// - `try` will raise an [`OutOfBound`] error (which is convertible to [`ERANGE`]).
262+ /// - `build` will use the [`build_assert!`] mechanism to have the compiler validate the index is
263+ /// in bounds.
264+ /// - `panic` will cause a Rust [`panic!`] if the index goes out of bounds.
217265///
218266/// # Examples
219267///
@@ -231,17 +279,21 @@ unsafe impl<T: Deref> ProjectField<true> for T {
231279/// }
232280/// ```
233281///
234- /// Index projections are performed with `[index]`:
282+ /// Index projections are performed with `[<flavor>: index]`, where `flavor` is `try`, `build` or
283+ /// `panic`:
235284///
236285/// ```
237286/// fn proj(ptr: *const [u8; 32]) -> Result {
238- /// let field_ptr: *const u8 = kernel::ptr::project!(ptr, [1]);
287+ /// let field_ptr: *const u8 = kernel::ptr::project!(ptr, [build: 1]);
239288/// // The following invocation, if uncommented, would fail the build.
240289/// //
241- /// // kernel::ptr::project!(ptr, [128]);
290+ /// // kernel::ptr::project!(ptr, [build: 128]);
242291///
243292/// // This will raise an `OutOfBound` error (which is convertible to `ERANGE`).
244- /// kernel::ptr::project!(ptr, [128]?);
293+ /// kernel::ptr::project!(ptr, [try: 128]);
294+ ///
295+ /// // This will panic at runtime if executed.
296+ /// kernel::ptr::project!(ptr, [panic: 128]);
245297/// Ok(())
246298/// }
247299/// ```
@@ -251,7 +303,7 @@ unsafe impl<T: Deref> ProjectField<true> for T {
251303/// ```
252304/// let ptr: *const [u8; 32] = core::ptr::dangling();
253305/// let field_ptr: Result<*const u8> = (|| -> Result<_> {
254- /// Ok(kernel::ptr::project!(ptr, [128]? ))
306+ /// Ok(kernel::ptr::project!(ptr, [try: 128]))
255307/// })();
256308/// assert!(field_ptr.is_err());
257309/// ```
@@ -260,7 +312,7 @@ unsafe impl<T: Deref> ProjectField<true> for T {
260312///
261313/// ```
262314/// let ptr: *mut [(u8, u16); 32] = core::ptr::dangling_mut();
263- /// let field_ptr: *mut u16 = kernel::ptr::project!(mut ptr, [1].1);
315+ /// let field_ptr: *mut u16 = kernel::ptr::project!(mut ptr, [build: 1].1);
264316/// ```
265317#[ macro_export]
266318macro_rules! project_pointer {
@@ -283,16 +335,30 @@ macro_rules! project_pointer {
283335 $crate:: ptr:: project!( @gen $ptr, $( $rest) * )
284336 } ;
285337 // Fallible index projection.
286- ( @gen $ptr: ident, [ $index: expr] ? $( $rest: tt) * ) => {
338+ ( @gen $ptr: ident, [ try : $index: expr] $( $rest: tt) * ) => {
287339 let $ptr = $crate:: ptr:: projection:: ProjectIndex :: get( $index, $ptr)
288340 . ok_or( $crate:: ptr:: projection:: OutOfBound ) ?;
289341 $crate:: ptr:: project!( @gen $ptr, $( $rest) * )
290342 } ;
343+ // Panicking index projection.
344+ ( @gen $ptr: ident, [ panic: $index: expr] $( $rest: tt) * ) => {
345+ let $ptr = $crate:: ptr:: projection:: ProjectIndex :: index( $index, $ptr) ;
346+ $crate:: ptr:: project!( @gen $ptr, $( $rest) * )
347+ } ;
291348 // Build-time checked index projection.
292- ( @gen $ptr: ident, [ $index: expr] $( $rest: tt) * ) => {
349+ ( @gen $ptr: ident, [ build : $index: expr] $( $rest: tt) * ) => {
293350 let $ptr = $crate:: ptr:: projection:: ProjectIndex :: build_index( $index, $ptr) ;
294351 $crate:: ptr:: project!( @gen $ptr, $( $rest) * )
295352 } ;
353+
354+ // For compatibility
355+ ( @gen $ptr: ident, [ $index: expr] ? $( $rest: tt) * ) => {
356+ $crate:: ptr:: project!( @gen $ptr, [ try: $index] $( $rest) * )
357+ } ;
358+ ( @gen $ptr: ident, [ $index: expr] $( $rest: tt) * ) => {
359+ $crate:: ptr:: project!( @gen $ptr, [ build: $index] $( $rest) * )
360+ } ;
361+
296362 ( mut $ptr: expr, $( $proj: tt) * ) => { {
297363 let ptr: * mut _ = $ptr;
298364 $crate:: ptr:: project!( @gen ptr, $( $proj) * ) ;
0 commit comments