My proposed library-only implementation (to live in libcore
):
macro_rules! offset_of {
($Struct:path, $field:ident) => ({
// Using a separate function to minimize unhygienic hazards
// (e.g. unsafety of #[repr(packed)] field borrows).
// Uncomment `const` when `const fn`s can juggle pointers.
/*const*/ fn offset() -> usize {
let u = $crate::mem::MaybeUninit::<$Struct>::uninitialized();
// Use pattern-matching to avoid accidentally going through Deref.
let &$Struct { $field: ref f, .. } = unsafe { &*u.as_ptr() };
let o = (f as *const _ as usize).wrapping_sub(&u as *const _ as usize);
// Triple check that we are within `u` still.
assert!((0..=$crate::mem::size_of_val(&u)).contains(&o));
o
}
offset()
})
}
Also to quote myself on implementing offset_of!
like asm!
:
I dislike having macros that expand to builtins that cannot be written with other syntax
(I really hope one day we can solve the asm
issue - const
generics + intrinsics is probably the way to go)