1#[cfg(maybe_uninit)]
24#[macro_export]
25#[doc(hidden)]
26macro_rules! _memoffset__let_base_ptr {
27 ($name:ident, $type:ty) => {
28 let uninit = $crate::__priv::mem::MaybeUninit::<$type>::uninit();
34 let $name: *const $type = uninit.as_ptr();
35 };
36}
37#[cfg(not(maybe_uninit))]
38#[macro_export]
39#[doc(hidden)]
40macro_rules! _memoffset__let_base_ptr {
41 ($name:ident, $type:ty) => {
42 let $name = $crate::__priv::mem::align_of::<$type>() as *const $type;
45 };
46}
47
48#[cfg(feature = "unstable_const")]
50#[macro_export]
51#[doc(hidden)]
52macro_rules! _memoffset_offset_from_unsafe {
53 ($field:expr, $base:expr) => {{
54 let field = $field; let base = $base; unsafe { (field as *const u8).offset_from(base as *const u8) as usize }
59 }};
60}
61#[cfg(not(feature = "unstable_const"))]
62#[macro_export]
63#[doc(hidden)]
64macro_rules! _memoffset_offset_from_unsafe {
65 ($field:expr, $base:expr) => {
66 ($field as usize) - ($base as usize)
68 };
69}
70
71#[macro_export(local_inner_macros)]
90macro_rules! offset_of {
91 ($parent:path, $field:tt) => {{
92 _memoffset__let_base_ptr!(base_ptr, $parent);
94 let field_ptr = raw_field!(base_ptr, $parent, $field);
96 _memoffset_offset_from_unsafe!(field_ptr, base_ptr)
98 }};
99}
100
101#[cfg(tuple_ty)]
112#[macro_export(local_inner_macros)]
113macro_rules! offset_of_tuple {
114 ($parent:ty, $field:tt) => {{
115 _memoffset__let_base_ptr!(base_ptr, $parent);
117 let field_ptr = raw_field_tuple!(base_ptr, $parent, $field);
119 _memoffset_offset_from_unsafe!(field_ptr, base_ptr)
121 }};
122}
123
124#[cfg(test)]
125mod tests {
126 #[test]
127 fn offset_simple() {
128 #[repr(C)]
129 struct Foo {
130 a: u32,
131 b: [u8; 2],
132 c: i64,
133 }
134
135 assert_eq!(offset_of!(Foo, a), 0);
136 assert_eq!(offset_of!(Foo, b), 4);
137 assert_eq!(offset_of!(Foo, c), 8);
138 }
139
140 #[test]
141 #[cfg_attr(miri, ignore)] fn offset_simple_packed() {
143 #[repr(C, packed)]
144 struct Foo {
145 a: u32,
146 b: [u8; 2],
147 c: i64,
148 }
149
150 assert_eq!(offset_of!(Foo, a), 0);
151 assert_eq!(offset_of!(Foo, b), 4);
152 assert_eq!(offset_of!(Foo, c), 6);
153 }
154
155 #[test]
156 fn tuple_struct() {
157 #[repr(C)]
158 struct Tup(i32, i32);
159
160 assert_eq!(offset_of!(Tup, 0), 0);
161 assert_eq!(offset_of!(Tup, 1), 4);
162 }
163
164 #[test]
165 fn path() {
166 mod sub {
167 #[repr(C)]
168 pub struct Foo {
169 pub x: u32,
170 }
171 }
172
173 assert_eq!(offset_of!(sub::Foo, x), 0);
174 }
175
176 #[test]
177 fn inside_generic_method() {
178 struct Pair<T, U>(T, U);
179
180 fn foo<T, U>(_: Pair<T, U>) -> usize {
181 offset_of!(Pair<T, U>, 1)
182 }
183
184 assert_eq!(foo(Pair(0, 0)), 4);
185 }
186
187 #[cfg(tuple_ty)]
188 #[test]
189 fn test_tuple_offset() {
190 let f = (0i32, 0.0f32, 0u8);
191 let f_ptr = &f as *const _;
192 let f1_ptr = &f.1 as *const _;
193
194 assert_eq!(
195 f1_ptr as usize - f_ptr as usize,
196 offset_of_tuple!((i32, f32, u8), 1)
197 );
198 }
199
200 #[test]
201 fn test_raw_field() {
202 #[repr(C)]
203 struct Foo {
204 a: u32,
205 b: [u8; 2],
206 c: i64,
207 }
208
209 let f: Foo = Foo {
210 a: 0,
211 b: [0, 0],
212 c: 0,
213 };
214 let f_ptr = &f as *const _;
215 assert_eq!(f_ptr as usize + 0, raw_field!(f_ptr, Foo, a) as usize);
216 assert_eq!(f_ptr as usize + 4, raw_field!(f_ptr, Foo, b) as usize);
217 assert_eq!(f_ptr as usize + 8, raw_field!(f_ptr, Foo, c) as usize);
218 }
219
220 #[cfg(tuple_ty)]
221 #[test]
222 fn test_raw_field_tuple() {
223 let t = (0u32, 0u8, false);
224 let t_ptr = &t as *const _;
225 let t_addr = t_ptr as usize;
226
227 assert_eq!(
228 &t.0 as *const _ as usize - t_addr,
229 raw_field_tuple!(t_ptr, (u32, u8, bool), 0) as usize - t_addr
230 );
231 assert_eq!(
232 &t.1 as *const _ as usize - t_addr,
233 raw_field_tuple!(t_ptr, (u32, u8, bool), 1) as usize - t_addr
234 );
235 assert_eq!(
236 &t.2 as *const _ as usize - t_addr,
237 raw_field_tuple!(t_ptr, (u32, u8, bool), 2) as usize - t_addr
238 );
239 }
240
241 #[cfg(feature = "unstable_const")]
242 #[test]
243 fn const_offset() {
244 #[repr(C)]
245 struct Foo {
246 a: u32,
247 b: [u8; 2],
248 c: i64,
249 }
250
251 assert_eq!([0; offset_of!(Foo, b)].len(), 4);
252 }
253
254 #[cfg(feature = "unstable_const")]
255 #[test]
256 fn const_offset_interior_mutable() {
257 #[repr(C)]
258 struct Foo {
259 a: u32,
260 b: core::cell::Cell<u32>,
261 }
262
263 assert_eq!([0; offset_of!(Foo, b)].len(), 4);
264 }
265
266 #[cfg(feature = "unstable_const")]
267 #[test]
268 fn const_fn_offset() {
269 const fn test_fn() -> usize {
270 #[repr(C)]
271 struct Foo {
272 a: u32,
273 b: [u8; 2],
274 c: i64,
275 }
276
277 offset_of!(Foo, b)
278 }
279
280 assert_eq!([0; test_fn()].len(), 4);
281 }
282}