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}