volatile/volatile_ptr/
macros.rs

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