#[macro_export]
macro_rules! offset_of {
($($tt:tt)*) => {
$crate::__offset_of2!([] $($tt)*)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __offset_of2 {
([$($ty:tt)*] . $($field:tt)*) => {
::core::mem::offset_of!($($ty)*, $($field)*)
};
([$($ty:tt)*] $tt:tt $($tail:tt)*) => {
$crate::__offset_of2!([$($ty)* $tt] $($tail)*)
};
([$($ty:tt)*]) => {
compile_error!("missing field access")
};
}
#[macro_export]
macro_rules! span_of {
($($tt:tt)*) => {
$crate::__span_of!([] $($tt)*)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __span_of {
([$($ty:tt)*] . $($field:ident)?) => {const {
type Ty = $($ty)*;
let Ty { $($field)?: _, .. };
let uninit = ::core::mem::MaybeUninit::<Ty>::uninit();
let uninit_ptr = uninit.as_ptr();
#[allow(unused_unsafe)]
unsafe {
let field_ptr = ::core::ptr::addr_of!((*uninit_ptr).$($field)?);
let start = (field_ptr as *const u8).offset_from(uninit_ptr as *const u8) as usize;
let end = (field_ptr.offset(1) as *const u8).offset_from(uninit_ptr as *const u8) as usize;
start..end
}
}};
([$($ty:tt)*] . $($field:tt)?) => {
compile_error!("offset of tuple field not supported")
};
([$($ty:tt)*] $tt:tt $($tail:tt)*) => {
$crate::__span_of!([$($ty)* $tt] $($tail)*)
};
([$($ty:tt)*]) => {
compile_error!("missing field access")
};
}
#[test]
fn nested_fields() {
#[repr(C)]
struct Foo<T> { byte: u8, value: T }
assert_eq!(offset_of!(Foo<i32>.value), 4);
assert_eq!(span_of!(Foo<i32>.value), 4..8);
}
#[cfg(doc)]
fn deref_protection() {}