Skip to content

Commit de33f8a

Browse files
authored
Merge pull request #158 from wedsonaf/container_of
Add `container_of` and `offset_of` macros.
2 parents a553727 + 94d4038 commit de33f8a

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

rust/kernel/lib.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,5 +140,70 @@ fn panic(_info: &PanicInfo) -> ! {
140140
}
141141
}
142142

143+
/// Calculates the offset of a field from the beginning of the struct it belongs to.
144+
///
145+
/// # Example
146+
///
147+
///```
148+
/// struct Test {
149+
/// a: u64,
150+
/// b: u32,
151+
/// }
152+
///
153+
/// fn test() {
154+
/// // This prints `8`.
155+
/// println!("{}", offset_of!(Test, b));
156+
/// }
157+
///```
158+
#[macro_export]
159+
macro_rules! offset_of {
160+
($type:ty, $($f:tt)*) => {{
161+
let tmp = core::mem::MaybeUninit::<$type>::uninit();
162+
let outer = tmp.as_ptr();
163+
// To avoid warnings when nesting `unsafe` blocks.
164+
#[allow(unused_unsafe)]
165+
// SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
166+
// we don't actually read from `outer` (which would be UB) nor create an intermediate
167+
// reference.
168+
let inner = unsafe { core::ptr::addr_of!((*outer).$($f)*) } as *const u8;
169+
// To avoid warnings when nesting `unsafe` blocks.
170+
#[allow(unused_unsafe)]
171+
// SAFETY: The two pointers are within the same allocation block.
172+
unsafe { inner.offset_from(outer as *const u8) }
173+
}}
174+
}
175+
176+
/// Produces a pointer to an object from a pointer to one of its fields.
177+
///
178+
/// # Safety
179+
///
180+
/// Callers must ensure that the pointer to the field is in fact a pointer to the specified field,
181+
/// as opposed to a pointer to another object of the same type.
182+
///
183+
/// # Example
184+
///
185+
///```
186+
/// struct Test {
187+
/// a: u64,
188+
/// b: u32,
189+
/// }
190+
///
191+
/// fn test() {
192+
/// let test = Test{a: 10, b: 20};
193+
/// let b_ptr = &test.b;
194+
/// let test_alias = unsafe { container_of!(b_ptr, Test, b) };
195+
/// // This prints `true`.
196+
/// println!("{}", core::ptr::eq(&test, test_alias));
197+
/// }
198+
///```
199+
///
200+
#[macro_export]
201+
macro_rules! container_of {
202+
($ptr:expr, $type:ty, $($f:tt)*) => {{
203+
let offset = $crate::offset_of!($type, $($f)*);
204+
($ptr as *const _ as *const u8).offset(-offset) as *const $type
205+
}}
206+
}
207+
143208
#[global_allocator]
144209
static ALLOCATOR: allocator::KernelAllocator = allocator::KernelAllocator;

0 commit comments

Comments
 (0)