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}