repr_offset/macros/
unsafe_struct_field_offsets.rs

1/// Declares a sequence of associated constants with the offsets of the listed fields,
2/// and implements the [`GetFieldOffset`] trait.
3///
4/// # Safety
5///
6/// Callers must ensure that:
7///
8/// - The type that the offsets are for is a `#[repr(C)]` struct.
9///
10/// - All field types are listed,in declaration order.
11///
12/// - The `alignment` parameter is [`Unaligned`] if the struct is `#[repr(C,packed)]`,
13/// and [`Aligned`] if it's not.
14///
15/// # Parameters
16///
17/// ### `Self`
18///
19/// The optional `Self` parameter overrides which struct the [`FieldOffset`] constants
20/// (that this outputs) are an offset inside of.
21///
22/// Note that passing the this parameter unconditionally causes the type
23/// not to implement [`GetFieldOffset`].
24///
25/// ### `alignment`
26///
27/// The `alignment` parameter can be either [`Aligned`] or [`Unaligned`],
28/// and describes whether the fields are aligned or potentially unaligned,
29/// changing how fields are accessed in [`FieldOffset`] methods.
30///
31/// ### `usize_offsets`
32///
33/// The optional `usize_offsets` parameter determines whether type of the
34/// generated constants is [`FieldOffset`] or `usize`.<br>
35///
36/// The valid values for this parameter are:
37/// - (not passing this parameter): The constants are [`FieldOffset`]s.
38/// - `false`: The constants are [`FieldOffset`]s.
39/// - `true`: The constants are `usize`s.
40///
41/// ### `impl_GetFieldOffset`
42///
43/// The optional `impl_GetFieldOffset` parameter determines whether `$self`
44/// implements the [`GetFieldOffset`] trait,
45/// which allows getting the [`FieldOffset`] for each field using the
46/// [`OFF`](./macro.OFF.html),
47/// [`off`](./macro.off.html),
48/// [`PUB_OFF`](./macro.PUB_OFF.html), and
49/// [`pub_off`](./macro.pub_off.html) macros.
50///
51/// The valid values for this parameter are:
52/// - (not passing this parameter): Implements [`GetFieldOffset`].
53/// - `false`: Does not implement [`GetFieldOffset`].
54/// - `true`: Implements [`GetFieldOffset`].
55///
56/// Note that passing the `Self` parameter unconditionally causes the type
57/// not to implement [`GetFieldOffset`].
58///
59/// # Examples
60///
61/// ### Syntax example
62///
63/// This demonstrates the macro being used with all of the syntax.
64///
65/// ```rust
66/// use repr_offset::{unsafe_struct_field_offsets, Aligned};
67///
68/// #[repr(C)]
69/// struct Bar<T: Copy, U>(T,U)
70/// where U: Clone;
71///
72/// unsafe_struct_field_offsets!{
73///     // Optional parameter.
74///     // Generic parameters from the impl block can be used here.
75///     Self = Bar<T, U>,
76///
77///     alignment =  Aligned,
78///
79///     // Optional parameter.
80///     usize_offsets = false,
81///
82///     // Optional parameter.
83///     impl_GetFieldOffset = false,
84///
85///     impl[T: Copy, U] Bar<T, U>
86///     where[ U: Clone ]
87///     {
88///         pub const OFFSET_0, 0: T;
89///         pub const OFFSET_1, 1: U;
90///     }
91/// }
92///
93/// ```
94///
95/// ### Unaligned struct example
96///
97/// This example demonstrates how you can replace fields in a packed struct,
98/// as well as getting a raw pointer to a field,
99/// using both [`FieldOffset`] methods, and extension traits from the [`ext`] module
100///
101/// ```rust
102/// use repr_offset::{
103///     unsafe_struct_field_offsets,
104///     off,
105///     ROExtAcc, ROExtOps, Unaligned,
106/// };
107///
108/// // Replacing the table field
109/// {
110///     let mut bar = Bar{ mugs: 3, bottles: 5, table: "wooden".to_string() };
111///    
112///     assert_eq!( replace_table_a(&mut bar, "metallic".to_string()), "wooden".to_string());
113///     assert_eq!( replace_table_b(&mut bar, "granite".to_string()), "metallic".to_string());
114///     assert_eq!( replace_table_b(&mut bar, "carbonite".to_string()), "granite".to_string());
115///     
116///     fn replace_table_a(this: &mut Bar, replacement: String)-> String{
117///         Bar::OFFSET_TABLE.replace_mut(this, replacement)
118///     }
119///    
120///     fn replace_table_b(this: &mut Bar, replacement: String)-> String{
121///         this.f_replace(off!(table), replacement)
122///     }
123/// }
124///
125/// // Getting raw pointers to fields
126/// unsafe {
127///     let bar = Bar{ mugs: 3, bottles: 5, table: "wooden".to_string() };
128///
129///     assert_eq!(get_mugs_ptr(&bar).read_unaligned(), 3);
130///
131///     assert_eq!(get_bottles_ptr(&bar).read_unaligned(), 5);
132///
133///     fn get_mugs_ptr(this: &Bar) -> *const u32 {
134///         Bar::OFFSET_MUGS.get_ptr(this)
135///     }
136///    
137///     fn get_bottles_ptr(this: &Bar) -> *const u16 {
138///         this.f_get_ptr(off!(bottles))
139///     }
140/// }
141///
142///
143///
144/// #[repr(C,packed)]
145/// struct Bar{
146///     mugs: u32,
147///     bottles: u16,
148///     table: String,
149/// }
150///
151/// unsafe_struct_field_offsets!{
152///     alignment =  Unaligned,
153///
154///     impl[] Bar {
155///         pub const OFFSET_MUGS, mugs: u32;
156///         pub const OFFSET_BOTTLES, bottles: u16;
157///         pub const OFFSET_TABLE, table: String;
158///     }
159/// }
160///
161/// ```
162///
163/// [`Aligned`]: ./alignment/struct.Aligned.html
164/// [`Unaligned`]: ./alignment/struct.Unaligned.html
165/// [`FieldOffset`]: ./struct.FieldOffset.html
166/// [`GetFieldOffset`]: ./get_field_offset/trait.GetFieldOffset.html
167///
168/// [`FieldOffset`]: ./struct.FieldOffset.html
169/// [`ext`]: ./ext/index.html
170///
171#[macro_export]
172macro_rules! unsafe_struct_field_offsets{
173    (
174        $( Self = $Self:ty, )?
175        alignment =  $alignment:ty,
176        $( usize_offsets = $usize_offsets:ident,)?
177        $( impl_GetFieldOffset = $impl_gfo:ident,)?
178
179        $(#[$impl_attr:meta])*
180        impl[ $($impl_params:tt)* ] $self:ty
181        $(where [ $($where:tt)* ])?
182        {
183            $(
184                $(#[$const_attr:meta])*
185                $( pub $(($($inn:tt)*))? )?
186                const $offset:ident, $field_ident:tt: $field_ty:ty;
187            )*
188        }
189    )=>{
190        $(#[$impl_attr])*
191        impl<$($impl_params)*>  $self
192        $(where $($where)*)?
193        {
194            $crate::_priv_usfoi!{
195                @setup
196                params(
197                    Self( $($Self,)? Self, )
198                    alignment =  $alignment,
199                    usize_offsets($($usize_offsets,)? false,)
200                    impl_GetFieldOffset( $(false, $Self:ty )? $($impl_gfo,)? true,)
201
202                    $(#[$impl_attr])*
203                    impl[ $($impl_params)* ] $self
204                    where [ $($($where)*)? ]
205                )
206                previous(
207                    (
208                        $crate::_priv_usfoi!(
209                            @initial
210                            $($usize_offsets)?, 0,
211                        ),
212                        ()
213                    ),
214                    $((Self::$offset, $field_ty),)*
215                )
216                offsets($(
217                    $(#[$const_attr])*
218                    ($( pub $(($($inn)*))? )?) $offset, $field_ident: $field_ty;
219                )*)
220            }
221        }
222
223        $crate::expand_if_true!{[ $(false $Self:ty )? $($impl_gfo)? true,]
224            $(#[$impl_attr])*
225            unsafe impl<$($impl_params)*> $crate::pmr::ImplsGetFieldOffset for $self
226            $(where $($where)*)?
227            {}
228        }
229    };
230}
231
232#[doc(hidden)]
233#[macro_export]
234macro_rules! _priv_usfoi{
235    (@setup
236        params $params:tt
237        previous( $($prev:tt)* )
238        offsets( $($offsets:tt)* )
239    )=>{
240        $crate::_priv_usfoi!{
241            params $params
242            params $params
243            previous( $($prev)* )
244            offsets( $($offsets)* )
245        }
246    };
247    (@initial true, $value:expr, )=>{
248        $value
249    };
250    (@initial $(false)?, $value:expr, )=>{
251        $crate::FieldOffset::<_,(),$crate::Aligned>::new($value)
252    };
253    (@ty true, $Self:ty, $next_ty:ty, $alignment:ty )=>{
254        usize
255    };
256    (@ty false, $Self:ty, $next_ty:ty, $alignment:ty )=>{
257        $crate::FieldOffset<$Self,$next_ty,$alignment>
258    };
259    (@val true, $Self:ty, $prev:expr, $prev_ty:ty, $next_ty:ty )=>{
260        $crate::offset_calc::next_field_offset::<$Self, $prev_ty, $next_ty>( $prev )
261    };
262    (@val false, $Self:ty, $prev:expr, $prev_ty:ty, $next_ty:ty )=>{
263        $prev.next_field_offset()
264    };
265    (@FieldOffsetWithVis false, $expr:expr)=>{
266        $crate::pmr::FieldOffsetWithVis::from_fieldoffset($expr)
267    };
268    (@FieldOffsetWithVis true, $expr:expr)=>{unsafe{
269        $crate::pmr::FieldOffsetWithVis::new($expr)
270    }};
271
272    (
273        params $params:tt
274        params(
275            Self( $Self:ty, $($_ignored_Self:ty,)? )
276            alignment =  $alignment:ty,
277            usize_offsets($usize_offsets:ident, $($_ignored_io:ident,)? )
278            impl_GetFieldOffset($impl_gfo:ident, $($_ignored_impl_gfo:tt)*)
279
280            $(#[$impl_attr:meta])*
281            impl[ $($impl_params:tt)* ] $self:ty
282            where [ $($where:tt)* ]
283        )
284        previous( ($prev_offset:expr, $prev_ty:ty), $($prev:tt)* )
285        offsets(
286            $(#[$const_attr:meta])*
287            ($($vis:tt)*) $offset:ident, $field_ident:tt : $field_ty:ty;
288            $($next:tt)*
289        )
290    )=>{
291        $(#[$const_attr])*
292        $($vis)* const $offset:
293            $crate::_priv_usfoi!(
294                @ty $usize_offsets, $Self, $field_ty, $alignment
295            )
296        = unsafe{
297            $crate::_priv_impl_getfieldoffset!{
298                impl_GetFieldOffset = $impl_gfo,
299                Self = $Self,
300                alignment = $alignment,
301                usize_offsets = $usize_offsets,
302
303                $(#[$impl_attr])*
304                impl[ $($impl_params)* ] $self
305                where [ $($where)* ]
306
307                (($($vis)*), $offset, $field_ident : $field_ty)
308            }
309
310            $crate::_priv_usfoi!(
311                @val
312                $usize_offsets, $Self, $prev_offset, $prev_ty, $field_ty
313            )
314        };
315
316        $crate::_priv_usfoi!{
317            params $params
318            params $params
319            previous($($prev)*)
320            offsets($($next)*)
321        }
322    };
323    (
324        params $params:tt
325        params $params2:tt
326        previous($($prev:tt)*)
327        offsets()
328    )=>{};
329}
330
331#[doc(hidden)]
332#[macro_export]
333macro_rules! _priv_impl_getfieldoffset{
334    (
335        impl_GetFieldOffset = true,
336
337        Self = $Self:ty,
338        alignment = $alignment:ty,
339        usize_offsets = $usize_offsets:ident,
340
341        $(#[$impl_attr:meta])*
342        impl[ $($impl_params:tt)* ] $self:ty
343        where [ $($where:tt)* ]
344
345        (($($vis:tt)*), $offset:ident, $field_ident:tt : $field_ty:ty)
346
347    )=>{
348        type __Key = $crate::tstr::TS!($field_ident);
349        type __Privacy = $crate::_priv_get_privacy!($($vis)*);
350
351        $crate::_priv_doc_attribute!{
352            [$($vis)*]
353            $(#[$impl_attr])*
354            unsafe impl<$($impl_params)*> $crate::pmr::GetFieldOffset<__Key> for $self
355            where $($where)*
356            {
357                type Type = $field_ty;
358                type Alignment = $alignment;
359                type Privacy = __Privacy;
360
361                const OFFSET_WITH_VIS: $crate::pmr::FieldOffsetWithVis<
362                    Self,
363                    __Privacy,
364                    __Key,
365                    Self::Type,
366                    $alignment,
367                > = unsafe{
368                    $crate::_priv_usfoi!( @FieldOffsetWithVis $usize_offsets, Self::$offset)
369                };
370            }
371        }
372    };
373    (impl_GetFieldOffset = false $($rem:tt)*)=>[];
374}
375
376#[doc(hidden)]
377#[macro_export]
378macro_rules! _priv_get_privacy {
379    (pub) => {
380        $crate::privacy::IsPublic
381    };
382    ($($vis:tt)*) => {
383        $crate::privacy::IsPrivate
384    };
385}
386
387#[doc(hidden)]
388#[macro_export]
389macro_rules! _priv_doc_attribute {
390    ([pub] $($item:tt)*) => {
391        $($item)*
392    };
393    ([$($vis:tt)*] $($item:tt)*) => {
394        #[doc(hidden)]
395        $($item)*
396    };
397}
398
399#[doc(hidden)]
400#[macro_export]
401macro_rules! expand_if_true {
402    ([true $($ignore:tt)*] $($item:tt)*) => {
403        $($item)*
404    };
405    ([false $($ignore:tt)*] $($item:tt)*) => {};
406}