pub use memoffset::offset_of;
#[macro_export]
macro_rules! container_of {
($ptr:expr, $type:path, $field:ident) => {
$ptr.cast::<u8>()
.sub($crate::offset_of!($type, $field))
.cast::<$type>()
};
}
#[cfg(test)]
mod tests {
#[allow(unused)]
#[repr(C)]
struct Wrapper<T: ?Sized> {
foo: i32,
bar: u8,
inner: T
}
#[test]
fn works_with_both_mutable_and_const_pointers() {
let mut wrap = Wrapper { foo: 1234, bar: 56, inner: 78u8 };
let inner_ptr = &wrap.inner as *const u8;
let _: *const Wrapper<u8> = unsafe {
crate::container_of!(inner_ptr, Wrapper<u8>, inner)
};
let inner_ptr_mut = &mut wrap.inner as *mut u8;
let _: *mut Wrapper<u8> = unsafe {
crate::container_of!(inner_ptr_mut, Wrapper<u8>, inner)
};
}
#[test]
fn no_padding() {
let wrap = Wrapper { foo: 1234, bar: 56, inner: 78u8 };
let inner_ptr = &wrap.inner as *const u8;
let wrap_ptr = unsafe {
crate::container_of!(inner_ptr, Wrapper<u8>, inner)
};
assert_eq!(&wrap as *const Wrapper<u8>, wrap_ptr);
}
#[test]
fn with_padding() {
let wrap = Wrapper { foo: 1234, bar: 56, inner: 78i32 };
let inner_ptr = &wrap.inner as *const i32;
let wrap_ptr = unsafe {
crate::container_of!(inner_ptr, Wrapper<i32>, inner)
};
assert_eq!(&wrap as *const Wrapper<i32>, wrap_ptr);
}
}