1*f3518400SJunjie Mao // SPDX-License-Identifier: MIT 2*f3518400SJunjie Mao 3*f3518400SJunjie Mao /// This macro provides the same functionality as `core::mem::offset_of`, 4*f3518400SJunjie Mao /// except that only one level of field access is supported. The declaration 5*f3518400SJunjie Mao /// of the struct must be wrapped with `with_offsets! { }`. 6*f3518400SJunjie Mao /// 7*f3518400SJunjie Mao /// It is needed because `offset_of!` was only stabilized in Rust 1.77. 8*f3518400SJunjie Mao #[cfg(not(has_offset_of))] 9*f3518400SJunjie Mao #[macro_export] 10*f3518400SJunjie Mao macro_rules! offset_of { 11*f3518400SJunjie Mao ($Container:ty, $field:ident) => { 12*f3518400SJunjie Mao <$Container>::OFFSET_TO__.$field 13*f3518400SJunjie Mao }; 14*f3518400SJunjie Mao } 15*f3518400SJunjie Mao 16*f3518400SJunjie Mao /// A wrapper for struct declarations, that allows using `offset_of!` in 17*f3518400SJunjie Mao /// versions of Rust prior to 1.77 18*f3518400SJunjie Mao #[macro_export] 19*f3518400SJunjie Mao macro_rules! with_offsets { 20*f3518400SJunjie Mao // This method to generate field offset constants comes from: 21*f3518400SJunjie Mao // 22*f3518400SJunjie Mao // https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=10a22a9b8393abd7b541d8fc844bc0df 23*f3518400SJunjie Mao // 24*f3518400SJunjie Mao // used under MIT license with permission of Yandros aka Daniel Henry-Mantilla 25*f3518400SJunjie Mao ( 26*f3518400SJunjie Mao $(#[$struct_meta:meta])* 27*f3518400SJunjie Mao $struct_vis:vis 28*f3518400SJunjie Mao struct $StructName:ident { 29*f3518400SJunjie Mao $( 30*f3518400SJunjie Mao $(#[$field_meta:meta])* 31*f3518400SJunjie Mao $field_vis:vis 32*f3518400SJunjie Mao $field_name:ident : $field_ty:ty 33*f3518400SJunjie Mao ),* 34*f3518400SJunjie Mao $(,)? 35*f3518400SJunjie Mao } 36*f3518400SJunjie Mao ) => ( 37*f3518400SJunjie Mao #[cfg(not(has_offset_of))] 38*f3518400SJunjie Mao const _: () = { 39*f3518400SJunjie Mao struct StructOffsetsHelper<T>(std::marker::PhantomData<T>); 40*f3518400SJunjie Mao const END_OF_PREV_FIELD: usize = 0; 41*f3518400SJunjie Mao 42*f3518400SJunjie Mao // populate StructOffsetsHelper<T> with associated consts, 43*f3518400SJunjie Mao // one for each field 44*f3518400SJunjie Mao $crate::with_offsets! { 45*f3518400SJunjie Mao @struct $StructName 46*f3518400SJunjie Mao @names [ $($field_name)* ] 47*f3518400SJunjie Mao @tys [ $($field_ty ,)*] 48*f3518400SJunjie Mao } 49*f3518400SJunjie Mao 50*f3518400SJunjie Mao // now turn StructOffsetsHelper<T>'s consts into a single struct, 51*f3518400SJunjie Mao // applying field visibility. This provides better error messages 52*f3518400SJunjie Mao // than if offset_of! used StructOffsetsHelper::<T> directly. 53*f3518400SJunjie Mao pub 54*f3518400SJunjie Mao struct StructOffsets { 55*f3518400SJunjie Mao $( 56*f3518400SJunjie Mao $field_vis 57*f3518400SJunjie Mao $field_name: usize, 58*f3518400SJunjie Mao )* 59*f3518400SJunjie Mao } 60*f3518400SJunjie Mao impl $StructName { 61*f3518400SJunjie Mao pub 62*f3518400SJunjie Mao const OFFSET_TO__: StructOffsets = StructOffsets { 63*f3518400SJunjie Mao $( 64*f3518400SJunjie Mao $field_name: StructOffsetsHelper::<$StructName>::$field_name, 65*f3518400SJunjie Mao )* 66*f3518400SJunjie Mao }; 67*f3518400SJunjie Mao } 68*f3518400SJunjie Mao }; 69*f3518400SJunjie Mao ); 70*f3518400SJunjie Mao 71*f3518400SJunjie Mao ( 72*f3518400SJunjie Mao @struct $StructName:ident 73*f3518400SJunjie Mao @names [] 74*f3518400SJunjie Mao @tys [] 75*f3518400SJunjie Mao ) => (); 76*f3518400SJunjie Mao 77*f3518400SJunjie Mao ( 78*f3518400SJunjie Mao @struct $StructName:ident 79*f3518400SJunjie Mao @names [$field_name:ident $($other_names:tt)*] 80*f3518400SJunjie Mao @tys [$field_ty:ty , $($other_tys:tt)*] 81*f3518400SJunjie Mao ) => ( 82*f3518400SJunjie Mao #[allow(non_local_definitions)] 83*f3518400SJunjie Mao #[allow(clippy::modulo_one)] 84*f3518400SJunjie Mao impl StructOffsetsHelper<$StructName> { 85*f3518400SJunjie Mao #[allow(nonstandard_style)] 86*f3518400SJunjie Mao const $field_name: usize = { 87*f3518400SJunjie Mao const ALIGN: usize = std::mem::align_of::<$field_ty>(); 88*f3518400SJunjie Mao const TRAIL: usize = END_OF_PREV_FIELD % ALIGN; 89*f3518400SJunjie Mao END_OF_PREV_FIELD + (if TRAIL == 0 { 0usize } else { ALIGN - TRAIL }) 90*f3518400SJunjie Mao }; 91*f3518400SJunjie Mao } 92*f3518400SJunjie Mao const _: () = { 93*f3518400SJunjie Mao const END_OF_PREV_FIELD: usize = 94*f3518400SJunjie Mao StructOffsetsHelper::<$StructName>::$field_name + 95*f3518400SJunjie Mao std::mem::size_of::<$field_ty>() 96*f3518400SJunjie Mao ; 97*f3518400SJunjie Mao $crate::with_offsets! { 98*f3518400SJunjie Mao @struct $StructName 99*f3518400SJunjie Mao @names [$($other_names)*] 100*f3518400SJunjie Mao @tys [$($other_tys)*] 101*f3518400SJunjie Mao } 102*f3518400SJunjie Mao }; 103*f3518400SJunjie Mao ); 104*f3518400SJunjie Mao } 105*f3518400SJunjie Mao 106*f3518400SJunjie Mao #[cfg(test)] 107*f3518400SJunjie Mao mod tests { 108*f3518400SJunjie Mao use crate::offset_of; 109*f3518400SJunjie Mao 110*f3518400SJunjie Mao #[repr(C)] 111*f3518400SJunjie Mao struct Foo { 112*f3518400SJunjie Mao a: u16, 113*f3518400SJunjie Mao b: u32, 114*f3518400SJunjie Mao c: u64, 115*f3518400SJunjie Mao d: u16, 116*f3518400SJunjie Mao } 117*f3518400SJunjie Mao 118*f3518400SJunjie Mao #[repr(C)] 119*f3518400SJunjie Mao struct Bar { 120*f3518400SJunjie Mao pub a: u16, 121*f3518400SJunjie Mao pub b: u64, 122*f3518400SJunjie Mao c: Foo, 123*f3518400SJunjie Mao d: u64, 124*f3518400SJunjie Mao } 125*f3518400SJunjie Mao 126*f3518400SJunjie Mao crate::with_offsets! { 127*f3518400SJunjie Mao #[repr(C)] 128*f3518400SJunjie Mao struct Bar { 129*f3518400SJunjie Mao pub a: u16, 130*f3518400SJunjie Mao pub b: u64, 131*f3518400SJunjie Mao c: Foo, 132*f3518400SJunjie Mao d: u64, 133*f3518400SJunjie Mao } 134*f3518400SJunjie Mao } 135*f3518400SJunjie Mao 136*f3518400SJunjie Mao #[repr(C)] 137*f3518400SJunjie Mao pub struct Baz { 138*f3518400SJunjie Mao b: u32, 139*f3518400SJunjie Mao a: u8, 140*f3518400SJunjie Mao } 141*f3518400SJunjie Mao crate::with_offsets! { 142*f3518400SJunjie Mao #[repr(C)] 143*f3518400SJunjie Mao pub struct Baz { 144*f3518400SJunjie Mao b: u32, 145*f3518400SJunjie Mao a: u8, 146*f3518400SJunjie Mao } 147*f3518400SJunjie Mao } 148*f3518400SJunjie Mao 149*f3518400SJunjie Mao #[test] test_offset_of()150*f3518400SJunjie Mao fn test_offset_of() { 151*f3518400SJunjie Mao const OFFSET_TO_C: usize = offset_of!(Bar, c); 152*f3518400SJunjie Mao 153*f3518400SJunjie Mao assert_eq!(offset_of!(Bar, a), 0); 154*f3518400SJunjie Mao assert_eq!(offset_of!(Bar, b), 8); 155*f3518400SJunjie Mao assert_eq!(OFFSET_TO_C, 16); 156*f3518400SJunjie Mao assert_eq!(offset_of!(Bar, d), 40); 157*f3518400SJunjie Mao 158*f3518400SJunjie Mao assert_eq!(offset_of!(Baz, b), 0); 159*f3518400SJunjie Mao assert_eq!(offset_of!(Baz, a), 4); 160*f3518400SJunjie Mao } 161*f3518400SJunjie Mao } 162