#[cfg(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: *const $type = uninit.as_ptr();
};
}
#[cfg(not(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;
};
}
#[cfg(feature = "unstable_const")]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset_offset_from {
($field:expr, $base:expr) => {
unsafe { ($field as *const u8).offset_from($base as *const u8) as usize }
};
}
#[cfg(not(feature = "unstable_const"))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset_offset_from {
($field:expr, $base:expr) => {
($field as usize) - ($base as usize)
};
}
#[macro_export(local_inner_macros)]
macro_rules! offset_of {
($parent:path, $field:tt) => {{
_memoffset__let_base_ptr!(base_ptr, $parent);
let field_ptr = raw_field!(base_ptr, $parent, $field);
_memoffset_offset_from!(field_ptr, base_ptr)
}};
}
#[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_attr(miri, ignore)] 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);
}
#[test]
fn inside_generic_method() {
struct Pair<T, U>(T, U);
fn foo<T, U>(_: Pair<T, U>) -> usize {
offset_of!(Pair<T, U>, 1)
}
assert_eq!(foo(Pair(0, 0)), 4);
}
#[test]
fn test_raw_field() {
#[repr(C)]
struct Foo {
a: u32,
b: [u8; 2],
c: i64,
}
let f: Foo = Foo {
a: 0,
b: [0, 0],
c: 0,
};
let f_ptr = &f as *const _;
assert_eq!(f_ptr as usize + 0, raw_field!(f_ptr, Foo, a) as usize);
assert_eq!(f_ptr as usize + 4, raw_field!(f_ptr, Foo, b) as usize);
assert_eq!(f_ptr as usize + 8, raw_field!(f_ptr, Foo, c) as usize);
}
#[cfg(feature = "unstable_const")]
#[test]
fn const_offset() {
#[repr(C)]
struct Foo {
a: u32,
b: [u8; 2],
c: i64,
}
assert_eq!([0; offset_of!(Foo, b)].len(), 4);
}
#[cfg(feature = "unstable_const")]
#[test]
fn const_fn_offset() {
const fn test_fn() -> usize {
#[repr(C)]
struct Foo {
a: u32,
b: [u8; 2],
c: i64,
}
offset_of!(Foo, b)
}
assert_eq!([0; test_fn()].len(), 4);
}
}