|
14 | 14 | #![no_std]
|
15 | 15 | #![feature(allocator_api)]
|
16 | 16 | #![feature(coerce_unsized)]
|
| 17 | +#![feature(const_ptr_offset_from)] |
| 18 | +#![feature(const_refs_to_cell)] |
17 | 19 | #![feature(dispatch_from_dyn)]
|
18 | 20 | #![feature(new_uninit)]
|
19 | 21 | #![feature(receiver_trait)]
|
@@ -98,3 +100,37 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
|
98 | 100 | // instead of `!`. See <https://github.com/rust-lang/rust-bindgen/issues/2094>.
|
99 | 101 | loop {}
|
100 | 102 | }
|
| 103 | + |
| 104 | +/// Calculates the offset of a field from the beginning of the struct it belongs to. |
| 105 | +/// |
| 106 | +/// # Examples |
| 107 | +/// |
| 108 | +/// ``` |
| 109 | +/// #[repr(C)] |
| 110 | +/// struct Test { |
| 111 | +/// a: u64, |
| 112 | +/// b: u32, |
| 113 | +/// } |
| 114 | +/// |
| 115 | +/// assert_eq!(kernel::offset_of!(Test, b), 8); |
| 116 | +/// ``` |
| 117 | +#[macro_export] |
| 118 | +macro_rules! offset_of { |
| 119 | + ($type:path, $field:ident) => {{ |
| 120 | + let $type { $field: _, .. }; |
| 121 | + let tmp = ::core::mem::MaybeUninit::<$type>::uninit(); |
| 122 | + let outer = tmp.as_ptr(); |
| 123 | + // To avoid warnings when nesting `unsafe` blocks. |
| 124 | + #[allow(unused_unsafe)] |
| 125 | + // SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that |
| 126 | + // we don't actually read from `outer` (which would be UB) nor create an intermediate |
| 127 | + // reference. |
| 128 | + let inner = unsafe { ::core::ptr::addr_of!((*outer).$field) } as *const u8; |
| 129 | + // To avoid warnings when nesting `unsafe` blocks. |
| 130 | + #[allow(unused_unsafe)] |
| 131 | + // SAFETY: The two pointers are within the same allocation block. |
| 132 | + unsafe { |
| 133 | + inner.offset_from(outer as *const u8) as usize |
| 134 | + } |
| 135 | + }}; |
| 136 | +} |
0 commit comments