#[cfg(memoffset_maybe_uninit)]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__let_base_ptr {
($name:ident, $type:path) => {
let uninit = $crate::mem::MaybeUninit::<$type>::uninit();
let $name = uninit.as_ptr();
};
}
#[cfg(not(memoffset_maybe_uninit))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__let_base_ptr {
($name:ident, $type:path) => {
let $name = $crate::mem::align_of::<$type>() as *const $type;
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__field_check {
($type:path, $field:tt) => {
let $type { $field: _, .. };
};
}
#[macro_export(local_inner_macros)]
macro_rules! offset_of {
($parent:path, $field:tt) => {{
_memoffset__field_check!($parent, $field);
_memoffset__let_base_ptr!(base_ptr, $parent);
#[allow(unused_unsafe)] let field_ptr = unsafe { &(*base_ptr).$field as *const _ };
let offset = (field_ptr as usize) - (base_ptr as usize);
offset
}};
}
#[cfg(test)]
mod tests {
#[test]
fn offset_simple() {
#[repr(C)]
struct Foo {
a: u32,
b: [u8; 2],
c: i64,
}
assert_eq!(offset_of!(Foo, a), 0);
assert_eq!(offset_of!(Foo, b), 4);
assert_eq!(offset_of!(Foo, c), 8);
}
#[test]
#[cfg(not(miri))] fn offset_simple_packed() {
#[repr(C, packed)]
struct Foo {
a: u32,
b: [u8; 2],
c: i64,
}
assert_eq!(offset_of!(Foo, a), 0);
assert_eq!(offset_of!(Foo, b), 4);
assert_eq!(offset_of!(Foo, c), 6);
}
#[test]
fn tuple_struct() {
#[repr(C)]
struct Tup(i32, i32);
assert_eq!(offset_of!(Tup, 0), 0);
assert_eq!(offset_of!(Tup, 1), 4);
}
#[test]
fn path() {
mod sub {
#[repr(C)]
pub struct Foo {
pub x: u32,
}
}
assert_eq!(offset_of!(sub::Foo, x), 0);
}
}