macro_rules! project_pointer {
(@gen $ptr:ident, ) => { ... };
(@gen $ptr:ident, .$field:tt $($rest:tt)*) => { ... };
(@gen $ptr:ident, [$index:expr]? $($rest:tt)*) => { ... };
(@gen $ptr:ident, [$index:expr] $($rest:tt)*) => { ... };
(mut $ptr:expr, $($proj:tt)*) => { ... };
($ptr:expr, $($proj:tt)*) => { ... };
}Expand description
Create a projection from a raw pointer.
The projected pointer is within the memory region marked by the input pointer. There is no requirement that the input raw pointer needs to be valid, so this macro may be used for projecting pointers outside normal address space, e.g. I/O pointers. However, if the input pointer is valid, the projected pointer is also valid.
Supported projections include field projections and index projections.
It is not allowed to project into types that implement custom Deref or
Index.
The macro has basic syntax of kernel::ptr::project!(ptr, projection), where ptr is an
expression that evaluates to a raw pointer which serves as the base of projection. projection
can be a projection expression of form .field (normally identifier, or numeral in case of
tuple structs) or of form [index].
If a mutable pointer is needed, the macro input can be prefixed with the mut keyword, i.e.
kernel::ptr::project!(mut ptr, projection). By default, a const pointer is created.
ptr::project! macro can perform both fallible indexing and build-time checked indexing.
[index] form performs build-time bounds checking; if compiler fails to prove [index] is in
bounds, compilation will fail. [index]? can be used to perform runtime bounds checking;
OutOfBound error is raised via ? if the index is out of bounds.
ยงExamples
Field projections are performed with .field_name:
struct MyStruct { field: u32, }
let ptr: *const MyStruct = core::ptr::dangling();
let field_ptr: *const u32 = kernel::ptr::project!(ptr, .field);
struct MyTupleStruct(u32, u32);
fn proj(ptr: *const MyTupleStruct) {
let field_ptr: *const u32 = kernel::ptr::project!(ptr, .1);
}Index projections are performed with [index]:
fn proj(ptr: *const [u8; 32]) -> Result {
let field_ptr: *const u8 = kernel::ptr::project!(ptr, [1]);
// The following invocation, if uncommented, would fail the build.
//
// kernel::ptr::project!(ptr, [128]);
// This will raise an `OutOfBound` error (which is convertible to `ERANGE`).
kernel::ptr::project!(ptr, [128]?);
Ok(())
}If you need to match on the error instead of propagate, put the invocation inside a closure:
let ptr: *const [u8; 32] = core::ptr::dangling();
let field_ptr: Result<*const u8> = (|| -> Result<_> {
Ok(kernel::ptr::project!(ptr, [128]?))
})();
assert!(field_ptr.is_err());For mutable pointers, put mut as the first token in macro invocation.
let ptr: *mut [(u8, u16); 32] = core::ptr::dangling_mut();
let field_ptr: *mut u16 = kernel::ptr::project!(mut ptr, [1].1);