repr_offset/struct_field_offset.rs
1// All the uses of usize as isize are for struct offsets,
2// which as far as I am aware are all smaller than isize::MAX
3#![allow(clippy::ptr_offset_with_cast)]
4
5#[macro_use]
6mod impl_fieldoffset_methods;
7
8mod repr_offset_ext_impls;
9
10////////////////////////////////////////////////////////////////////////////////
11
12use crate::{
13 alignment::{Aligned, Alignment, CombineAlignment, CombineAlignmentOut, Unaligned},
14 offset_calc::GetNextFieldOffset,
15 utils::Mem,
16};
17
18use crate::get_field_offset::FieldOffsetWithVis;
19
20use core::{
21 fmt::{self, Debug},
22 marker::PhantomData,
23 ops::Add,
24};
25
26/// Represents the offset of a (potentially nested) field inside a type.
27///
28/// # Type parameters
29///
30/// The type parameters are:
31///
32/// - `S`(for `struct`): the struct that contains the field that this is an offset for.
33///
34/// - `F`(for field): the type of the field this is an offset for.
35///
36/// - `A`(for alignment):
37/// Is [`Aligned`] if this offset is for [an aligned field](#alignment-guidelines)
38/// within the `S` struct,
39/// [`Unaligned`] if it is for [an unaligned field](#alignment-guidelines).
40/// This changes which methods are available,and the implementation of many of them.
41///
42/// # Safety
43///
44/// ### Alignment
45///
46/// All the unsafe methods for `FieldOffset<_, _, Aligned>`
47/// that move/copy the field require that
48/// the passed in pointers are aligned,
49/// while the ones for `FieldOffset<_, _, Unaligned>` do not.
50///
51/// Because passing unaligned pointers to `FieldOffset<_, _, Aligned>` methods
52/// causes undefined behavior,
53/// you must be careful when accessing a nested field in `#[repr(C, packed)]` structs.
54///
55/// For an example of how to correctly access nested fields inside of
56/// `#[repr(C, packed)]` structs [look here](#nested-field-in-packed).
57///
58/// <span id="alignment-guidelines"></span>
59/// # Field alignment guidelines
60///
61/// A non-nested field is:
62///
63/// - Aligned: if the type that contains the field is
64/// `#[repr(C)]`/`#[repr(C, align(...))]`/`#[repr(transparent)]`.
65///
66/// - Unaligned: if the type that contains the field is `#[repr(C, packed(....))]`,
67/// and the packing is smaller than the alignment of the field type.<br>
68/// Note that type alignment can vary across platforms,
69/// so `FieldOffset<S, F, Unaligned>`(as opposed to `FieldOffset<S, F, Aligned>`)
70/// is safest when `S` is a `#[repr(C, packed)]` type.
71///
72/// A nested field is unaligned if any field in the chain of field accesses to the
73/// nested field (ie: `foo` and `bar` and `baz` in `foo.bar.baz`)
74/// is unaligned according to the rules for non-nested fields described in this section.
75///
76///
77/// # Examples
78///
79/// ### No Macros
80///
81/// This example demonstrates how you can construct `FieldOffset` without macros.
82///
83/// You can use the [`ReprOffset`] derive macro or [`unsafe_struct_field_offsets`] macro
84/// to construct the constants more conveniently (and in a less error-prone way).
85///
86/// ```rust
87/// # #![deny(safe_packed_borrows)]
88/// use repr_offset::{Aligned, FieldOffset};
89///
90/// use std::mem;
91///
92///
93/// fn main(){
94/// let mut foo = Foo{ first: 3u16, second: 5, third: None };
95///
96/// *Foo::OFFSET_FIRST.get_mut(&mut foo) = 13;
97/// *Foo::OFFSET_SECOND.get_mut(&mut foo) = 21;
98/// *Foo::OFFSET_THIRD.get_mut(&mut foo) = Some(34);
99///
100/// assert_eq!( foo, Foo{ first: 13, second: 21, third: Some(34) } );
101/// }
102///
103///
104/// #[repr(C)]
105/// #[derive(Debug,PartialEq)]
106/// struct Foo<T>{
107/// first: T,
108/// second: u32,
109/// third: Option<T>,
110/// }
111///
112/// impl<T> Foo<T>{
113/// const OFFSET_FIRST: FieldOffset<Self, T, Aligned> = unsafe{ FieldOffset::new(0) };
114///
115/// const OFFSET_SECOND: FieldOffset<Self, u32, Aligned> = unsafe{
116/// Self::OFFSET_FIRST.next_field_offset()
117/// };
118///
119/// const OFFSET_THIRD: FieldOffset<Self, Option<T>, Aligned> = unsafe{
120/// Self::OFFSET_SECOND.next_field_offset()
121/// };
122/// }
123///
124/// ```
125///
126/// <span id="nested-field-in-packed"></span>
127/// ### Accessing Nested Fields
128///
129/// This example demonstrates how to access nested fields in a `#[repr(C, packed)]` struct,
130/// using the [`GetFieldOffset`] trait implemented by the [`ReprOffset`] derive,
131/// through the [`off`](./macro.off.html) macro.
132///
133/// ```rust
134/// # #![deny(safe_packed_borrows)]
135#[cfg_attr(feature = "derive", doc = "use repr_offset::ReprOffset;")]
136#[cfg_attr(not(feature = "derive"), doc = "use repr_offset_derive::ReprOffset;")]
137/// use repr_offset::{
138/// alignment::{Aligned, Unaligned},
139/// off,
140/// FieldOffset,
141/// };
142///
143/// #[repr(C, packed)]
144/// #[derive(ReprOffset)]
145/// struct Pack{
146/// x: u8,
147/// y: NestedC,
148/// }
149///
150/// #[repr(C)]
151/// #[derive(ReprOffset)]
152/// struct NestedC{
153/// name: &'static str,
154/// years: usize,
155/// }
156///
157/// let this = Pack{
158/// x: 0,
159/// y: NestedC{ name: "John", years: 13 },
160/// };
161///
162/// let off_y: FieldOffset<Pack, NestedC, Unaligned> = off!(y);
163///
164/// let off_name: FieldOffset<Pack, &'static str, Unaligned> = off!(y.name);
165///
166/// // You can also get the FieldOffset for a nested field like this.
167/// let off_years: FieldOffset<Pack, usize, Unaligned> = off_y.add(off!(years));
168///
169/// // The this argument is required to call FieldOffset methods,
170/// // infering the S type parameter of FieldOffset from `this`.
171/// let _ = off!(this; y.years);
172///
173/// assert_eq!(off_name.get_copy(&this), "John" );
174/// assert_eq!(off_years.get_copy(&this), 13 );
175///
176/// unsafe{
177/// let nested_ptr: *const NestedC = off_y.get_ptr(&this);
178///
179/// // This code is undefined behavior,
180/// // because `NestedC`'s offsets require the passed in pointer to be aligned.
181/// //
182/// // assert_eq!(NestedC::OFFSET_NAME.read(nested_ptr), "John" );
183/// // assert_eq!(NestedC::OFFSET_YEARS.read(nested_ptr), 13 );
184///
185/// // This is fine though,because the offsets were turned into
186/// // `FieldOffset<_, _, Unaligned>` with `.to_unaligned()`.
187/// assert_eq!( NestedC::OFFSET_NAME.to_unaligned().read(nested_ptr), "John" );
188/// assert_eq!( NestedC::OFFSET_YEARS.to_unaligned().read(nested_ptr), 13 );
189///
190/// }
191/// ```
192///
193/// [`Aligned`]: ./alignment/struct.Aligned.html
194/// [`Unaligned`]: ./alignment/struct.Unaligned.html
195///
196/// [`ReprOffset`]: ./derive.ReprOffset.html
197/// [`unsafe_struct_field_offsets`]: ./macro.unsafe_struct_field_offsets.html
198/// [`GetFieldOffset`]: ./get_field_offset/trait.GetFieldOffset.html
199///
200#[repr(transparent)]
201pub struct FieldOffset<S, F, A> {
202 offset: usize,
203 #[doc(hidden)]
204 pub tys: FOGhosts<S, F, A>,
205}
206
207//////////////////////
208
209#[doc(hidden)]
210pub struct FOGhosts<S, F, A> {
211 pub struct_: PhantomData<fn() -> S>,
212 pub field: PhantomData<fn() -> F>,
213 pub alignment: PhantomData<fn() -> A>,
214}
215
216impl<S, F, A> Copy for FOGhosts<S, F, A> {}
217
218impl<S, F, A> Clone for FOGhosts<S, F, A> {
219 #[inline(always)]
220 fn clone(&self) -> Self {
221 *self
222 }
223}
224
225impl<S, F, A> FOGhosts<S, F, A> {
226 const NEW: Self = Self {
227 struct_: PhantomData,
228 field: PhantomData,
229 alignment: PhantomData,
230 };
231}
232
233//////////////////////
234
235#[doc(hidden)]
236#[repr(transparent)]
237pub struct FOAssertStruct<S, F, A> {
238 pub offset: FieldOffset<S, F, A>,
239 pub struct_: PhantomData<fn() -> S>,
240}
241
242//////////////////////
243
244impl_cmp_traits_for_offset! {
245 impl[S, F, A] FieldOffset<S, F, A>
246}
247
248impl<S, F, A> Debug for FieldOffset<S, F, A> {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 f.debug_struct("FieldOffset")
251 .field("offset", &self.offset)
252 .finish()
253 }
254}
255
256impl<S, F, A> Copy for FieldOffset<S, F, A> {}
257
258impl<S, F, A> Clone for FieldOffset<S, F, A> {
259 #[inline(always)]
260 fn clone(&self) -> Self {
261 *self
262 }
263}
264
265impl<S, F, A> FieldOffset<S, F, A> {
266 /// Constructs this `FieldOffset` from the offset of the field.
267 ///
268 /// # Safety
269 ///
270 /// Callers must ensure all of these:
271 ///
272 /// - `S` must be a `#[repr(C)]` or `#[repr(transparent)]` struct
273 /// (optionally with `align` or `packed` attributes).
274 ///
275 /// - `offset` must be the byte offset of a field of type `F` inside the struct `S`.
276 ///
277 /// - The `A` type parameter must be [`Unaligned`]
278 /// if the field [is unaligned](#alignment-guidelines),
279 /// or [`Aligned`] if [it is aligned](#alignment-guidelines).
280 ///
281 /// # Example
282 ///
283 /// Constructing the `FieldOffset`s of a packed struct.
284 ///
285 /// ```rust
286 /// # #![deny(safe_packed_borrows)]
287 /// use repr_offset::{Aligned, FieldOffset, Unaligned};
288 ///
289 /// let this = Packed{ x: 3, y: 5, z: "huh" };
290 ///
291 /// assert_eq!( OFFSET_X.get_copy(&this), 3 );
292 /// assert_eq!( OFFSET_Y.get_copy(&this), 5 );
293 /// assert_eq!( OFFSET_Z.get_copy(&this), "huh" );
294 ///
295 /// #[repr(C, packed)]
296 /// struct Packed{
297 /// x: u8,
298 /// y: u32,
299 /// z: &'static str,
300 /// }
301 ///
302 /// // `u8` is always aligned.
303 /// const OFFSET_X: FieldOffset<Packed, u8, Aligned> = unsafe{
304 /// FieldOffset::new(0)
305 /// };
306 /// const OFFSET_Y: FieldOffset<Packed, u32, Unaligned> = unsafe{
307 /// OFFSET_X.next_field_offset()
308 /// };
309 /// const OFFSET_Z: FieldOffset<Packed, &'static str, Unaligned> = unsafe{
310 /// OFFSET_Y.next_field_offset()
311 /// };
312 ///
313 /// ```
314 /// [`Aligned`]: ./alignment/struct.Aligned.html
315 /// [`Unaligned`]: ./alignment/struct.Unaligned.html
316 #[inline(always)]
317 pub const unsafe fn new(offset: usize) -> Self {
318 Self {
319 offset,
320 tys: FOGhosts::NEW,
321 }
322 }
323
324 // This must be kept private
325 #[inline(always)]
326 const fn priv_new(offset: usize) -> Self {
327 Self {
328 offset,
329 tys: FOGhosts::NEW,
330 }
331 }
332
333 /// Constructs a `FieldOffset` by calculating the offset of the next field.
334 ///
335 /// # Safety
336 ///
337 /// Callers must ensure that:
338 ///
339 /// - `Next` is the type of the field after the one that this is an offset for.
340 ///
341 /// - `NextA` must be [`Unaligned`] if the field [is unaligned](#alignment-guidelines),
342 /// or [`Aligned`] if [it is aligned](#alignment-guidelines).
343 ///
344 /// # Example
345 ///
346 /// Constructing the `FieldOffset`s of a `#[repr(C, align(16))]` struct.
347 ///
348 /// ```rust
349 /// # #![deny(safe_packed_borrows)]
350 /// use repr_offset::{Aligned, FieldOffset};
351 ///
352 /// let this = ReprAligned{ foo: true, bar: Some('8'), baz: 55 };
353 ///
354 /// assert_eq!( OFFSET_FOO.get_copy(&this), true );
355 /// assert_eq!( OFFSET_BAR.get_copy(&this), Some('8') );
356 /// assert_eq!( OFFSET_BAZ.get_copy(&this), 55 );
357 ///
358 ///
359 /// #[repr(C, align(16))]
360 /// struct ReprAligned{
361 /// foo: bool,
362 /// bar: Option<char>,
363 /// baz: u64,
364 /// }
365 ///
366 /// const OFFSET_FOO: FieldOffset<ReprAligned, bool, Aligned> = unsafe{
367 /// FieldOffset::new(0)
368 /// };
369 /// const OFFSET_BAR: FieldOffset<ReprAligned, Option<char>, Aligned> = unsafe{
370 /// OFFSET_FOO.next_field_offset()
371 /// };
372 /// const OFFSET_BAZ: FieldOffset<ReprAligned, u64, Aligned> = unsafe{
373 /// OFFSET_BAR.next_field_offset()
374 /// };
375 ///
376 /// ```
377 ///
378 /// [`Aligned`]: ./alignment/struct.Aligned.html
379 /// [`Unaligned`]: ./alignment/struct.Unaligned.html
380 pub const unsafe fn next_field_offset<Next, NextA>(self) -> FieldOffset<S, Next, NextA> {
381 let offset = GetNextFieldOffset {
382 previous_offset: self.offset,
383 previous_size: Mem::<F>::SIZE,
384 container_alignment: Mem::<S>::ALIGN,
385 next_alignment: Mem::<Next>::ALIGN,
386 }
387 .call();
388
389 FieldOffset {
390 offset,
391 tys: FOGhosts::NEW,
392 }
393 }
394}
395
396impl FieldOffset<(), (), Aligned> {
397 /// Constructs a `FieldOffset` where `T` is the struct and the field type.
398 pub const fn identity<T>() -> FieldOffset<T, T, Aligned> {
399 FieldOffset {
400 offset: 0,
401 tys: FOGhosts::NEW,
402 }
403 }
404}
405
406impl<S, F> FieldOffset<S, F, Aligned> {
407 /// Combines this `FieldOffset` with another one, to access a nested field.
408 ///
409 /// Note that the resulting `FieldOffset` has the
410 /// alignment type parameter (the third one) of `other`.
411 ///
412 /// # Example
413 ///
414 /// ```rust
415 /// # #![deny(safe_packed_borrows)]
416 /// use repr_offset::{Aligned, FieldOffset, Unaligned};
417 /// use repr_offset::for_examples::{ReprC, ReprPacked};
418 ///
419 /// type This = ReprC<char, ReprC<u8, u16>, ReprPacked<u32, u64>>;
420 ///
421 /// let this: This = ReprC {
422 /// a: '3',
423 /// b: ReprC{ a: 5u8, b: 8u16, c: (), d: () },
424 /// c: ReprPacked{ a: 13u32, b: 21u64, c: (), d: () },
425 /// d: (),
426 /// };
427 ///
428 /// assert_eq!( OFFSET_B_A.get_copy(&this), 5 );
429 /// assert_eq!( OFFSET_C_A.get_copy(&this), 13 );
430 ///
431 /// // This is the FieldOffset of the `.b.a` nested field.
432 /// const OFFSET_B_A: FieldOffset<This, u8, Aligned> =
433 /// ReprC::OFFSET_B.add(ReprC::OFFSET_A);
434 ///
435 /// // This is the FieldOffset of the `.c.a` nested field.
436 /// //
437 /// // The alignment type parameter of the combined FieldOffset is`Unaligned` if
438 /// // either FieldOffset has `Unaligned` as the `A` type parameter.
439 /// const OFFSET_C_A: FieldOffset<This, u32, Unaligned> =
440 /// ReprC::OFFSET_C.add(ReprPacked::OFFSET_A);
441 ///
442 /// ```
443 ///
444 #[inline(always)]
445 pub const fn add<F2, A2>(self, other: FieldOffset<F, F2, A2>) -> FieldOffset<S, F2, A2> {
446 FieldOffset::priv_new(self.offset + other.offset)
447 }
448}
449
450impl<S, F> FieldOffset<S, F, Unaligned> {
451 /// Combines this `FieldOffset` with another one, to access a nested field.
452 ///
453 /// # Example
454 ///
455 /// ```rust
456 /// # #![deny(safe_packed_borrows)]
457 /// use repr_offset::{FieldOffset, Unaligned};
458 /// use repr_offset::for_examples::{ReprC, ReprPacked};
459 ///
460 /// type This = ReprPacked<char, ReprC<u8, u16>, ReprPacked<u32, u64>>;
461 ///
462 /// let this: This = ReprPacked {
463 /// a: '3',
464 /// b: ReprC{ a: 34u8, b: 55u16, c: (), d: () },
465 /// c: ReprPacked{ a: 89u32, b: 144u64, c: (), d: () },
466 /// d: (),
467 /// };
468 ///
469 /// assert_eq!( OFFSET_B_A.get_copy(&this), 34 );
470 /// assert_eq!( OFFSET_C_A.get_copy(&this), 89 );
471 ///
472 /// // This is the FieldOffset of the `.b.a` nested field.
473 /// const OFFSET_B_A: FieldOffset<This, u8, Unaligned> =
474 /// ReprPacked::OFFSET_B.add(ReprC::OFFSET_A);
475 ///
476 /// // This is the FieldOffset of the `.c.a` nested field.
477 /// const OFFSET_C_A: FieldOffset<This, u32, Unaligned> =
478 /// ReprPacked::OFFSET_C.add(ReprPacked::OFFSET_A);
479 ///
480 /// ```
481 ///
482 #[inline(always)]
483 pub const fn add<F2, A2>(self, other: FieldOffset<F, F2, A2>) -> FieldOffset<S, F2, Unaligned> {
484 FieldOffset::priv_new(self.offset + other.offset)
485 }
486}
487
488/// Equivalent to the inherent `FieldOffset::add` method,
489/// that one can be ran at compile-time(this one can't).
490///
491/// # Example
492///
493/// ```rust
494/// # #![deny(safe_packed_borrows)]
495/// use repr_offset::{Aligned, FieldOffset, Unaligned};
496/// use repr_offset::for_examples::{ReprC, ReprPacked};
497///
498/// type This = ReprC<char, ReprC<u8, u16>, ReprPacked<u32, u64>>;
499///
500/// let this: This = ReprC {
501/// a: '3',
502/// b: ReprC{ a: 5u8, b: 8u16, c: (), d: () },
503/// c: ReprPacked{ a: 13u32, b: 21u64, c: (), d: () },
504/// d: (),
505/// };
506///
507/// // This is the FieldOffset of the `.b.a` nested field.
508/// let offset_b_b = ReprC::OFFSET_B + ReprC::OFFSET_B;
509///
510/// // This is the FieldOffset of the `.c.a` nested field.
511/// let offset_c_b = ReprC::OFFSET_C + ReprPacked::OFFSET_B;
512///
513/// assert_eq!( offset_b_b.get_copy(&this), 8 );
514/// assert_eq!( offset_c_b.get_copy(&this), 21 );
515///
516/// ```
517///
518impl<S, F, A, F2, A2> Add<FieldOffset<F, F2, A2>> for FieldOffset<S, F, A>
519where
520 A: CombineAlignment<A2>,
521 A2: Alignment,
522{
523 type Output = FieldOffset<S, F2, CombineAlignmentOut<A, A2>>;
524
525 #[inline(always)]
526 fn add(self, other: FieldOffset<F, F2, A2>) -> Self::Output {
527 FieldOffset::priv_new(self.offset + other.offset)
528 }
529}
530
531impl<S, F, A> FieldOffset<S, F, A> {
532 /// The offset (in bytes) of the `F` field in the `S` struct.
533 ///
534 /// # Example
535 ///
536 /// This example demonstrates this method with a `#[repr(C, packed)]` struct.
537 ///
538 /// ```rust
539 /// # #![deny(safe_packed_borrows)]
540 /// use repr_offset::for_examples::ReprPacked;
541 ///
542 /// type Normal = ReprPacked<u8, u16, u32, u64>;
543 /// type Reversed = ReprPacked<u64, u32, u16, u8>;
544 ///
545 /// assert_eq!( Normal::OFFSET_A.offset(), 0 );
546 /// assert_eq!( Normal::OFFSET_B.offset(), 1 );
547 /// assert_eq!( Normal::OFFSET_C.offset(), 3 );
548 /// assert_eq!( Normal::OFFSET_D.offset(), 7 );
549 ///
550 /// assert_eq!( Reversed::OFFSET_A.offset(), 0 );
551 /// assert_eq!( Reversed::OFFSET_B.offset(), 8 );
552 /// assert_eq!( Reversed::OFFSET_C.offset(), 12 );
553 /// assert_eq!( Reversed::OFFSET_D.offset(), 14 );
554 ///
555 ///
556 /// ```
557 #[inline(always)]
558 pub const fn offset(self) -> usize {
559 self.offset
560 }
561}
562
563impl<S, F, A> FieldOffset<S, F, A> {
564 /// Converts this FieldOffset into a [`FieldOffsetWithVis`].
565 ///
566 /// # Safety
567 ///
568 /// The `V` type parameter must be:
569 /// - `[`IsPublic`]`: When the field is `pub`.
570 ///
571 /// - [`IsPrivate`]: When the field has the default (private) visibility,
572 /// or has a visibility smaller or equal to `pub(crate)`.
573 ///
574 /// The `FN` type parameter must be the name of the field using the
575 /// `repr_offset::tstr::TS` macro,
576 /// eg: `TS!(foo)` for the `foo` field.
577 ///
578 /// [`IsPublic`]: ./privacy/struct.IsPublic.html
579 /// [`IsPrivate`]: ./privacy/struct.IsPrivate.html
580 ///
581 /// [`FieldOffsetWithVis`] ./get_field_offset/struct.FieldOffsetWithVis.html
582 ///
583 #[inline(always)]
584 pub const unsafe fn with_vis<V, FN>(self) -> FieldOffsetWithVis<S, V, FN, F, A> {
585 FieldOffsetWithVis::from_fieldoffset(self)
586 }
587}
588
589impl<S, F, A> FieldOffset<S, F, A> {
590 /// Changes the `S` type parameter, most useful for `#[repr(transparent)]` wrappers.
591 ///
592 /// # Safety
593 ///
594 /// Callers must ensure that there is a field of type `F` at the same offset
595 /// inside the `S2` type,
596 /// and is at least as public as this `FieldOffset`.
597 ///
598 /// If the `A` type parameter is [`Aligned`],
599 /// then the field [must be aligned](#alignment-guidelines)
600 ///
601 /// # Example
602 ///
603 /// ```rust
604 /// # #![deny(safe_packed_borrows)]
605 /// use repr_offset::FieldOffset;
606 /// use repr_offset::for_examples::ReprC;
607 ///
608 /// let this = Wrapper(ReprC{
609 /// a: false,
610 /// b: 3u8,
611 /// c: Some('5'),
612 /// d: [8u32, 13u32],
613 /// });
614 ///
615 /// assert_eq!( cast_offset(ReprC::OFFSET_A).get(&this), &false );
616 /// assert_eq!( cast_offset(ReprC::OFFSET_B).get(&this), &3u8 );
617 /// assert_eq!( cast_offset(ReprC::OFFSET_C).get(&this), &Some('5') );
618 /// assert_eq!( cast_offset(ReprC::OFFSET_D).get(&this), &[8u32, 13u32] );
619 ///
620 ///
621 /// #[repr(transparent)]
622 /// pub struct Wrapper<T>(pub T);
623 ///
624 /// pub const fn cast_offset<T,F,A>(offset: FieldOffset<T,F,A>) -> FieldOffset<Wrapper<T>,F,A>{
625 /// // safety: This case is safe because this is a
626 /// // `#[repr(transparent)]` wrapper around `T`
627 /// // where `T` is a public field in the wrapper
628 /// unsafe{ offset.cast_struct() }
629 /// }
630 ///
631 ///
632 ///
633 /// ```
634 ///
635 /// [`Aligned`]: ./alignment/struct.Aligned.html
636 /// [`Unaligned`]: ./alignment/struct.Unaligned.html
637 #[inline(always)]
638 pub const unsafe fn cast_struct<S2>(self) -> FieldOffset<S2, F, A> {
639 FieldOffset::new(self.offset)
640 }
641
642 /// Changes the `F` type parameter.
643 ///
644 /// # Safety
645 ///
646 /// Callers must ensure that the `F2` type is compatible with the `F` type,
647 /// including size,alignment, and internal layout.
648 ///
649 /// If the `F` type encodes an invariant,
650 /// then callers must ensure that if the field is used as the `F` type
651 /// (including the destructor for the type)
652 /// that the invariants for that type must be upheld.
653 ///
654 /// The same applies if the field is used as the `F2` type
655 /// (if the returned FieldOffset isn't used,then it would not be used as the `F2` type)
656 ///
657 /// # Example
658 ///
659 /// ```rust
660 /// # #![deny(safe_packed_borrows)]
661 ///
662 /// use repr_offset::{Aligned, FieldOffset};
663 /// use repr_offset::for_examples::ReprC;
664 ///
665 /// type This = ReprC<u8, u64, (), ()>;
666 ///
667 /// let this: This = ReprC{ a: 3, b: 5, c: (), d: () };
668 ///
669 /// unsafe{
670 /// assert_eq!( This::OFFSET_A.cast_field::<i8>().get(&this), &3i8 );
671 /// assert_eq!( This::OFFSET_B.cast_field::<i64>().get(&this), &5i64 );
672 /// }
673 ///
674 /// ```
675 /// [safe and valid]:
676 /// https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#validity-and-safety-invariant
677 #[inline(always)]
678 pub const unsafe fn cast_field<F2>(self) -> FieldOffset<S, F2, A> {
679 FieldOffset::new(self.offset)
680 }
681
682 /// Changes this `FieldOffset` to be for a (potentially) unaligned field.
683 ///
684 /// This is useful if you want to get a nested field from an unaligned pointer to a
685 /// `#[repr(C)]`/`#[repr(C,align())]` struct.
686 ///
687 /// # Example
688 ///
689 /// This example demonstrates how you can copy a field
690 /// from an unaligned pointer to a `#[repr(C)]` struct.
691 ///
692 /// ```rust
693 /// # #![deny(safe_packed_borrows)]
694 /// use repr_offset::for_examples::{ReprC, ReprPacked};
695 ///
696 /// type Inner = ReprC<usize, &'static str>;
697 /// type Outer = ReprPacked<u8, Inner>;
698 ///
699 /// let inner = ReprC { a: 3, b: "5", c: (), d: () };
700 /// let outer: Outer = ReprPacked{ a: 21, b: inner, c: (), d: () };
701 ///
702 /// let inner_ptr: *const Inner = Outer::OFFSET_B.get_ptr(&outer);
703 /// unsafe{
704 /// assert_eq!( Inner::OFFSET_A.to_unaligned().read_copy(inner_ptr), 3 );
705 /// assert_eq!( Inner::OFFSET_B.to_unaligned().read_copy(inner_ptr), "5" );
706 ///
707 /// // This is undefined behavior,
708 /// // because ReprC's FieldOFfsets require the pointer to be aligned.
709 /// //
710 /// // assert_eq!( Inner::OFFSET_A.read_copy(inner_ptr), 3 );
711 /// // assert_eq!( Inner::OFFSET_B.read_copy(inner_ptr), "5" );
712 /// }
713 ///
714 /// ```
715 ///
716 #[inline(always)]
717 pub const fn to_unaligned(self) -> FieldOffset<S, F, Unaligned> {
718 FieldOffset {
719 offset: self.offset,
720 tys: FOGhosts::NEW,
721 }
722 }
723
724 /// Changes this `FieldOffset` to be for an aligned field.
725 ///
726 /// # Safety
727 ///
728 /// Callers must ensure that [the field is aligned](#alignment-guidelines)
729 /// within the `S` type.
730 ///
731 /// # Example
732 ///
733 /// ```rust
734 /// # #![deny(safe_packed_borrows)]
735 /// use repr_offset::{Aligned, FieldOffset, Unaligned};
736 ///
737 /// // ReprPacked2 is aligned to 2 bytes.
738 /// use repr_offset::for_examples::ReprPacked2;
739 ///
740 /// type This = ReprPacked2<u8, u16, (), ()>;
741 ///
742 /// let _: FieldOffset<This, u8, Unaligned> = This::OFFSET_A;
743 /// let _: FieldOffset<This, u16, Unaligned> = This::OFFSET_B;
744 ///
745 /// let this: This = ReprPacked2{ a: 89, b: 144, c: (), d: () };
746 ///
747 /// unsafe{
748 /// assert_eq!( This::OFFSET_A.to_aligned().get(&this), &89 );
749 /// assert_eq!( This::OFFSET_B.to_aligned().get(&this), &144 );
750 /// }
751 /// ```
752 #[inline(always)]
753 pub const unsafe fn to_aligned(self) -> FieldOffset<S, F, Aligned> {
754 FieldOffset::new(self.offset)
755 }
756}
757
758impl<S, F> FieldOffset<S, F, Aligned> {
759 /// Gets a reference to the field that this is an offset for.
760 ///
761 /// # Example
762 ///
763 /// ```rust
764 /// # #![deny(safe_packed_borrows)]
765 /// use repr_offset::for_examples::ReprC;
766 ///
767 /// let this = ReprC{ a: '@', b: 21u8, c: (), d: () };
768 ///
769 /// assert_eq!( ReprC::OFFSET_A.get(&this), &'@' );
770 /// assert_eq!( ReprC::OFFSET_B.get(&this), &21u8 );
771 ///
772 /// ```
773 #[inline(always)]
774 pub fn get(self, base: &S) -> &F {
775 unsafe { impl_fo!(fn get<S, F, Aligned>(self, base)) }
776 }
777
778 /// Gets a mutable reference to the field that this is an offset for.
779 ///
780 /// # Example
781 ///
782 /// ```rust
783 /// # #![deny(safe_packed_borrows)]
784 /// use repr_offset::for_examples::ReprC;
785 ///
786 /// let mut this = ReprC{ a: "what", b: '?', c: (), d: () };
787 ///
788 /// assert_eq!( ReprC::OFFSET_A.get_mut(&mut this), &mut "what" );
789 /// assert_eq!( ReprC::OFFSET_B.get_mut(&mut this), &mut '?' );
790 ///
791 /// ```
792 #[inline(always)]
793 pub fn get_mut(self, base: &mut S) -> &mut F {
794 unsafe { impl_fo!(fn get_mut<S, F, Aligned>(self, base)) }
795 }
796
797 /// Copies the aligned field that this is an offset for.
798 ///
799 /// # Example
800 ///
801 /// ```rust
802 /// # #![deny(safe_packed_borrows)]
803 /// use repr_offset::for_examples::ReprC;
804 ///
805 /// let this = ReprC{ a: Some(false), b: [8i32, 13, 21], c: (), d: () };
806 ///
807 /// assert_eq!( ReprC::OFFSET_A.get_copy(&this), Some(false) );
808 /// assert_eq!( ReprC::OFFSET_B.get_copy(&this), [8i32, 13, 21] );
809 ///
810 /// ```
811 ///
812 /// This method can't be called for non-Copy fields.
813 /// ```compile_fail
814 /// # #![deny(safe_packed_borrows)]
815 /// use repr_offset::for_examples::ReprC;
816 ///
817 /// let this = ReprC{ a: vec![0, 1, 2, 3], b: (), c: (), d: () };
818 ///
819 /// let _ = ReprC::OFFSET_A.get_copy(&this);
820 /// ```
821 #[inline(always)]
822 pub fn get_copy(self, base: &S) -> F
823 where
824 F: Copy,
825 {
826 unsafe { impl_fo!(fn get_copy<S, F, Aligned>(self, base)) }
827 }
828}
829
830impl<S, F, A> FieldOffset<S, F, A> {
831 /// Gets a raw pointer to a field from a reference to the `S` struct.
832 ///
833 /// # Example
834 ///
835 /// ```rust
836 /// # #![deny(safe_packed_borrows)]
837 /// use repr_offset::FieldOffset;
838 /// use repr_offset::for_examples::ReprPacked;
839 ///
840 /// let this = ReprPacked{ a: 3u8, b: 5u16, c: (), d: () };
841 ///
842 /// let ptr_a = ReprPacked::OFFSET_A.get_ptr(&this);
843 /// // A `u8` is always aligned,so a `.read()` is fine.
844 /// assert_eq!( unsafe{ ptr_a.read() }, 3u8 );
845 ///
846 /// let ptr_b = ReprPacked::OFFSET_B.get_ptr(&this);
847 /// // ReprPacked has an alignment of 1,
848 /// // so this u16 field has to be copied with `.read_unaligned()`.
849 /// assert_eq!( unsafe{ ptr_b.read_unaligned() }, 5u16 );
850 ///
851 /// ```
852 #[inline(always)]
853 pub fn get_ptr(self, base: &S) -> *const F {
854 unsafe { impl_fo!(fn get_ptr<S, F, A>(self, base)) }
855 }
856
857 /// Gets a mutable raw pointer to a field from a mutable reference to the `S` struct.
858 ///
859 /// # Example
860 ///
861 /// ```rust
862 /// # #![deny(safe_packed_borrows)]
863 /// use repr_offset::FieldOffset;
864 /// use repr_offset::for_examples::ReprPacked;
865 ///
866 /// let mut this = ReprPacked{ a: 3u8, b: 5u16, c: (), d: () };
867 ///
868 /// let ptr_a = ReprPacked::OFFSET_A.get_mut_ptr(&mut this);
869 /// unsafe{
870 /// // A `u8` is always aligned,so a `.read()` is fine.
871 /// assert_eq!( ptr_a.read(), 3u8 );
872 /// ptr_a.write(103);
873 /// assert_eq!( ptr_a.read(), 103 );
874 /// }
875 ///
876 /// let ptr_b = ReprPacked::OFFSET_B.get_mut_ptr(&mut this);
877 /// unsafe{
878 /// // ReprPacked has an alignment of 1,
879 /// // so this u16 field has to be read with `.read_unaligned()`.
880 /// assert_eq!( ptr_b.read_unaligned(), 5u16 );
881 /// ptr_b.write_unaligned(105);
882 /// assert_eq!( ptr_b.read_unaligned(), 105 );
883 /// }
884 ///
885 /// ```
886 #[inline(always)]
887 pub fn get_mut_ptr(self, base: &mut S) -> *mut F {
888 unsafe { impl_fo!(fn get_mut_ptr<S, F, A>(self, base)) }
889 }
890
891 /// Gets a raw pointer to a field from a pointer to the `S` struct.
892 ///
893 /// # Safety
894 ///
895 /// This has the same safety requirements as the [`<*const T>::offset`] method.
896 ///
897 /// [`<*const T>::offset`]:
898 /// https://doc.rust-lang.org/std/primitive.pointer.html#method.offset
899 ///
900 /// # Example
901 ///
902 /// ```rust
903 /// # #![deny(safe_packed_borrows)]
904 /// use repr_offset::FieldOffset;
905 /// use repr_offset::for_examples::ReprPacked;
906 ///
907 /// let this = ReprPacked{ a: 3u8, b: 5u16, c: (), d: () };
908 ///
909 /// let ptr: *const _ = &this;
910 ///
911 /// unsafe{
912 /// // A `u8` is always aligned,so a `.read()` is fine.
913 /// assert_eq!( ReprPacked::OFFSET_A.raw_get(ptr).read(), 3u8 );
914 ///
915 /// // ReprPacked has an alignment of 1,
916 /// // so this u16 field has to be copied with `.read_unaligned()`.
917 /// assert_eq!( ReprPacked::OFFSET_B.raw_get(ptr).read_unaligned(), 5u16 );
918 /// }
919 ///
920 /// ```
921 #[inline(always)]
922 pub unsafe fn raw_get(self, base: *const S) -> *const F {
923 impl_fo!(fn raw_get<S, F, A>(self, base))
924 }
925
926 /// Gets a mutable raw pointer to a field from a pointer to the `S` struct.
927 ///
928 /// # Safety
929 ///
930 /// This has the same safety requirements as the [`<*mut T>::offset`] method.
931 ///
932 /// [`<*mut T>::offset`]:
933 /// https://doc.rust-lang.org/std/primitive.pointer.html#method.offset-1
934 ///
935 /// # Example
936 ///
937 /// ```rust
938 /// # #![deny(safe_packed_borrows)]
939 /// use repr_offset::FieldOffset;
940 /// use repr_offset::for_examples::ReprPacked;
941 ///
942 /// let mut this = ReprPacked{ a: 3u8, b: 5u16, c: (), d: () };
943 ///
944 /// let ptr: *mut _ = &mut this;
945 ///
946 /// unsafe{
947 /// let ptr_a = ReprPacked::OFFSET_A.raw_get_mut(ptr);
948 ///
949 /// // A `u8` is always aligned,so a `.read()` is fine.
950 /// assert_eq!( ptr_a.read(), 3u8 );
951 /// ptr_a.write(103);
952 /// assert_eq!( ptr_a.read(), 103 );
953 ///
954 ///
955 /// let ptr_b = ReprPacked::OFFSET_B.raw_get_mut(ptr);
956 ///
957 /// // ReprPacked has an alignment of 1,
958 /// // so this u16 field has to be read with `.read_unaligned()`.
959 /// assert_eq!( ptr_b.read_unaligned(), 5u16 );
960 /// ptr_b.write_unaligned(105);
961 /// assert_eq!( ptr_b.read_unaligned(), 105 );
962 /// }
963 ///
964 /// ```
965 #[inline(always)]
966 pub unsafe fn raw_get_mut(self, base: *mut S) -> *mut F {
967 impl_fo!(fn raw_get_mut<S, F, A>(self, base))
968 }
969
970 /// Gets a raw pointer to a field from a pointer to the `S` struct.
971 ///
972 /// # Safety
973 ///
974 /// While calling this method is not by itself unsafe,
975 /// using the pointer returned by this method has the same safety requirements
976 /// as the [`<*const T>::wrapping_offset`] method.
977 ///
978 /// [`<*const T>::wrapping_offset`]:
979 /// https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset
980 ///
981 /// # Example
982 ///
983 /// ```rust
984 /// # #![deny(safe_packed_borrows)]
985 /// use repr_offset::FieldOffset;
986 /// use repr_offset::for_examples::ReprPacked;
987 ///
988 /// let this = ReprPacked{ a: 3u8, b: 5u16, c: (), d: () };
989 ///
990 /// let ptr_a = ReprPacked::OFFSET_A.wrapping_raw_get(&this);
991 /// // A `u8` is always aligned,so a `.read()` is fine.
992 /// assert_eq!( unsafe{ ptr_a.read() }, 3u8 );
993 ///
994 /// let ptr_b = ReprPacked::OFFSET_B.wrapping_raw_get(&this);
995 /// // ReprPacked has an alignment of 1,
996 /// // so this u16 field has to be copied with `.read_unaligned()`.
997 /// assert_eq!( unsafe{ ptr_b.read_unaligned() }, 5u16 );
998 ///
999 /// ```
1000 #[inline(always)]
1001 pub fn wrapping_raw_get(self, base: *const S) -> *const F {
1002 (base as *const u8).wrapping_offset(self.offset as isize) as *const F
1003 }
1004
1005 /// Gets a mutable raw pointer to a field from a pointer to the `S` struct.
1006 ///
1007 /// # Safety
1008 ///
1009 /// While calling this method is not by itself unsafe,
1010 /// using the pointer returned by this method has the same safety requirements
1011 /// as the [`<*mut T>::wrapping_offset`] method.
1012 ///
1013 /// [`<*mut T>::wrapping_offset`]:
1014 /// https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset-1
1015 ///
1016 /// # Example
1017 ///
1018 /// ```rust
1019 /// # #![deny(safe_packed_borrows)]
1020 /// use repr_offset::FieldOffset;
1021 /// use repr_offset::for_examples::ReprPacked;
1022 ///
1023 /// let mut this = ReprPacked{ a: 3u8, b: 5u16, c: (), d: () };
1024 ///
1025 /// let ptr: *mut _ = &mut this;
1026 ///
1027 /// let ptr_a = ReprPacked::OFFSET_A.wrapping_raw_get_mut(ptr);
1028 /// unsafe{
1029 ///
1030 /// // A `u8` is always aligned,so a `.read()` is fine.
1031 /// assert_eq!( ptr_a.read(), 3u8 );
1032 /// ptr_a.write(103);
1033 /// assert_eq!( ptr_a.read(), 103 );
1034 /// }
1035 ///
1036 /// let ptr_b = ReprPacked::OFFSET_B.wrapping_raw_get_mut(ptr);
1037 /// unsafe{
1038 ///
1039 /// // ReprPacked has an alignment of 1,
1040 /// // so this u16 field has to be read with `.read_unaligned()`.
1041 /// assert_eq!( ptr_b.read_unaligned(), 5u16 );
1042 /// ptr_b.write_unaligned(105);
1043 /// assert_eq!( ptr_b.read_unaligned(), 105 );
1044 /// }
1045 ///
1046 /// ```
1047 #[inline(always)]
1048 pub fn wrapping_raw_get_mut(self, base: *mut S) -> *mut F {
1049 (base as *mut u8).wrapping_offset(self.offset as isize) as *mut F
1050 }
1051}
1052
1053impl<S, F> FieldOffset<S, F, Aligned> {
1054 /// Copies the aligned field that this is an offset for.
1055 ///
1056 /// # Safety
1057 ///
1058 /// This function has the same safety requirements as
1059 /// [`std::ptr::read`](https://doc.rust-lang.org/std/ptr/fn.read.html).
1060 ///
1061 /// Those safety requirements only apply to the field that this is an offset for,
1062 /// fields after it or before it don't need to be valid to call this method.
1063 ///
1064 /// # Example
1065 ///
1066 /// ```rust
1067 /// # #![deny(safe_packed_borrows)]
1068 /// use repr_offset::for_examples::ReprC;
1069 ///
1070 /// let this = ReprC{ a: 10u8, b: "20", c: (), d: () };
1071 ///
1072 /// let ptr: *const _ = &this;
1073 /// unsafe{
1074 /// assert_eq!( ReprC::OFFSET_A.read_copy(ptr), 10u8 );
1075 /// assert_eq!( ReprC::OFFSET_B.read_copy(ptr), "20" );
1076 /// }
1077 /// ```
1078 ///
1079 /// This method can't be called for non-Copy fields.
1080 /// ```compile_fail
1081 /// # #![deny(safe_packed_borrows)]
1082 /// use repr_offset::for_examples::ReprC;
1083 ///
1084 /// let this = ReprC{ a: vec![0, 1, 2, 3], b: (), c: (), d: () };
1085 /// unsafe{
1086 /// let _ = ReprC::OFFSET_A.read_copy(&this);
1087 /// }
1088 /// ```
1089 ///
1090 #[inline(always)]
1091 pub unsafe fn read_copy(self, base: *const S) -> F
1092 where
1093 F: Copy,
1094 {
1095 impl_fo!(fn read_copy<S, F, Aligned>(self, base))
1096 }
1097
1098 /// Reads the value from the field in `source` without moving it.
1099 ///
1100 /// # Safety
1101 ///
1102 /// This function has the same safety requirements as
1103 /// [`std::ptr::read`](https://doc.rust-lang.org/std/ptr/fn.read.html).
1104 ///
1105 /// Those safety requirements only apply to the field that this is an offset for,
1106 /// fields after it or before it don't need to be valid to call this method.
1107 ///
1108 /// # Example
1109 ///
1110 /// ```rust
1111 /// # #![deny(safe_packed_borrows)]
1112 /// use repr_offset::for_examples::ReprC;
1113 ///
1114 /// use std::mem::ManuallyDrop;
1115 ///
1116 /// let this = ManuallyDrop::new(ReprC{
1117 /// a: vec![0, 1, 2],
1118 /// b: "20".to_string(),
1119 /// c: (),
1120 /// d: (),
1121 /// });
1122 ///
1123 /// let ptr: *const _ = &*this;
1124 /// unsafe{
1125 /// assert_eq!( ReprC::OFFSET_A.read(ptr), vec![0, 1, 2] );
1126 /// assert_eq!( ReprC::OFFSET_B.read(ptr), "20".to_string() );
1127 /// }
1128 ///
1129 /// ```
1130 #[inline(always)]
1131 pub unsafe fn read(self, source: *const S) -> F {
1132 impl_fo!(fn read<S, F, Aligned>(self, source))
1133 }
1134
1135 /// Writes `value` ìnto the field in `destination` without dropping the old value of the field.
1136 ///
1137 /// This allows uninitialized fields to be initialized,since doing
1138 /// `*OFFSET_FOO.raw_get_mut(ptr) = value;` would drop uninitialized memory.
1139 ///
1140 /// # Safety
1141 ///
1142 /// This function has the same safety requirements as
1143 /// [`std::ptr::write`](https://doc.rust-lang.org/std/ptr/fn.write.html).
1144 ///
1145 /// Those safety requirements only apply to the field that this is an offset for,
1146 /// fields after it or before it don't need to be valid to call this method.
1147 ///
1148 /// # Example
1149 ///
1150 /// ```rust
1151 /// # #![deny(safe_packed_borrows)]
1152 /// use repr_offset::for_examples::ReprC;
1153 ///
1154 /// let mut this = ReprC{ a: 10u8, b: "20", c: (), d: () };
1155 ///
1156 /// let ptr: *mut _ = &mut this;
1157 /// unsafe{
1158 /// ReprC::OFFSET_A.write(ptr, 13u8);
1159 /// ReprC::OFFSET_B.write(ptr, "21");
1160 /// }
1161 /// assert_eq!( this.a, 13u8 );
1162 /// assert_eq!( this.b, "21" );
1163 ///
1164 /// ```
1165 #[inline(always)]
1166 pub unsafe fn write(self, destination: *mut S, value: F) {
1167 impl_fo!(fn write<S, F, Aligned>(self, destination, value))
1168 }
1169
1170 /// Copies the field in `source` into `destination`.
1171 ///
1172 /// # Safety
1173 ///
1174 /// This function has the same safety requirements as
1175 /// [`std::ptr::copy`](https://doc.rust-lang.org/std/ptr/fn.copy.html).
1176 ///
1177 /// Those safety requirements only apply to the field that this is an offset for,
1178 /// fields after it or before it don't need to be valid to call this method.
1179 ///
1180 /// # Example
1181 ///
1182 /// ```rust
1183 /// # #![deny(safe_packed_borrows)]
1184 /// use repr_offset::for_examples::ReprC;
1185 ///
1186 /// let this = ReprC{ a: 10u8, b: "20", c: (), d: () };
1187 /// let mut other = ReprC{ a: 0u8, b: "", c: (), d: () };
1188 ///
1189 /// let this_ptr: *const _ = &this;
1190 /// let other_ptr: *mut _ = &mut other;
1191 /// unsafe{
1192 /// ReprC::OFFSET_A.copy(this_ptr, other_ptr);
1193 /// ReprC::OFFSET_B.copy(this_ptr, other_ptr);
1194 /// }
1195 /// assert_eq!( this.a, 10u8 );
1196 /// assert_eq!( this.b, "20" );
1197 ///
1198 /// assert_eq!( other.a, 10u8 );
1199 /// assert_eq!( other.b, "20" );
1200 ///
1201 /// ```
1202 #[inline(always)]
1203 pub unsafe fn copy(self, source: *const S, destination: *mut S) {
1204 impl_fo!(fn copy<S, F, Aligned>(self, source, destination))
1205 }
1206
1207 /// Copies the field in `source` into `destination`,
1208 /// `source` and `destination` must not overlap.
1209 ///
1210 /// # Safety
1211 ///
1212 /// This function has the same safety requirements as
1213 /// [`std::ptr::copy_nonoverlapping`
1214 /// ](https://doc.rust-lang.org/std/ptr/fn.copy_nonoverlapping.html).
1215 ///
1216 /// Those safety requirements only apply to the field that this is an offset for,
1217 /// fields after it or before it don't need to be valid to call this method.
1218 ///
1219 /// # Example
1220 ///
1221 /// ```rust
1222 /// # #![deny(safe_packed_borrows)]
1223 /// use repr_offset::for_examples::ReprC;
1224 ///
1225 /// let this = ReprC{ a: '#', b: 81, c: (), d: () };
1226 /// let mut other = ReprC{ a: '_', b: 0, c: (), d: () };
1227 ///
1228 /// let this_ptr: *const _ = &this;
1229 /// let other_ptr: *mut _ = &mut other;
1230 /// unsafe{
1231 /// ReprC::OFFSET_A.copy_nonoverlapping(this_ptr, other_ptr);
1232 /// ReprC::OFFSET_B.copy_nonoverlapping(this_ptr, other_ptr);
1233 /// }
1234 /// assert_eq!( this.a, '#' );
1235 /// assert_eq!( this.b, 81 );
1236 ///
1237 /// assert_eq!( other.a, '#' );
1238 /// assert_eq!( other.b, 81 );
1239 ///
1240 /// ```
1241 #[inline(always)]
1242 pub unsafe fn copy_nonoverlapping(self, source: *const S, destination: *mut S) {
1243 impl_fo!(fn copy_nonoverlapping<S, F, Aligned>(self, source, destination))
1244 }
1245
1246 /// Replaces the value of a field in `destination` with `value`,
1247 /// returning the old value of the field.
1248 ///
1249 /// # Safety
1250 ///
1251 /// This function has the same safety requirements as
1252 /// [`std::ptr::replace`](https://doc.rust-lang.org/std/ptr/fn.replace.html).
1253 ///
1254 /// Those safety requirements only apply to the field that this is an offset for,
1255 /// fields after it or before it don't need to be valid to call this method.
1256 ///
1257 /// # Example
1258 ///
1259 /// ```rust
1260 /// # #![deny(safe_packed_borrows)]
1261 /// use repr_offset::for_examples::ReprC;
1262 ///
1263 /// let mut this = ReprC{ a: [0u8, 1], b: false, c: (), d: () };
1264 ///
1265 /// let ptr: *mut _ = &mut this;
1266 /// unsafe{
1267 /// assert_eq!( ReprC::OFFSET_A.replace(ptr, [2, 3]), [0u8, 1] );
1268 /// assert_eq!( ReprC::OFFSET_B.replace(ptr, true), false );
1269 /// }
1270 ///
1271 /// assert_eq!( this.a, [2u8, 3] );
1272 /// assert_eq!( this.b, true );
1273 ///
1274 /// ```
1275 #[inline(always)]
1276 pub unsafe fn replace(self, destination: *mut S, value: F) -> F {
1277 impl_fo!(fn replace<S, F, Aligned>(self, destination, value))
1278 }
1279
1280 /// Replaces the value of a field in `destination` with `value`,
1281 /// returning the old value of the field.
1282 ///
1283 /// # Example
1284 ///
1285 /// ```rust
1286 /// # #![deny(safe_packed_borrows)]
1287 /// use repr_offset::for_examples::ReprC;
1288 ///
1289 /// let mut this = ReprC{ a: [0u8, 1], b: false, c: (), d: () };
1290 ///
1291 /// assert_eq!( ReprC::OFFSET_A.replace_mut(&mut this, [2, 3]), [0u8, 1] );
1292 /// assert_eq!( ReprC::OFFSET_B.replace_mut(&mut this, true), false );
1293 ///
1294 /// assert_eq!( this.a, [2u8, 3] );
1295 /// assert_eq!( this.b, true );
1296 ///
1297 /// ```
1298 #[inline(always)]
1299 pub fn replace_mut(self, destination: &mut S, value: F) -> F {
1300 unsafe { impl_fo!(fn replace_mut<S, F, Aligned>(self, destination, value)) }
1301 }
1302
1303 /// Swaps the values of a field between the `left` and `right` pointers.
1304 ///
1305 /// # Safety
1306 ///
1307 /// This function has the same safety requirements as
1308 /// [`std::ptr::swap`](https://doc.rust-lang.org/std/ptr/fn.swap.html).
1309 ///
1310 /// Those safety requirements only apply to the field that this is an offset for,
1311 /// fields after it or before it don't need to be valid to call this method.
1312 ///
1313 /// # Example
1314 ///
1315 /// ```rust
1316 /// # #![deny(safe_packed_borrows)]
1317 /// use repr_offset::for_examples::ReprC;
1318 ///
1319 /// let mut this = ReprC{ a: '=', b: 64u16, c: (), d: () };
1320 /// let mut other = ReprC{ a: '!', b: 255u16, c: (), d: () };
1321 ///
1322 /// let this_ptr: *mut _ = &mut this;
1323 /// let other_ptr: *mut _ = &mut other;
1324 /// unsafe{
1325 /// ReprC::OFFSET_A.swap(this_ptr, other_ptr);
1326 /// ReprC::OFFSET_B.swap(this_ptr, other_ptr);
1327 /// }
1328 /// assert_eq!( this.a, '!' );
1329 /// assert_eq!( this.b, 255 );
1330 ///
1331 /// assert_eq!( other.a, '=' );
1332 /// assert_eq!( other.b, 64 );
1333 ///
1334 /// ```
1335 #[inline(always)]
1336 pub unsafe fn swap(self, left: *mut S, right: *mut S) {
1337 impl_fo!(fn swap<S, F, Aligned>(self, left, right))
1338 }
1339
1340 /// Swaps the values of a field between the `left` and `right` non-overlapping pointers.
1341 ///
1342 /// # Safety
1343 ///
1344 /// This function has the same safety requirements as
1345 /// [`std::ptr::swap_nonoverlapping`
1346 /// ](https://doc.rust-lang.org/std/ptr/fn.swap_nonoverlapping.html).
1347 ///
1348 /// Those safety requirements only apply to the field that this is an offset for,
1349 /// fields after it or before it don't need to be valid to call this method.
1350 ///
1351 /// # Example
1352 ///
1353 /// ```rust
1354 /// # #![deny(safe_packed_borrows)]
1355 /// use repr_offset::for_examples::ReprC;
1356 ///
1357 /// let mut this = ReprC{ a: [false, true], b: &27u32, c: (), d: () };
1358 /// let mut other = ReprC{ a: [true, false], b: &81u32, c: (), d: () };
1359 ///
1360 /// let this_ptr: *mut _ = &mut this;
1361 /// let other_ptr: *mut _ = &mut other;
1362 /// unsafe{
1363 /// ReprC::OFFSET_A.swap_nonoverlapping(this_ptr, other_ptr);
1364 /// ReprC::OFFSET_B.swap_nonoverlapping(this_ptr, other_ptr);
1365 /// }
1366 /// assert_eq!( this.a, [true, false] );
1367 /// assert_eq!( this.b, &81 );
1368 ///
1369 /// assert_eq!( other.a, [false, true] );
1370 /// assert_eq!( other.b, &27 );
1371 ///
1372 /// ```
1373 ///
1374 #[inline(always)]
1375 pub unsafe fn swap_nonoverlapping(self, left: *mut S, right: *mut S) {
1376 impl_fo!(fn swap_nonoverlapping<S, F, Aligned>(self, left, right))
1377 }
1378
1379 /// Swaps the values of a field between `left` and `right`.
1380 ///
1381 /// # Example
1382 ///
1383 /// ```rust
1384 /// # #![deny(safe_packed_borrows)]
1385 /// use repr_offset::for_examples::ReprC;
1386 ///
1387 /// let mut this = ReprC{ a: [true, true], b: 0x0Fu8, c: (), d: () };
1388 /// let mut other = ReprC{ a: [false, false], b: 0xF0u8, c: (), d: () };
1389 ///
1390 /// ReprC::OFFSET_A.swap_mut(&mut this, &mut other);
1391 /// ReprC::OFFSET_B.swap_mut(&mut this, &mut other);
1392 ///
1393 /// assert_eq!( this.a, [false, false] );
1394 /// assert_eq!( this.b, 0xF0u8 );
1395 ///
1396 /// assert_eq!( other.a, [true, true] );
1397 /// assert_eq!( other.b, 0x0Fu8 );
1398 ///
1399 /// ```
1400 ///
1401 #[inline(always)]
1402 pub fn swap_mut(self, left: &mut S, right: &mut S) {
1403 unsafe { impl_fo!(fn swap_mut<S, F, Aligned>(self, left, right)) }
1404 }
1405}
1406
1407impl<S, F> FieldOffset<S, F, Unaligned> {
1408 /// Copies the unaligned field that this is an offset for.
1409 ///
1410 /// # Example
1411 ///
1412 /// ```rust
1413 /// # #![deny(safe_packed_borrows)]
1414 /// use repr_offset::for_examples::ReprPacked;
1415 ///
1416 /// let this = ReprPacked{ a: Some(false), b: [8i32, 13, 21], c: (), d: () };
1417 ///
1418 /// assert_eq!( ReprPacked::OFFSET_A.get_copy(&this), Some(false) );
1419 /// assert_eq!( ReprPacked::OFFSET_B.get_copy(&this), [8i32, 13, 21] );
1420 ///
1421 /// ```
1422 ///
1423 /// This method can't be called for non-Copy fields.
1424 /// ```compile_fail
1425 /// # #![deny(safe_packed_borrows)]
1426 /// use repr_offset::for_examples::ReprPacked;
1427 ///
1428 /// let this = ReprPacked{ a: vec![0, 1, 2], b: (), c: (), d: () };
1429 ///
1430 /// let _ = ReprPacked::OFFSET_A.get_copy(&this);
1431 ///
1432 /// ```
1433 #[inline(always)]
1434 pub fn get_copy(self, base: &S) -> F
1435 where
1436 F: Copy,
1437 {
1438 unsafe { impl_fo!(fn get_copy<S, F, Unaligned>(self, base)) }
1439 }
1440
1441 /// Copies the unaligned field that this is an offset for.
1442 ///
1443 /// # Safety
1444 ///
1445 /// This function has the same safety requirements as
1446 /// [`std::ptr::read_unaligned`](https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html).
1447 ///
1448 /// Those safety requirements only apply to the field that this is an offset for,
1449 /// fields after it or before it don't need to be valid to call this method.
1450 ///
1451 /// # Example
1452 ///
1453 /// ```rust
1454 /// # #![deny(safe_packed_borrows)]
1455 /// use repr_offset::for_examples::ReprPacked;
1456 ///
1457 /// let this = ReprPacked{ a: 10u8, b: "20", c: (), d: () };
1458 ///
1459 /// let ptr: *const _ = &this;
1460 /// unsafe{
1461 /// assert_eq!( ReprPacked::OFFSET_A.read_copy(ptr), 10u8 );
1462 /// assert_eq!( ReprPacked::OFFSET_B.read_copy(ptr), "20" );
1463 /// }
1464 /// ```
1465 ///
1466 /// This method can't be called for non-Copy fields.
1467 /// ```compile_fail
1468 /// # #![deny(safe_packed_borrows)]
1469 /// use repr_offset::for_examples::ReprPacked;
1470 ///
1471 /// let this = ReprPacked{ a: vec![0, 1, 2], b: "20", c: (), d: () };
1472 ///
1473 /// unsafe{
1474 /// let _ = ReprPacked::OFFSET_A.read_copy(&this);
1475 /// }
1476 /// ```
1477 #[inline(always)]
1478 pub unsafe fn read_copy(self, base: *const S) -> F
1479 where
1480 F: Copy,
1481 {
1482 impl_fo!(fn read_copy<S, F, Unaligned>(self, base))
1483 }
1484
1485 /// Reads the value from the field in `source` without moving it.
1486 ///
1487 /// # Safety
1488 ///
1489 /// This function has the same safety requirements as
1490 /// [`std::ptr::read_unaligned`](https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html).
1491 ///
1492 /// Those safety requirements only apply to the field that this is an offset for,
1493 /// fields after it or before it don't need to be valid to call this method.
1494 ///
1495 /// # Example
1496 ///
1497 /// ```rust
1498 /// # #![deny(safe_packed_borrows)]
1499 /// use repr_offset::for_examples::ReprPacked;
1500 ///
1501 /// use std::mem::ManuallyDrop;
1502 ///
1503 /// let this = ManuallyDrop::new(ReprPacked{
1504 /// a: vec![0, 1, 2],
1505 /// b: "20".to_string(),
1506 /// c: (),
1507 /// d: (),
1508 /// });
1509 ///
1510 /// let ptr: *const _ = &*this;
1511 /// unsafe{
1512 /// assert_eq!( ReprPacked::OFFSET_A.read(ptr), vec![0, 1, 2] );
1513 /// assert_eq!( ReprPacked::OFFSET_B.read(ptr), "20".to_string() );
1514 /// }
1515 ///
1516 /// ```
1517 #[inline(always)]
1518 pub unsafe fn read(self, source: *const S) -> F {
1519 impl_fo!(fn read<S, F, Unaligned>(self, source))
1520 }
1521
1522 /// Writes `value` ìnto the field in `source` without dropping the old value of the field.
1523 ///
1524 /// # Safety
1525 ///
1526 /// This function has the same safety requirements as
1527 /// [`std::ptr::write_unaligned`](https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html).
1528 ///
1529 /// Those safety requirements only apply to the field that this is an offset for,
1530 /// fields after it or before it don't need to be valid to call this method.
1531 ///
1532 ///
1533 /// # Example
1534 ///
1535 /// ```rust
1536 /// # #![deny(safe_packed_borrows)]
1537 /// use repr_offset::for_examples::ReprPacked;
1538 /// use repr_offset::utils::moved;
1539 ///
1540 /// let mut this = ReprPacked{ a: 10u8, b: "20", c: (), d: () };
1541 ///
1542 /// let ptr: *mut _ = &mut this;
1543 /// unsafe{
1544 /// ReprPacked::OFFSET_A.write(ptr, 13u8);
1545 /// ReprPacked::OFFSET_B.write(ptr, "21");
1546 /// }
1547 /// assert_eq!( moved(this.a), 13u8 );
1548 /// assert_eq!( moved(this.b), "21" );
1549 ///
1550 /// ```
1551 #[inline(always)]
1552 pub unsafe fn write(self, source: *mut S, value: F) {
1553 impl_fo!(fn write<S, F, Unaligned>(self, source, value))
1554 }
1555
1556 /// Copies the field in `source` into `destination`.
1557 ///
1558 /// # Safety
1559 ///
1560 /// This function has the same safety requirements as
1561 /// [`std::ptr::copy`](https://doc.rust-lang.org/std/ptr/fn.copy.html),
1562 /// except that `source` and `destination` do not need to be properly aligned.
1563 ///
1564 /// Those safety requirements only apply to the field that this is an offset for,
1565 /// fields after it or before it don't need to be valid to call this method.
1566 ///
1567 /// # Example
1568 ///
1569 /// ```rust
1570 /// # #![deny(safe_packed_borrows)]
1571 /// use repr_offset::for_examples::ReprPacked;
1572 /// use repr_offset::utils::moved;
1573 ///
1574 ///
1575 /// let this = ReprPacked{ a: 10u8, b: "20", c: (), d: () };
1576 /// let mut other = ReprPacked{ a: 0u8, b: "", c: (), d: () };
1577 ///
1578 /// let this_ptr: *const _ = &this;
1579 /// let other_ptr: *mut _ = &mut other;
1580 /// unsafe{
1581 /// ReprPacked::OFFSET_A.copy(this_ptr, other_ptr);
1582 /// ReprPacked::OFFSET_B.copy(this_ptr, other_ptr);
1583 /// }
1584 /// assert_eq!( moved(this.a), 10u8 );
1585 /// assert_eq!( moved(this.b), "20" );
1586 ///
1587 /// assert_eq!( moved(other.a), 10u8 );
1588 /// assert_eq!( moved(other.b), "20" );
1589 ///
1590 /// ```
1591 #[inline(always)]
1592 pub unsafe fn copy(self, source: *const S, destination: *mut S) {
1593 impl_fo!(fn copy<S, F, Unaligned>(self, source, destination))
1594 }
1595
1596 /// Copies the field in `source` into `destination`,
1597 /// `source` and `destination` must not overlap.
1598 ///
1599 /// # Safety
1600 ///
1601 /// This function has the same safety requirements as
1602 /// [`std::ptr::copy_nonoverlapping`
1603 /// ](https://doc.rust-lang.org/std/ptr/fn.copy_nonoverlapping.html),
1604 /// except that `source` and `destination` do not need to be properly aligned.
1605 ///
1606 /// Those safety requirements only apply to the field that this is an offset for,
1607 /// fields after it or before it don't need to be valid to call this method.
1608 ///
1609 /// # Example
1610 ///
1611 /// ```rust
1612 /// # #![deny(safe_packed_borrows)]
1613 /// use repr_offset::for_examples::ReprPacked;
1614 /// use repr_offset::utils::moved;
1615 ///
1616 /// let this = ReprPacked{ a: '#', b: 81, c: (), d: () };
1617 /// let mut other = ReprPacked{ a: '_', b: 0, c: (), d: () };
1618 ///
1619 /// let this_ptr: *const _ = &this;
1620 /// let other_ptr: *mut _ = &mut other;
1621 /// unsafe{
1622 /// ReprPacked::OFFSET_A.copy_nonoverlapping(this_ptr, other_ptr);
1623 /// ReprPacked::OFFSET_B.copy_nonoverlapping(this_ptr, other_ptr);
1624 /// }
1625 /// assert_eq!( moved(this.a), '#' );
1626 /// assert_eq!( moved(this.b), 81 );
1627 ///
1628 /// assert_eq!( moved(other.a), '#' );
1629 /// assert_eq!( moved(other.b), 81 );
1630 ///
1631 /// ```
1632 #[inline(always)]
1633 pub unsafe fn copy_nonoverlapping(self, source: *const S, destination: *mut S) {
1634 impl_fo!(fn copy_nonoverlapping<S, F, Unaligned>(self, source, destination))
1635 }
1636}
1637
1638impl<S, F> FieldOffset<S, F, Unaligned> {
1639 /// Replaces the value of a field in `dest` with `value`,
1640 /// returning the old value of the field.
1641 ///
1642 /// # Safety
1643 ///
1644 /// This function has the same safety requirements as
1645 /// [`std::ptr::replace`](https://doc.rust-lang.org/std/ptr/fn.replace.html),
1646 /// except that `dest` does not need to be properly aligned.
1647 ///
1648 /// Those safety requirements only apply to the field that this is an offset for,
1649 /// fields after it or before it don't need to be valid to call this method.
1650 ///
1651 /// # Example
1652 ///
1653 /// ```rust
1654 /// # #![deny(safe_packed_borrows)]
1655 /// use repr_offset::for_examples::ReprPacked;
1656 /// use repr_offset::utils::moved;
1657 ///
1658 /// let mut this = ReprPacked{ a: [0u8, 1], b: false, c: (), d: () };
1659 ///
1660 /// let ptr: *mut _ = &mut this;
1661 /// unsafe{
1662 /// assert_eq!( ReprPacked::OFFSET_A.replace(ptr, [2, 3]), [0u8, 1] );
1663 /// assert_eq!( ReprPacked::OFFSET_B.replace(ptr, true), false );
1664 /// }
1665 ///
1666 /// assert_eq!( moved(this.a), [2u8, 3] );
1667 /// assert_eq!( moved(this.b), true );
1668 ///
1669 /// ```
1670 #[inline(always)]
1671 pub unsafe fn replace(self, dest: *mut S, value: F) -> F {
1672 impl_fo!(fn replace<S, F, Unaligned>(self, dest, value))
1673 }
1674
1675 /// Replaces the value of a field in `dest` with `value`,
1676 /// returning the old value of the field.
1677 ///
1678 ///
1679 /// # Example
1680 ///
1681 /// ```rust
1682 /// # #![deny(safe_packed_borrows)]
1683 /// use repr_offset::for_examples::ReprPacked;
1684 /// use repr_offset::utils::moved;
1685 ///
1686 /// let mut this = ReprPacked{ a: [0u8, 1], b: false, c: (), d: () };
1687 ///
1688 /// assert_eq!( ReprPacked::OFFSET_A.replace_mut(&mut this, [2, 3]), [0u8, 1] );
1689 /// assert_eq!( ReprPacked::OFFSET_B.replace_mut(&mut this, true), false );
1690 ///
1691 /// assert_eq!( moved(this.a), [2u8, 3] );
1692 /// assert_eq!( moved(this.b), true );
1693 ///
1694 /// ```
1695 pub fn replace_mut(self, dest: &mut S, value: F) -> F {
1696 unsafe { impl_fo!(fn replace_mut<S, F, Unaligned>(self, dest, value)) }
1697 }
1698}
1699
1700impl<S, F> FieldOffset<S, F, Unaligned> {
1701 /// Swaps the values of a field between the `left` and `right` pointers.
1702 ///
1703 /// # Safety
1704 ///
1705 /// This function has the same safety requirements as
1706 /// [`std::ptr::swap`](https://doc.rust-lang.org/std/ptr/fn.swap.html),
1707 /// except that it does not require aligned pointers.
1708 ///
1709 /// Those safety requirements only apply to the field that this is an offset for,
1710 /// fields after it or before it don't need to be valid to call this method.
1711 ///
1712 /// # Example
1713 ///
1714 /// ```rust
1715 /// # #![deny(safe_packed_borrows)]
1716 /// use repr_offset::for_examples::ReprPacked;
1717 /// use repr_offset::utils::moved;
1718 ///
1719 /// let mut this = ReprPacked{ a: '=', b: 64u16, c: (), d: () };
1720 /// let mut other = ReprPacked{ a: '!', b: 255u16, c: (), d: () };
1721 ///
1722 /// let this_ptr: *mut _ = &mut this;
1723 /// let other_ptr: *mut _ = &mut other;
1724 /// unsafe{
1725 /// ReprPacked::OFFSET_A.swap(this_ptr, other_ptr);
1726 /// ReprPacked::OFFSET_B.swap(this_ptr, other_ptr);
1727 /// }
1728 /// assert_eq!( moved(this.a), '!' );
1729 /// assert_eq!( moved(this.b), 255 );
1730 ///
1731 /// assert_eq!( moved(other.a), '=' );
1732 /// assert_eq!( moved(other.b), 64 );
1733 ///
1734 /// ```
1735 #[inline(always)]
1736 pub unsafe fn swap(self, left: *mut S, right: *mut S) {
1737 impl_fo!(fn swap<S, F, Unaligned>(self, left, right))
1738 }
1739
1740 /// Swaps the values of a field between the non-overlapping `left` and `right` pointers.
1741 ///
1742 /// # Safety
1743 ///
1744 /// This function has the same safety requirements as
1745 /// [`std::ptr::swap_nonoverlapping`
1746 /// ](https://doc.rust-lang.org/std/ptr/fn.swap_nonoverlapping.html)
1747 /// except that it does not require aligned pointers.
1748 ///
1749 /// Those safety requirements only apply to the field that this is an offset for,
1750 /// fields after it or before it don't need to be valid to call this method.
1751 ///
1752 /// # Example
1753 ///
1754 /// ```rust
1755 /// # #![deny(safe_packed_borrows)]
1756 /// use repr_offset::for_examples::ReprPacked;
1757 /// use repr_offset::utils::moved;
1758 ///
1759 /// let mut this = ReprPacked{ a: [false, true], b: &27u32, c: (), d: () };
1760 /// let mut other = ReprPacked{ a: [true, false], b: &81u32, c: (), d: () };
1761 ///
1762 /// let this_ptr: *mut _ = &mut this;
1763 /// let other_ptr: *mut _ = &mut other;
1764 /// unsafe{
1765 /// ReprPacked::OFFSET_A.swap_nonoverlapping(this_ptr, other_ptr);
1766 /// ReprPacked::OFFSET_B.swap_nonoverlapping(this_ptr, other_ptr);
1767 /// }
1768 /// assert_eq!( moved(this.a), [true, false] );
1769 /// assert_eq!( moved(this.b), &81 );
1770 ///
1771 /// assert_eq!( moved(other.a), [false, true] );
1772 /// assert_eq!( moved(other.b), &27 );
1773 ///
1774 /// ```
1775 ///
1776 #[inline(always)]
1777 pub unsafe fn swap_nonoverlapping(self, left: *mut S, right: *mut S) {
1778 impl_fo!(fn swap_nonoverlapping<S, F, Unaligned>(self, left, right))
1779 }
1780
1781 /// Swaps the values of a field between `left` and `right`.
1782 ///
1783 /// # Example
1784 ///
1785 /// ```rust
1786 /// # #![deny(safe_packed_borrows)]
1787 /// use repr_offset::for_examples::ReprPacked;
1788 /// use repr_offset::utils::moved;
1789 ///
1790 /// let mut this = ReprPacked{ a: [true, true], b: 0x0Fu8, c: (), d: () };
1791 /// let mut other = ReprPacked{ a: [false, false], b: 0xF0u8, c: (), d: () };
1792 ///
1793 /// ReprPacked::OFFSET_A.swap_mut(&mut this, &mut other);
1794 /// ReprPacked::OFFSET_B.swap_mut(&mut this, &mut other);
1795 ///
1796 /// assert_eq!( moved(this.a), [false, false] );
1797 /// assert_eq!( moved(this.b), 0xF0u8 );
1798 ///
1799 /// assert_eq!( moved(other.a), [true, true] );
1800 /// assert_eq!( moved(other.b), 0x0Fu8 );
1801 ///
1802 /// ```
1803 ///
1804 #[inline(always)]
1805 pub fn swap_mut(self, left: &mut S, right: &mut S) {
1806 unsafe { impl_fo!(fn swap_mut<S, F, Unaligned>(self, left, right)) }
1807 }
1808}
1809
1810#[cfg(test)]
1811mod tests {
1812 use super::*;
1813
1814 use crate::types_for_tests::StructPacked;
1815
1816 use core::mem;
1817
1818 #[test]
1819 fn test_constructor_offset() {
1820 unsafe {
1821 let field_0 = FieldOffset::<(u128,), u8, Aligned>::new(0);
1822 let field_1 = field_0.next_field_offset::<u32, Aligned>();
1823 assert_eq!(field_0.offset(), 0);
1824 assert_eq!(field_1.offset(), mem::align_of::<u32>());
1825 }
1826 unsafe {
1827 let field_0 = FieldOffset::<StructPacked<u128, (), (), ()>, u8, Unaligned>::new(0);
1828 let field_1 = field_0.next_field_offset::<u32, Unaligned>();
1829 let field_2 = field_1.next_field_offset::<&'static str, Unaligned>();
1830 assert_eq!(field_0.offset(), 0);
1831 assert_eq!(field_1.offset(), 1);
1832 assert_eq!(field_2.offset(), 5);
1833 }
1834 }
1835}