Skip to content

Commit 6646d85

Browse files
committed
Add container_of and offset_of macros.
1 parent 101e008 commit 6646d85

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

rust/kernel/lib.rs

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

143+
/// Calculates the offset of a field from the beginning of the struct it belongs to.
144+
#[macro_export]
145+
macro_rules! offset_of {
146+
($type:ty, $($f:tt)*) => {{
147+
let tmp = core::mem::MaybeUninit::<$type>::uninit();
148+
let ptr = tmp.as_ptr();
149+
#[allow(unused_unsafe)]
150+
let dev = unsafe { core::ptr::addr_of!((*ptr).$($f)*) as *const u8 };
151+
#[allow(unused_unsafe)]
152+
unsafe { dev.offset_from(ptr as *const u8) }
153+
}}
154+
}
155+
156+
/// Produces a pointer to an object from a pointer to one of its fields.
157+
///
158+
/// # Safety
159+
///
160+
/// Callers must ensure that the pointer to the field is in fact a pointer to the specified field,
161+
/// as opposed to a pointer to another object of the same type.
162+
///
163+
/// # Example
164+
///
165+
///```
166+
/// struct Test {
167+
/// a: u64,
168+
/// b: u32,
169+
/// }
170+
///
171+
/// fn test() {
172+
/// let test = Test{a: 10, b: 20};
173+
/// let b_ptr = &test.b;
174+
/// let test_alias = unsafe { container_of!(b_ptr, Test, b) };
175+
/// // This prints `true`.
176+
/// println!("{}", core::ptr::eq(&test, test_alias));
177+
/// }
178+
///```
179+
///
180+
#[macro_export]
181+
macro_rules! container_of {
182+
($ptr:expr, $type:ty, $($f:tt)*) => {{
183+
let offset = $crate::offset_of!($type, $($f)*);
184+
($ptr as *const _ as *const u8).offset(-offset) as *const $type
185+
}}
186+
}
187+
143188
#[global_allocator]
144189
static ALLOCATOR: allocator::KernelAllocator = allocator::KernelAllocator;

0 commit comments

Comments
 (0)