xref: /openbmc/qemu/rust/qemu-api/src/offset_of.rs (revision f3518400)
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