Skip to content

Instantly share code, notes, and snippets.

@EHfive
Last active August 28, 2023 17:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EHfive/1843fe96a0b0c85e59bc057e25392631 to your computer and use it in GitHub Desktop.
Save EHfive/1843fe96a0b0c85e59bc057e25392631 to your computer and use it in GitHub Desktop.
Rust offset_of!() and container_of!() macros utilizing core::ptr::addr_of!()
/**
* Macros
*/
macro_rules! offset_of {
($Container:ty, $($fields:tt).+) => {{
// avoid dereferencing null pointer
let container = ::core::mem::align_of::<$Container>() as *const $Container;
let member = ::core::ptr::addr_of!((*container).$($fields).+);
member.cast::<u8>().offset_from(container.cast::<u8>()) as usize
}};
}
macro_rules! container_of {
($ptr:expr, $Container:ty, $($fields:tt).+) => {{
let container = ::core::mem::align_of::<$Container>() as *const $Container;
let member = ::core::ptr::addr_of!((*container).$($fields).+);
if false {
// static type check
let _ = member == $ptr;
}
let offset = container.cast::<u8>().offset_from(member.cast::<u8>());
($ptr.cast::<u8>())
.offset(offset)
.cast::<$Container>()
}};
}
/**
* Example
*/
mod lib_x {
#[repr(C)]
#[derive(Default)]
pub struct Abi {
foo: u8,
bar: u8,
}
pub unsafe fn invoke_callback(this: *mut Abi, cb: unsafe fn(*mut Abi)) {
(*this).foo = 1;
cb(this);
}
}
const SIGNATURE: u32 = 0xdeadbeef;
#[repr(C)]
#[derive(Default)]
struct UserData {
sig: u32,
field_abi: lib_x::Abi,
tuple: (u8, u8),
callback_count: u32,
}
unsafe fn callback(this: *mut lib_x::Abi) {
let user_data = &mut *container_of!(this, UserData, field_abi);
assert_eq!(SIGNATURE, user_data.sig);
user_data.callback_count += 1;
}
fn main() {
unsafe {
let mut user_data = UserData {
sig: SIGNATURE,
..UserData::default()
};
assert_eq!(4, offset_of!(UserData, field_abi));
assert_eq!(7, offset_of!(UserData, tuple.1));
lib_x::invoke_callback(
core::ptr::addr_of_mut!(user_data.field_abi),
callback, //
);
assert_eq!(1, user_data.callback_count);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment