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