sel4_abstract_ptr/abstract_ptr/
macros.rs

1//
2// Copyright 2024, Colias Group, LLC
3// Copyright (c) 2020 Philipp Oppermann
4//
5// SPDX-License-Identifier: MIT OR Apache-2.0
6//
7
8/// Provides safe field projection for abstract pointers referencing structs.
9///
10/// ## Examples
11///
12/// Accessing a struct field:
13///
14/// ```ignore
15/// use sel4_abstract_ptr::{AbstractPtr, map_field};
16///
17/// struct Example { field_1: u32, field_2: u8, }
18/// let mut value = Example { field_1: 15, field_2: 255 };
19/// let ptr = unsafe { AbstractPtr::new((&mut value).into()) };
20///
21/// // construct an abstract reference to a field
22/// let field_2 = map_field!(ptr.field_2);
23/// assert_eq!(field_2.read(), 255);
24/// ```
25///
26/// Creating `AbstractPtr`s to unaligned field in packed structs is not allowed:
27/// ```ignore
28/// use sel4_abstract_ptr::{AbstractPtr, map_field};
29///
30/// #[repr(packed)]
31/// struct Example { field_1: u8, field_2: usize, }
32/// let mut value = Example { field_1: 15, field_2: 255 };
33/// let ptr = unsafe { AbstractPtr::new((&mut value).into()) };
34///
35/// // Constructing an abstract reference to an unaligned field doesn't compile.
36/// let field_2 = map_field!(ptr.field_2);
37/// ```
38#[macro_export]
39macro_rules! map_field {
40    ($abstract_ptr:ident.$($place:ident).+) => {{
41        // Simulate creating a reference to the field. This is done to make
42        // sure that the field is not potentially unaligned. The body of the
43        // if statement will never be executed, so it can never cause any UB.
44        if false {
45            let _ref_to_field = &(unsafe { &*$abstract_ptr.as_raw_ptr().as_ptr() }).$($place).+;
46        }
47
48        unsafe {
49            $abstract_ptr.map(|ptr| {
50                core::ptr::NonNull::new(core::ptr::addr_of_mut!((*ptr.as_ptr()).$($place).+)).unwrap()
51            })
52        }
53    }};
54}