macro_rules! project {
(@gen $ptr:ident, ) => { ... };
(@gen $ptr:ident, .$field:tt $($rest:tt)*) => { ... };
(@gen $ptr:ident, [try: $index:expr] $($rest:tt)*) => { ... };
(@gen $ptr:ident, [panic: $index:expr] $($rest:tt)*) => { ... };
(@gen $ptr:ident, [build: $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.
The ptr::project! macro can perform both fallible indexing and build-time checked indexing.
The syntax is of the form [<flavor>: index] where flavor indicates the way of handling
index out-of-bounds errors.
trywill raise anOutOfBounderror (which is convertible toERANGE).buildwill use thebuild_assert!mechanism to have the compiler validate the index is in bounds.panicwill cause a Rustpanic!if the index goes 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 [<flavor>: index], where flavor is try, build or
panic:
fn proj(ptr: *const [u8; 32]) -> Result {
let field_ptr: *const u8 = kernel::ptr::project!(ptr, [build: 1]);
// The following invocation, if uncommented, would fail the build.
//
// kernel::ptr::project!(ptr, [build: 128]);
// This will raise an `OutOfBound` error (which is convertible to `ERANGE`).
kernel::ptr::project!(ptr, [try: 128]);
// This will panic at runtime if executed.
kernel::ptr::project!(ptr, [panic: 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, [try: 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, [build: 1].1);