repr_offset/macros/
off_macro.rs

1/// Gets the [`FieldOffset`] for the passed in type and (possibly nested) field.
2///
3/// This macro allows accessing private fields, following the normal Rust rules around privacy.
4///
5/// This macro doesn't allow accessing fields from type parameters in generic functions,
6/// for that you can use `PUB_OFF`,
7/// but it can only get the [`FieldOffset`] for public fields.
8///
9/// # Type Argument
10///
11/// The type parameter can be passed as either:
12///
13/// - The path to the type (including the type name)
14///
15/// - A type with generic arguments
16///
17/// ### Caveats with path argument
18///
19/// With the path way of passing the type,
20/// if the type has all type parameters defaulted or is otherwise generic,
21/// there can be type inference issues.
22///
23/// To fix type inference issues with defaulted types,
24/// you can write `<>` (eg: `OFF!(for_examples::ReprC<>; a.b)`).
25///
26/// If a generic type is passed, and its arguments can be inferred from context,
27/// it's only necessary to specify the type of the accessed field,
28/// otherwise you need to write the full type.
29///
30/// # Example
31///
32/// ```rust
33/// use repr_offset::{
34///     for_examples::ReprC,
35///     OFF,
36///     FieldOffset, ROExtAcc,
37/// };
38///
39/// let this = ReprC {a: 3u8, b: 5u8, c: 8u8, d: 13u8};
40///
41/// // Passing the type as a path
42/// assert_eq!(OFF!(ReprC; a).get(&this), &this.a);
43///
44/// // Passing the type as a type
45/// assert_eq!(OFF!(ReprC<_, _, _, _>; b).get(&this), &this.b);
46///
47/// // Passing the type as a path
48/// assert_eq!(this.f_get(OFF!(ReprC; c)), &this.c);
49///
50/// // Passing the type as a type
51/// assert_eq!(this.f_get(OFF!(ReprC<_, _, _, _>; d)), &this.d);
52/// ```
53///
54/// [`FieldOffset`]: ./struct.FieldOffset.html
55#[macro_export]
56macro_rules! OFF{
57    (
58        $(:: $(@$leading:tt@)? )? $first:ident $(:: $trailing:ident)* ;
59        $($fields:tt).+
60    )=>{
61        $crate::__priv_OFF_path!(
62            [$(:: $($leading)?)? $first $(::$trailing)* ];
63            $($fields).+
64        )
65    };
66    ($type:ty; $($fields:tt).+ )=>{unsafe{
67        let marker =  $crate::utils::MakePhantomData::<$type>::FN_RET;
68
69        $crate::pmr::FOAssertStruct{
70            offset:{
71                use $crate::get_field_offset::r#unsafe::unsafe_get_private_field;
72                unsafe_get_private_field::<
73                    _,
74                    $crate::tstr::TS!($($fields),*)
75                >::__unsafe__GET_PRIVATE_FIELD_OFFSET
76            },
77            struct_: {
78                let _ = move || {
79                    let variable = $crate::pmr::loop_create_mutref(marker);
80                    #[allow(unused_unsafe)]
81                    unsafe{ let _ = (*variable) $(.$fields)*; }
82                };
83                marker
84            },
85        }.offset
86    }};
87}
88
89#[doc(hidden)]
90#[macro_export]
91macro_rules! __priv_OFF_path{
92    ([$($path:tt)*]; $($fields:tt).+)=>{
93        $crate::pmr::FOAssertStruct{
94            offset:{
95                use $crate::get_field_offset::r#unsafe::unsafe_get_private_field;
96                unsafe_get_private_field::<
97                    _,
98                    $crate::tstr::TS!($($fields),*)
99                >::__unsafe__GET_PRIVATE_FIELD_OFFSET
100            },
101            struct_: {
102                use $crate::utils::AsPhantomData;
103                let marker = $($path)*::__REPR_OFFSET_PHANTOMDATA_FN;
104                let _ = move || {
105                    let variable = $crate::pmr::loop_create_mutref(marker);
106                    #[allow(unused_unsafe)]
107                    unsafe{ let _ = (*variable) $(.$fields)*; }
108                };
109                marker
110            },
111        }.offset
112    }
113}
114
115/// Gets the [`FieldOffset`] for a (possibly nested) field, and an optionally passed in value.
116///
117/// The value argument is only necessary when the type that the fields are
118/// from can't be inferred.
119///
120/// # Example
121///
122/// ```rust
123/// use repr_offset::{
124///     for_examples::ReprC,
125///     off,
126///     FieldOffset, ROExtAcc,
127/// };
128///
129/// let this = ReprC {a: 3u8, b: 5u8, c: 8u8, d: 13u8};
130///
131/// // The value must be passed to the macro when you want to call
132/// // any method on the returned `FieldOffset`.
133/// assert_eq!(off!(this; a).get(&this), &this.a);
134///
135/// assert_eq!(this.f_get(off!(this; b)), &this.b);
136///
137/// assert_eq!(this.f_get(off!(c)), &this.c);
138/// assert_eq!(this.f_get(off!(d)), &this.d);
139/// ```
140///
141/// [`FieldOffset`]: ./struct.FieldOffset.html
142#[macro_export]
143macro_rules! off{
144    ($value:expr; $($fields:tt).+ )=>{
145        $crate::pmr::FOAssertStruct{
146            offset:{
147                use $crate::get_field_offset::r#unsafe::unsafe_get_private_field;
148                unsafe_get_private_field::<
149                    _,
150                    $crate::tstr::TS!($($fields),*)
151                >::__unsafe__GET_PRIVATE_FIELD_OFFSET
152            },
153            struct_: {
154                use $crate::utils::AsPhantomData;
155                let mut marker = $crate::pmr::PhantomData;
156                if false {
157                    let _ = $crate::utils::AsPhantomDataFn{
158                        reference: &$value,
159                        ty: marker,
160                    };
161                    let variable = $crate::pmr::loop_create_mutref(marker);
162                    #[allow(unused_unsafe)]
163                    unsafe{ let _ = (*variable) $(.$fields)*; }
164                }
165                marker
166            },
167        }.offset
168    };
169    ( $($fields:tt).+ )=>{{
170        let marker = $crate::pmr::PhantomData;
171
172        if false {
173            $crate::pmr::loop_create_fo(marker)
174        } else {
175            let _ = || {
176                let value = $crate::pmr::loop_create_val(marker);
177                #[allow(unused_unsafe)]
178                unsafe{ let _ = value $(.$fields)*; }
179            };
180
181            type __Key = $crate::tstr::TS!($($fields),*);
182
183            use $crate::get_field_offset::r#unsafe::unsafe_get_private_field;
184
185            unsafe_get_private_field::<_,__Key>::__unsafe__GET_PRIVATE_FIELD_OFFSET
186        }
187    }};
188}
189
190/// Gets the [`FieldOffset`] for a (possibly nested) public field,
191/// and an optionally passed in value.
192///
193/// This is the same as the [`off`] macro,
194/// except that this can't access private fields,
195/// and it allows accessing fields from type parameters in generic functions.
196///
197/// The value argument is only necessary when the type that the fields are
198/// from can't be inferred.
199///
200/// # Examples
201///
202/// ### Named Type
203///
204/// ```rust
205/// use repr_offset::{
206///     for_examples::ReprC,
207///     pub_off,
208///     FieldOffset, ROExtAcc,
209/// };
210///
211/// let this = ReprC {a: 3u8, b: 5u8, c: 8u8, d: 13u8};
212///
213/// // The value must be passed to the macro when you want to call
214/// // any method on the returned `FieldOffset`.
215/// assert_eq!(pub_off!(this; a).get(&this), &this.a);
216///
217/// assert_eq!(this.f_get(pub_off!(this; b)), &this.b);
218///
219/// assert_eq!(this.f_get(pub_off!(c)), &this.c);
220/// assert_eq!(this.f_get(pub_off!(d)), &this.d);
221/// ```
222///
223/// ### Accessing fields from type parameters
224///
225/// ```rust
226/// use repr_offset::{
227///     for_examples::ReprC,
228///     tstr::TS,
229///     pub_off,
230///     FieldOffset, GetPubFieldOffset, ROExtOps,
231/// };
232///
233/// let this = ReprC {a: 3u8, b: 5u8, c: 8u8, d: 13u8};
234///
235/// assertions(this);
236///
237/// fn assertions<T, A>(this: T)
238/// where
239///     T: GetPubFieldOffset<TS!(a), Type = u8, Alignment = A>,
240///     T: GetPubFieldOffset<TS!(b), Type = u8, Alignment = A>,
241///     T: GetPubFieldOffset<TS!(c), Type = u8, Alignment = A>,
242///     T: GetPubFieldOffset<TS!(d), Type = u8, Alignment = A>,
243///     T: ROExtOps<A>,
244/// {
245///     assert_eq!(this.f_get_copy(pub_off!(this; a)), 3);
246///     assert_eq!(this.f_get_copy(pub_off!(this; b)), 5);
247///     assert_eq!(this.f_get_copy(pub_off!(c)), 8);
248///     assert_eq!(this.f_get_copy(pub_off!(d)), 13);
249/// }
250/// ```
251///
252/// [`off`]: ./macro.off.html
253/// [`FieldOffset`]: ./struct.FieldOffset.html
254///
255#[macro_export]
256macro_rules! pub_off{
257    ($value:expr; $($fields:tt).+ )=>{
258        $crate::pmr::FOAssertStruct{
259            offset: $crate::pmr::GetPubFieldOffset::<$crate::tstr::TS!($($fields),*)>::OFFSET,
260            struct_: {
261                let mut marker = $crate::pmr::PhantomData;
262                if false {
263                    let _ = $crate::utils::AsPhantomDataFn{
264                        reference: &$value,
265                        ty: marker,
266                    };
267                }
268                marker
269            },
270        }.offset
271    };
272    ( $($fields:tt).+ )=>{
273        $crate::pmr::GetPubFieldOffset::<$crate::tstr::TS!($($fields),*)>::OFFSET
274    };
275}
276
277/// Gets the [`FieldOffset`] for the passed in type and (possibly nested) public field.
278///
279/// This is the same as the [`OFF`] macro,
280/// except that this can't access private fields,
281/// and it allows accessing fields from type parameters in generic functions.
282///
283/// # Examples
284///
285/// ### Named Type
286///
287/// ```rust
288/// use repr_offset::{
289///     for_examples::ReprC,
290///     PUB_OFF,
291///     FieldOffset, ROExtAcc,
292/// };
293///
294/// let this = ReprC {a: 3u8, b: 5u8, c: 8u8, d: 13u8};
295///
296/// // Passing the type as a path
297/// assert_eq!(PUB_OFF!(ReprC; a).get(&this), &this.a);
298///
299/// // Passing the type as a type
300/// assert_eq!(PUB_OFF!(ReprC<_, _, _, _>; b).get(&this), &this.b);
301///
302/// // Passing the type as a path
303/// assert_eq!(this.f_get(PUB_OFF!(ReprC; c)), &this.c);
304///
305/// // Passing the type as a type
306/// assert_eq!(this.f_get(PUB_OFF!(ReprC<_, _, _, _>; d)), &this.d);
307/// ```
308///
309///
310/// ### Accessing fields from type parameters
311///
312/// ```rust
313/// use repr_offset::{
314///     for_examples::ReprC,
315///     tstr::TS,
316///     PUB_OFF,
317///     FieldOffset, GetPubFieldOffset, ROExtOps,
318/// };
319///
320/// let this = ReprC {a: 3u8, b: 5u8, c: 8u8, d: 13u8};
321///
322/// assertions(this);
323///
324/// fn assertions<T, A>(this: T)
325/// where
326///     T: GetPubFieldOffset<TS!(a), Type = u8, Alignment = A>,
327///     T: GetPubFieldOffset<TS!(b), Type = u8, Alignment = A>,
328///     T: GetPubFieldOffset<TS!(c), Type = u8, Alignment = A>,
329///     T: GetPubFieldOffset<TS!(d), Type = u8, Alignment = A>,
330///     T: ROExtOps<A>,
331/// {
332///     assert_eq!(this.f_get_copy(PUB_OFF!(T; a)), 3);
333///     assert_eq!(this.f_get_copy(PUB_OFF!(T; b)), 5);
334///     assert_eq!(this.f_get_copy(PUB_OFF!(T; c)), 8);
335///     assert_eq!(this.f_get_copy(PUB_OFF!(T; d)), 13);
336/// }
337/// ```
338///
339/// [`OFF`]: ./macro.OFF.html
340/// [`FieldOffset`]: ./struct.FieldOffset.html
341#[macro_export]
342macro_rules! PUB_OFF{
343    (
344        $(:: $(@$leading:tt@)? )? $first:ident $(:: $trailing:ident)* ;
345        $($fields:tt).+
346    )=>{
347        $crate::__priv_ty_PUB_OFF_path!(
348            [$(:: $($leading)?)? $first $(::$trailing)* ];
349            $($fields).+
350        )
351    };
352    ($type:ty; $($fields:tt).+ )=>{
353        <$type as $crate::pmr::GetPubFieldOffset::<$crate::tstr::TS!($($fields),*)>>::OFFSET
354    };
355}
356
357#[doc(hidden)]
358#[macro_export]
359macro_rules! __priv_ty_PUB_OFF_path{
360    ([$($path:tt)*]; $($fields:tt).+)=>{
361        $crate::pmr::FOAssertStruct{
362            offset: $crate::pmr::GetPubFieldOffset::<$crate::tstr::TS!($($fields),*)>::OFFSET,
363            struct_: {
364                use $crate::utils::AsPhantomData;
365                $($path)*::__REPR_OFFSET_PHANTOMDATA_FN
366            }
367        }.offset
368    }
369}