repr_offset/
ext.rs

1//! Extension traits that use `FieldOffset` parameters to operate on fields.
2//!
3//! These are the extension traits for each kind of type:
4//!
5//! - non-pointer / `&T` / `&mut T`: [`ROExtAcc`] and [`ROExtOps`]
6//!
7//! - `*const T` and `*mut T`: [`ROExtRawAcc`] and [`ROExtRawOps`]
8//!
9//! - `*mut T`: [`ROExtRawMutAcc`] and [`ROExtRawMutOps`]
10//!
11//! # Imports
12//!
13//! Here is the code to import all of the extension traits for convenience:
14//! ```rust
15//! use repr_offset::{ROExtAcc, ROExtOps, ROExtRawAcc, ROExtRawMutAcc, ROExtRawOps, ROExtRawMutOps};
16//! ```
17//!
18//! # Examples
19//!
20//! # Initializing Types
21//!
22//! ```rust
23//! use repr_offset::{
24//!     for_examples::ReprC,
25//!     off,
26//!     ROExtRawMutOps,
27//! };
28//!
29//! use std::mem::MaybeUninit;
30//!
31//! type This = ReprC<String, Vec<u8>, usize, Option<char>>;
32//!
33//! let this = unsafe{
34//!     let mut uninit = MaybeUninit::<This>::uninit();
35//!     initialize_this(uninit.as_mut_ptr());
36//!     uninit.assume_init()
37//! };
38//!
39//! assert_eq!(this.a, "foo");
40//! assert_eq!(this.b, [3, 5, 8]);
41//! assert_eq!(this.c, 13);
42//! assert_eq!(this.d, Some('_'));
43//!
44//! /// Initializes `this`
45//! ///
46//! /// # Safety
47//! ///
48//! /// The passed in pointer must point to an aligned, allocated `This` (including on the stack).
49//! unsafe fn initialize_this(this: *mut This) {
50//!     this.f_write(off!(a), "foo".to_string());
51//!     this.f_write(off!(b), vec![3, 5, 8]);
52//!     this.f_write(off!(c), 13_usize);
53//!     this.f_write(off!(d), Some('_'));
54//! }
55//!
56//! ```
57//!
58//!
59//!
60//! [`ROExtAcc`]: ./trait.ROExtAcc.html
61//! [`ROExtOps`]: ./trait.ROExtOps.html
62//! [`ROExtRawAcc`]: ./trait.ROExtRawAcc.html
63//! [`ROExtRawMutAcc`]: ./trait.ROExtRawMutAcc.html
64//! [`ROExtRawOps`]: ./trait.ROExtRawOps.html
65//! [`ROExtRawMutOps`]: ./trait.ROExtRawMutOps.html
66//!
67//! [`FieldOffset`]: ../struct.FieldOffset.html
68
69use crate::{Aligned, FieldOffset};
70
71/// Extension trait for (mutable) references to access fields generically,
72/// where the field is determined by a [`FieldOffset`] parameter.
73///
74///
75/// # Safety
76///
77/// This trait must not to be implemented outside the `repr_offset` crate.
78///
79/// # Examples
80///
81/// ### Unaligned field pointers
82///
83/// Getting raw pointers to all fields in a packed struct.
84///
85/// ```rust
86/// # #![deny(safe_packed_borrows)]
87/// use repr_offset::{
88///     for_examples::ReprPacked,
89///     ROExtAcc,
90///     off,
91/// };
92///
93/// type This = ReprPacked<u8, Option<usize>, &'static [u16], &'static str>;
94///
95/// let value: This = ReprPacked {
96///     a: 3,
97///     b: Some(5),
98///     c: &[0, 1, 2],
99///     d: "hello",
100/// };
101///
102/// unsafe {
103///     let (a_ptr, b_ptr, c_ptr, d_ptr) = get_field_ptrs(&value);
104///     assert_eq!(a_ptr.read_unaligned(), 3);
105///     assert_eq!(b_ptr.read_unaligned(), Some(5));
106///     assert_eq!(c_ptr.read_unaligned(), &[0, 1, 2]);
107///     assert_eq!(d_ptr.read_unaligned(), "hello");
108/// }
109///
110/// // Note: the mutable version of this function couldn't use `f_get_mut_ptr`,
111/// //       it must use `ROExtRawMutAcc::f_raw_get_mut`
112/// fn get_field_ptrs(
113///     this: &This,
114/// ) -> (*const u8, *const Option<usize>, *const &'static [u16], *const &'static str) {
115///     (
116///         this.f_get_ptr(off!(a)),
117///         this.f_get_ptr(off!(b)),
118///         this.f_get_ptr(off!(c)),
119///         this.f_get_ptr(off!(d)),
120///     )
121/// }
122///
123/// ```
124///
125/// [`FieldOffset`]: ../struct.FieldOffset.html
126//
127// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
128//
129pub unsafe trait ROExtAcc: Sized {
130    /// Gets a reference to a field, determined by `offset`.
131    ///
132    /// # Example
133    ///
134    /// ```rust
135    /// # #![deny(safe_packed_borrows)]
136    /// use repr_offset::{
137    ///     for_examples::ReprC,
138    ///     ROExtAcc, off,
139    /// };
140    ///
141    /// let value = ReprC {
142    ///     a: 3,
143    ///     b: "foo",
144    ///     c: ReprC {
145    ///         a: 5,
146    ///         b: "bar",
147    ///         c: 8,
148    ///         d: 13,
149    ///     },
150    ///     d: false,
151    /// };
152    ///
153    /// assert_eq!(value.f_get(off!(a)), &3);
154    /// assert_eq!(value.f_get(off!(c.a)), &5);
155    /// assert_eq!(value.f_get(off!(c.b)), &"bar");
156    ///
157    ///
158    /// ```
159    fn f_get<F>(&self, offset: FieldOffset<Self, F, Aligned>) -> &F;
160
161    /// Gets a muatble reference to a field, determined by `offset`.
162    ///
163    /// # Example
164    ///
165    /// ```rust
166    /// # #![deny(safe_packed_borrows)]
167    /// use repr_offset::{
168    ///     for_examples::{ReprAlign4, ReprC},
169    ///     ROExtAcc, off,
170    /// };
171    ///
172    /// use std::cmp::Ordering;
173    ///
174    /// let mut value = ReprC {
175    ///     a: 3,
176    ///     b: Some(5),
177    ///     c: Ordering::Less,
178    ///     d: ReprAlign4 {
179    ///         a: 8,
180    ///         b: "bar",
181    ///         c: 13,
182    ///         d: 21,
183    ///     },
184    /// };
185    ///
186    /// let foo = value.f_get_mut(off!(a));
187    /// assert_eq!(foo, &mut 3);
188    /// *foo += 100;
189    /// assert_eq!(value.a, 103);
190    ///
191    /// let bar = value.f_get_mut(off!(d.a));
192    /// assert_eq!(bar, &mut 8);
193    ///
194    /// let baz = value.f_get_mut(off!(d.d));
195    /// assert_eq!(baz, &mut 21);
196    /// *baz += 300;
197    /// assert_eq!(value.d.d, 321);
198    ///
199    /// ```
200    ///
201    fn f_get_mut<F>(&mut self, offset: FieldOffset<Self, F, Aligned>) -> &mut F;
202
203    /// Gets a const pointer to a field,
204    /// the field is determined by `offset`.
205    ///
206    /// # Example
207    ///
208    /// ```rust
209    /// # #![deny(safe_packed_borrows)]
210    /// use repr_offset::{
211    ///     for_examples::ReprC,
212    ///     ROExtAcc, off,
213    /// };
214    ///
215    /// let value = ReprC {
216    ///     a: 3,
217    ///     b: "foo",
218    ///     c: ReprC {
219    ///         a: 5,
220    ///         b: "bar",
221    ///         c: 8,
222    ///         d: 13,
223    ///     },
224    ///     d: false,
225    /// };
226    ///
227    /// unsafe {
228    ///     assert_eq!(value.f_get_ptr(off!(a)).read(), 3);
229    ///     assert_eq!(value.f_get_ptr(off!(c.a)).read(), 5);
230    ///     assert_eq!(value.f_get_ptr(off!(c.b)).read(), "bar");
231    /// }
232    ///
233    /// ```
234    fn f_get_ptr<F, A>(&self, offset: FieldOffset<Self, F, A>) -> *const F;
235
236    /// Gets a mutable pointer to a field, determined by `offset`.
237    ///
238    /// # Example
239    ///
240    /// ```rust
241    /// # #![deny(safe_packed_borrows)]
242    /// use repr_offset::{
243    ///     for_examples::{ReprC, ReprPacked},
244    ///     utils::moved,
245    ///     ROExtAcc, off,
246    /// };
247    ///
248    /// use std::cmp::Ordering;
249    ///
250    /// let mut value = ReprPacked {
251    ///     a: 3,
252    ///     b: Some(5),
253    ///     c: Ordering::Less,
254    ///     d: ReprC {
255    ///         a: 8,
256    ///         b: "bar",
257    ///         c: 13,
258    ///         d: 21,
259    ///     },
260    /// };
261    ///
262    /// unsafe {
263    ///     let foo = value.f_get_mut_ptr(off!(a));
264    ///     let old_a = foo.read_unaligned();
265    ///     assert_eq!(old_a, 3);
266    ///     foo.write_unaligned(old_a + 100);
267    ///     // the `moved` function prevents the creation of a reference to the packed field.
268    ///     assert_eq!(moved(value.a), 103);
269    ///     
270    ///     let baz = value.f_get_mut_ptr(off!(d.d));
271    ///     let old_dd = baz.read_unaligned();
272    ///     assert_eq!(old_dd, 21);
273    ///     baz.write_unaligned(old_dd + 300);
274    ///     // the `moved` function prevents the creation of a reference to the packed field.
275    ///     assert_eq!(moved(value.d.d), 321);
276    /// }
277    /// ```
278    fn f_get_mut_ptr<F, A>(&mut self, offset: FieldOffset<Self, F, A>) -> *mut F;
279}
280
281/// Extension trait for (mutable) references to do generic field operations,
282/// where the field is determined by a [`FieldOffset`] parameter.
283///
284///
285/// # Safety
286///
287/// This trait must not to be implemented outside the `repr_offset` crate.
288///
289/// # Alignment
290///
291/// The `A` type parameter is the [`Alignment`] of the field,
292/// used to implement methods differently depending on whether the field is
293/// [`Aligned`] or [`Unaligned`].
294///
295/// [`FieldOffset`]: ../struct.FieldOffset.html
296/// [`Alignment`]: ../alignment/trait.Alignment.html
297/// [`Aligned`]: ../alignment/struct.Aligned.html
298/// [`Unaligned`]: ../alignment/struct.Unaligned.html
299///
300///
301//
302// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
303//
304pub unsafe trait ROExtOps<A>: ROExtAcc {
305    /// Replaces a field (determined by `offset`) with `value`,
306    /// returning the previous value of the field.
307    ///
308    /// # Example
309    ///
310    /// ```rust
311    /// # #![deny(safe_packed_borrows)]
312    /// use repr_offset::{
313    ///     for_examples::ReprPacked,
314    ///     utils::moved,
315    ///     ROExtOps, off,
316    /// };
317    ///
318    /// let mut value = ReprPacked {
319    ///     a: 3u128,
320    ///     b: Some(5u64),
321    ///     c: vec![0, 1],
322    ///     d: (),
323    /// };
324    ///
325    /// assert_eq!(value.f_replace(off!(a), 200), 3);
326    /// assert_eq!(moved(value.a), 200);
327    ///
328    /// assert_eq!(value.f_replace(off!(b), None), Some(5));
329    /// assert_eq!(moved(value.b), None);
330    ///
331    /// assert_eq!(value.f_replace(off!(c), vec![2, 3]), vec![0, 1]);
332    /// assert_eq!(moved(value.c), vec![2, 3]);
333    ///
334    /// ```
335    fn f_replace<F>(&mut self, offset: FieldOffset<Self, F, A>, value: F) -> F;
336
337    /// Swaps a field (determined by `offset`) with the same field in `right`.
338    ///
339    /// # Example
340    ///
341    /// ```rust
342    /// # #![deny(safe_packed_borrows)]
343    /// use repr_offset::{
344    ///     for_examples::ReprC,
345    ///     ROExtOps, off,
346    /// };
347    ///
348    /// let mut left = ReprC {
349    ///     a: 3u128,
350    ///     b: Some(5u64),
351    ///     c: vec![0, 1],
352    ///     d: (),
353    /// };
354    /// let mut right = ReprC {
355    ///     a: 55,
356    ///     b: None,
357    ///     c: vec![89, 144],
358    ///     d: (),
359    /// };
360    ///
361    /// left.f_swap(off!(a), &mut right);
362    /// assert_eq!(left.a, 55);
363    /// assert_eq!(right.a, 3);
364    ///
365    /// left.f_swap(off!(b), &mut right);
366    /// assert_eq!(left.b, None);
367    /// assert_eq!(right.b, Some(5));
368    ///
369    /// left.f_swap(off!(c), &mut right);
370    /// assert_eq!(left.c, vec![89, 144]);
371    /// assert_eq!(right.c, vec![0, 1]);
372    ///
373    /// ```
374    fn f_swap<F>(&mut self, offset: FieldOffset<Self, F, A>, right: &mut Self);
375
376    /// Gets a copy of a field (determined by `offset`).
377    /// The field is determined by `offset`.
378    ///
379    /// # Example
380    ///
381    /// ```rust
382    /// # #![deny(safe_packed_borrows)]
383    /// use repr_offset::{
384    ///     for_examples::ReprPacked,
385    ///     ROExtOps, off,
386    /// };
387    ///
388    /// let value = ReprPacked {
389    ///     a: 3,
390    ///     b: "foo",
391    ///     c: 'g',
392    ///     d: false,
393    /// };
394    ///
395    /// assert_eq!(value.f_get_copy(off!(a)), 3);
396    /// assert_eq!(value.f_get_copy(off!(b)), "foo");
397    /// assert_eq!(value.f_get_copy(off!(c)), 'g');
398    /// assert_eq!(value.f_get_copy(off!(d)), false);
399    ///
400    ///
401    /// ```
402    fn f_get_copy<F>(&self, offset: FieldOffset<Self, F, A>) -> F
403    where
404        F: Copy;
405}
406
407/////////////////////////////////////////////////////////////////////////////////
408
409/// Extension trait for raw pointers to access fields generically,
410/// where the field is determined by a [`FieldOffset`] parameter.
411///
412///
413/// # Safety
414///
415/// This trait must not to be implemented outside the `repr_offset` crate.
416///
417/// # Example
418///
419/// This example shows how you can get references to known aligned fields from a raw pointer
420/// to a partially initialized value..
421///
422/// ```rust
423/// # #![deny(safe_packed_borrows)]
424/// use repr_offset::{
425///     for_examples::ReprC,
426///     off,
427///     ROExtRawAcc, ROExtRawMutOps,
428/// };
429///
430/// use std::mem::MaybeUninit;
431///
432/// type This = ReprC<u8, Option<usize>, &'static [u16], &'static str>;
433///
434/// let mut uninit = MaybeUninit::<This>::uninit();
435///
436/// unsafe {
437///     let ptr = uninit.as_mut_ptr();
438///     ptr.f_write(off!(a), 3);
439///     ptr.f_write(off!(b), Some(5));
440///
441///     let (a, b) = get_init_refs(&uninit);
442///     assert_eq!(*a, 3);
443///     assert_eq!(*b, Some(5));
444/// }
445///
446/// /// # Safety
447/// ///
448/// /// The fields up to and including `b` must be initialized.
449/// unsafe fn get_init_refs(this: &MaybeUninit<This>) -> (&u8, &Option<usize>) {
450///     let this = this.as_ptr();
451///
452///     (
453///         &*this.f_raw_get(off!(a)),
454///         &*this.f_raw_get(off!(b)),
455///     )
456/// }
457///
458/// ```
459///
460///
461/// [`FieldOffset`]: ../struct.FieldOffset.html
462//
463// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
464pub unsafe trait ROExtRawAcc: crate::utils::PointerTarget {
465    /// Gets a raw pointer to a field (determined by `offset`) from this raw pointer.
466    ///
467    /// # Safety
468    ///
469    /// `self` must point to some allocated object,
470    /// allocated at least up to the field (inclusive).
471    ///
472    /// # Example
473    ///
474    /// ```rust
475    /// # #![deny(safe_packed_borrows)]
476    /// use repr_offset::{
477    ///     for_examples::{ReprC, ReprPacked},
478    ///     tstr::TS,
479    ///     GetPubFieldOffset, FieldType,
480    ///     ROExtRawAcc,
481    ///     pub_off,
482    /// };
483    ///
484    /// use std::cmp::Ordering;
485    ///
486    /// let value = ReprPacked {
487    ///     a: 3,
488    ///     b: Some(5),
489    ///     c: Ordering::Less,
490    ///     d: ReprC {
491    ///         a: 8,
492    ///         b: "bar",
493    ///         c: 13,
494    ///         d: 21,
495    ///     },
496    /// };
497    ///
498    /// unsafe {
499    ///     assert_eq!(copy_fields(&value), (3, 13));
500    /// }
501    ///
502    ///
503    /// /// Copies the `a` and `d.c` fields in this.
504    /// ///
505    /// /// # Safety
506    /// ///
507    /// /// The `a` and `d.c` fields in this must be initialized
508    /// unsafe fn copy_fields<T, O, U>(
509    ///     this: *const T,
510    /// ) -> (O, U)
511    /// where
512    ///     T: GetPubFieldOffset<TS!(a), Type = O>,
513    ///     T: GetPubFieldOffset<TS!(d,c), Type = U>,
514    ///     O: Copy,
515    ///     U: Copy,
516    /// {
517    ///     (
518    ///         this.f_raw_get(pub_off!(a)).read_unaligned(),
519    ///         this.f_raw_get(pub_off!(d.c)).read_unaligned(),
520    ///     )
521    /// }
522    ///
523    ///
524    /// ```
525    ///
526    unsafe fn f_raw_get<F, A>(self, offset: FieldOffset<Self::Target, F, A>) -> *const F;
527}
528
529/// Extension trait for mutable raw pointers to access fields generically,
530/// where the field is determined by a [`FieldOffset`] parameter.
531///
532///
533/// # Safety
534///
535/// This trait must not to be implemented outside the `repr_offset` crate.
536///
537/// # Example
538///
539/// This example demonstrates how you can get mutable references to the known initialized
540/// parts of a struct.
541///
542/// ```rust
543/// # #![deny(safe_packed_borrows)]
544/// use repr_offset::{
545///     for_examples::ReprC,
546///     tstr::TS,
547///     off,
548///     ROExtRawOps, ROExtRawMutAcc, ROExtRawMutOps,
549/// };
550///
551/// use std::mem::MaybeUninit;
552///
553/// type This = ReprC<u8, Option<usize>, &'static [u16], &'static str>;
554///
555/// let mut uninit = MaybeUninit::<This>::uninit();
556///
557/// unsafe {
558///     let ptr = uninit.as_mut_ptr();
559///     ptr.f_write(off!(a), 3);
560///     ptr.f_write(off!(b), Some(5));
561/// }
562/// {
563///     // Safety: We know that the a and b fields were initialized above.
564///     let (a, b) = unsafe{ get_mut_refs(&mut uninit) };
565///     assert_eq!(*a, 3);
566///     assert_eq!(*b, Some(5));
567///     *a += 100;
568///     *b.as_mut().unwrap() += 200;
569/// }
570/// unsafe {
571///     let ptr = uninit.as_ptr();
572///     assert_eq!(ptr.f_read_copy(off!(a)), 103);
573///     assert_eq!(ptr.f_read_copy(off!(b)), Some(205));
574/// }
575///
576/// /// Gets mutable references to the `a` and `b` fields in `this`
577/// ///
578/// /// # Safety
579/// ///
580/// /// The fields up to and including `b` must be initialized.
581/// unsafe fn get_mut_refs(this: &mut MaybeUninit<This>) -> (&mut u8, &mut Option<usize>) {
582///     let this = this.as_mut_ptr();
583///
584///     let ptrs = (
585///         this.f_raw_get_mut(off!(a)),
586///         this.f_raw_get_mut(off!(b)),
587///     );
588///
589///     (&mut *ptrs.0, &mut *ptrs.1)
590/// }
591///
592/// ```
593///
594/// [`FieldOffset`]: ../struct.FieldOffset.html
595//
596// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
597pub unsafe trait ROExtRawMutAcc: ROExtRawAcc {
598    /// Gets a muatble pointer to a field (determined by `offset`) from this mutable pointer.
599    ///
600    /// # Safety
601    ///
602    /// `self` must point to some allocated object,
603    /// allocated at least up to the field (inclusive).
604    ///
605    /// # Example
606    ///
607    /// ```rust
608    /// # #![deny(safe_packed_borrows)]
609    /// use repr_offset::{
610    ///     for_examples::{ReprC, ReprPacked},
611    ///     utils::moved,
612    ///     tstr::TS,
613    ///     GetPubFieldOffset, FieldType,
614    ///     ROExtRawMutAcc,
615    ///     off,
616    /// };
617    ///
618    /// use std::mem::MaybeUninit;
619    ///
620    /// type This = ReprPacked<Option<char>, ReprC<u32, u64, String, Vec<u32>>, bool>;
621    ///
622    /// let mut uninit = MaybeUninit::<This>::uninit();
623    ///
624    /// /// Initializes a `This` through a pointer
625    /// ///
626    /// /// # Safety
627    /// ///
628    /// /// You must pass a pointer to allocated (and writable) memory for `This`.
629    /// unsafe fn initialize(this: *mut This) {
630    ///     this.f_raw_get_mut(off!(a)).write_unaligned(None);
631    ///     this.f_raw_get_mut(off!(b.a)).write_unaligned(3);
632    ///     this.f_raw_get_mut(off!(b.b)).write_unaligned(5);
633    ///     this.f_raw_get_mut(off!(b.c)).write_unaligned("8".to_string());
634    ///     this.f_raw_get_mut(off!(b.d)).write_unaligned(vec![13, 21]);
635    ///     this.f_raw_get_mut(off!(c)).write_unaligned(false);
636    /// }
637    ///
638    /// let value = unsafe{
639    ///     initialize(uninit.as_mut_ptr());
640    ///     uninit.assume_init()
641    /// };
642    ///
643    /// assert_eq!(moved(value.a), None);
644    /// assert_eq!(moved(value.b.a), 3);
645    /// assert_eq!(moved(value.b.b), 5);
646    /// assert_eq!(moved(value.b.c), "8".to_string());
647    /// assert_eq!(moved(value.b.d), vec![13, 21]);
648    /// assert_eq!(moved(value.c), false);
649    ///
650    /// ```
651    ///
652    unsafe fn f_raw_get_mut<F, A>(self, offset: FieldOffset<Self::Target, F, A>) -> *mut F;
653}
654
655/// Extension trait for raw pointers to do generic field operations,
656/// where the field is determined by a [`FieldOffset`] parameter.
657///
658///
659/// # Safety
660///
661/// This trait must not to be implemented outside the `repr_offset` crate.
662///
663/// # Alignment
664///
665/// The `A` type parameter is the [`Alignment`] of the field,
666/// used to implement methods differently depending on whether the field is
667/// [`Aligned`] or [`Unaligned`].
668///
669/// [`FieldOffset`]: ../struct.FieldOffset.html
670/// [`Alignment`]: ../alignment/trait.Alignment.html
671/// [`Aligned`]: ../alignment/struct.Aligned.html
672/// [`Unaligned`]: ../alignment/struct.Unaligned.html
673//
674// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
675pub unsafe trait ROExtRawOps<A>: ROExtRawAcc {
676    /// Copies a field (determined by `offset`) from `self`.
677    ///
678    /// # Safety
679    ///
680    /// You must ensure these properties about the pointed-to value:
681    ///
682    /// - The value must be in an allocated object (this includes the stack)
683    /// allocated at least up to the field (inclusive).
684    ///
685    /// - The field must be initialized
686    ///
687    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
688    /// (because it is for an aligned field), `self` must be an aligned pointer.
689    ///
690    /// # Example
691    ///
692    /// ```rust
693    /// # #![deny(safe_packed_borrows)]
694    /// use repr_offset::{
695    ///     for_examples::ReprPacked,
696    ///     ROExtRawOps, off,
697    /// };
698    ///
699    /// use std::cmp::Ordering;
700    ///
701    /// let mut value = ReprPacked {
702    ///     a: 3,
703    ///     b: Some(5),
704    ///     c: Ordering::Less,
705    ///     d: (),
706    /// };
707    ///
708    /// let ptr: *const _ = &value;
709    /// unsafe {
710    ///     assert_eq!(ptr.f_read_copy(off!(a)), 3);
711    ///     assert_eq!(ptr.f_read_copy(off!(b)), Some(5));
712    ///     assert_eq!(ptr.f_read_copy(off!(c)), Ordering::Less);
713    /// }
714    /// ```
715    ///
716    unsafe fn f_read_copy<F>(self, offset: FieldOffset<Self::Target, F, A>) -> F
717    where
718        F: Copy;
719
720    /// Reads a copy of a field (determined by `offset`) from `self`,
721    /// without mutating or moving the field.
722    ///
723    /// # Safety
724    ///
725    /// You must ensure these properties about the pointed-to value:
726    ///
727    /// - The value must be in an allocated object (this includes the stack)
728    /// allocated at least up to the field (inclusive).
729    ///
730    /// - The field must be initialized
731    ///
732    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
733    /// (because it is for an aligned field), `self` must be an aligned pointer.
734    ///
735    /// # Example
736    ///
737    /// ```rust
738    /// # #![deny(safe_packed_borrows)]
739    /// use repr_offset::{
740    ///     for_examples::ReprPacked,
741    ///     ROExtRawOps, off,
742    /// };
743    ///
744    /// use std::{cmp::Ordering, mem::ManuallyDrop};
745    ///
746    /// let mut value = ManuallyDrop::new(ReprPacked {
747    ///     a: 3,
748    ///     b: Some(5),
749    ///     c: "hello".to_string(),
750    ///     d: vec![0, 1, 2],
751    /// });
752    ///
753    /// let ptr: *const ReprPacked<_, _, _, _> = &*value;
754    /// unsafe {
755    ///     assert_eq!(ptr.f_read(off!(a)), 3);
756    ///     assert_eq!(ptr.f_read(off!(b)), Some(5));
757    ///     assert_eq!(ptr.f_read(off!(c)), "hello".to_string());
758    ///     assert_eq!(ptr.f_read(off!(d)), vec![0, 1, 2]);
759    /// }
760    /// ```
761    ///
762    unsafe fn f_read<F>(self, offset: FieldOffset<Self::Target, F, A>) -> F;
763}
764
765/// Extension trait for mutable raw pointers to do generic field operations,
766/// where the field is determined by a [`FieldOffset`] parameter.
767///
768/// # Safety
769///
770/// This trait must not to be implemented outside the `repr_offset` crate.
771///
772/// # Alignment
773///
774/// The `A` type parameter is the [`Alignment`] of the field,
775/// used to implement methods differently depending on whether the field is
776/// [`Aligned`] or [`Unaligned`].
777///
778/// [`FieldOffset`]: ../struct.FieldOffset.html
779/// [`Alignment`]: ../alignment/trait.Alignment.html
780/// [`Aligned`]: ../alignment/struct.Aligned.html
781/// [`Unaligned`]: ../alignment/struct.Unaligned.html
782///
783/// # Example
784///
785/// This example shows how you can do the equivalent of `std::mem::replace`
786/// in partially initialized structs.
787///
788/// ```rust
789/// # #![deny(safe_packed_borrows)]
790/// use repr_offset::{
791///     for_examples::ReprPacked,
792///     utils::moved,
793///     ROExtRawMutOps, off,
794/// };
795///
796/// let mut value = ReprPacked {
797///     a: false,
798///     b: None,
799///     c: "",
800///     d: [0u64; 10],
801/// };
802///
803/// let (a, b) = unsafe{ replace_fields(&mut value, true, Some('!')) };
804///
805/// assert_eq!(moved(a), false);
806/// assert_eq!(moved(value.a), true);
807///
808/// assert_eq!(moved(b), None);
809/// assert_eq!(moved(value.b), Some('!'));
810///
811/// assert_eq!(moved(value.c), "");
812///
813///
814/// /// Replaces the `a` and `b` fields in `this`
815/// ///
816/// /// # Safety
817/// ///
818/// /// The fields up to and including `b` must be initialized.
819/// unsafe fn replace_fields(
820///     this: *mut ReprPacked<bool, Option<char>, &'static str, [u64; 10]>,
821///     a: bool,
822///     b: Option<char>,
823/// ) -> (bool, Option<char>) {
824///     (
825///         this.f_replace_raw(off!(a), a),
826///         this.f_replace_raw(off!(b), b),
827///     )
828/// }
829/// ```
830///
831//
832// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
833pub unsafe trait ROExtRawMutOps<A>: ROExtRawMutAcc {
834    /// Overwrites the value of a field (determined by `offset`) from `self`,
835    /// without dropping the previous value.
836    ///
837    /// # Safety
838    ///
839    /// You must ensure these properties:
840    ///
841    /// - `self` must point to an allocated object (this includes the stack)
842    /// allocated at least up to the field (inclusive).
843    ///
844    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
845    /// (because it is for an aligned field), `self` must be an aligned pointer.
846    ///
847    /// - The field must be writable(if in doubt, all of the pointed-to value).
848    ///
849    /// # Example
850    ///
851    /// ```rust
852    /// # #![deny(safe_packed_borrows)]
853    /// use repr_offset::{
854    ///     for_examples::ReprC,
855    ///     utils::moved,
856    ///     ROExtRawMutOps, off,
857    /// };
858    ///
859    /// let mut value = ReprC {
860    ///     a: 0,
861    ///     b: None::<u32>,
862    ///     c: Vec::new(),
863    ///     d: String::new(),
864    /// };
865    ///
866    /// let ptr: *mut _ = &mut value;
867    /// unsafe{
868    ///     ptr.f_write(off!(a), 3);
869    ///     ptr.f_write(off!(b), Some(5));
870    ///     ptr.f_write(off!(c), vec![8, 13]);
871    ///     ptr.f_write(off!(d), "world".to_string());
872    /// }
873    ///
874    /// assert_eq!(value.a, 3);
875    /// assert_eq!(value.b, Some(5));
876    /// assert_eq!(value.c, vec![8, 13]);
877    /// assert_eq!(value.d, "world".to_string());
878    ///
879    /// ```
880    ///
881    unsafe fn f_write<F>(self, offset: FieldOffset<Self::Target, F, A>, value: F);
882
883    /// Copies a field (determined by `offset`) from `source` to `self`.
884    ///
885    /// # Safety
886    ///
887    /// You must ensure these properties:
888    ///
889    /// - `self` and `source` must point to an allocated object (this includes the stack)
890    /// allocated at lest up to the field (inclusive).
891    ///
892    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
893    /// (because it is for an aligned field), both `self` and `source` must be aligned pointers.
894    ///
895    /// - The field must be writable (if in doubt, all of the pointed-to value must be writble).
896    ///
897    /// [`core::ptr::copy`] describes what happens when `self` ànd `source` overlap.
898    ///
899    ///
900    /// [`core::ptr::copy`]: https://doc.rust-lang.org/core/ptr/fn.copy.html
901    ///
902    ///
903    /// # Example
904    ///
905    /// ```rust
906    /// # #![deny(safe_packed_borrows)]
907    /// use repr_offset::{
908    ///     for_examples::ReprC,
909    ///     ROExtRawMutOps, off,
910    /// };
911    ///
912    /// let mut left = ReprC {
913    ///     a: 3u128,
914    ///     b: Some(5u64),
915    ///     c: &[8, 13, 21][..],
916    ///     d: (),
917    /// };
918    /// let right = ReprC {
919    ///     a: 55,
920    ///     b: None,
921    ///     c: &[34, 51, 89][..],
922    ///     d: (),
923    /// };
924    ///
925    /// let left_ptr: *mut _ = &mut left;
926    /// unsafe{
927    ///     left_ptr.f_copy_from(off!(a), &right);
928    ///     left_ptr.f_copy_from(off!(b), &right);
929    ///     left_ptr.f_copy_from(off!(c), &right);
930    /// }
931    ///
932    /// assert_eq!(left.a, 55);
933    /// assert_eq!(right.a, 55);
934    ///
935    /// assert_eq!(left.b, None);
936    /// assert_eq!(right.b, None);
937    ///
938    /// assert_eq!(left.c, &[34, 51, 89][..]);
939    /// assert_eq!(right.c, &[34, 51, 89][..]);
940    ///
941    ///
942    /// ```
943    ///
944    unsafe fn f_copy_from<F>(
945        self,
946        offset: FieldOffset<Self::Target, F, A>,
947        source: *const Self::Target,
948    );
949
950    /// Copies a field (determined by `offset`) from `source` to `self`.
951    ///
952    /// # Safety
953    ///
954    /// You must ensure these properties:
955    ///
956    /// - `self` and `source` must point to an allocated object (this includes the stack)
957    /// allocated at lest up to the field (inclusive).
958    ///
959    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
960    /// (because it is for an aligned field), both `self` and `source` must be aligned pointers.
961    ///
962    /// - The field must be writable (if in doubt, all of the pointed-to value must be writble).
963    ///
964    /// - The field in `self` and the same field in `source` must not overlap,
965    /// (if in doubt, the pointers must not point to overlapping memory).
966    ///
967    ///
968    /// # Example
969    ///
970    /// ```rust
971    /// # #![deny(safe_packed_borrows)]
972    /// use repr_offset::{
973    ///     for_examples::ReprPacked,
974    ///     utils::moved,
975    ///     ROExtRawMutOps, off,
976    /// };
977    ///
978    /// let mut left = ReprPacked {
979    ///     a: false,
980    ///     b: None,
981    ///     c: "foo",
982    ///     d: (),
983    /// };
984    /// let right = ReprPacked {
985    ///     a: true,
986    ///     b: Some('?'),
987    ///     c: "bar",
988    ///     d: (),
989    /// };
990    ///
991    /// let left_ptr: *mut _ = &mut left;
992    /// unsafe{
993    ///     left_ptr.f_copy_from_nonoverlapping(off!(a), &right);
994    ///     left_ptr.f_copy_from_nonoverlapping(off!(b), &right);
995    ///     left_ptr.f_copy_from_nonoverlapping(off!(c), &right);
996    /// }
997    ///
998    /// assert_eq!(moved(left.a), true);
999    /// assert_eq!(moved(right.a), true);
1000    ///
1001    /// assert_eq!(moved(left.b), Some('?'));
1002    /// assert_eq!(moved(right.b), Some('?'));
1003    ///
1004    /// assert_eq!(moved(left.c), "bar");
1005    /// assert_eq!(moved(right.c), "bar");
1006    ///
1007    ///
1008    /// ```
1009    ///
1010    unsafe fn f_copy_from_nonoverlapping<F>(
1011        self,
1012        offset: FieldOffset<Self::Target, F, A>,
1013        source: *const Self::Target,
1014    );
1015
1016    /// Replaces a field (determined by `offset`) with `value`,
1017    /// returning the previous value of the field.
1018    ///
1019    /// # Safety
1020    ///
1021    /// You must ensure these properties:
1022    ///
1023    /// - `self` must point to an allocated object (this includes the stack)
1024    /// allocated at lest up to the field (inclusive).
1025    ///
1026    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
1027    /// (because it is for an aligned field), `self` must be an aligned pointers.
1028    ///
1029    /// [`core::ptr::copy`]: https://doc.rust-lang.org/core/ptr/fn.copy.html
1030    ///
1031    /// # Example
1032    ///
1033    /// ```rust
1034    /// # #![deny(safe_packed_borrows)]
1035    /// use repr_offset::{
1036    ///     for_examples::ReprPacked,
1037    ///     utils::moved,
1038    ///     ROExtRawMutOps, off,
1039    /// };
1040    ///
1041    /// let mut value = ReprPacked {
1042    ///     a: 3u128,
1043    ///     b: Some(5u64),
1044    ///     c: vec![0, 1],
1045    ///     d: (),
1046    /// };
1047    ///
1048    /// let ptr: *mut _ = &mut value;
1049    /// unsafe {
1050    ///     assert_eq!(ptr.f_replace_raw(off!(a), 200), 3);
1051    ///     assert_eq!(ptr.f_replace_raw(off!(b), None), Some(5));
1052    ///     assert_eq!(ptr.f_replace_raw(off!(c), vec![2, 3]), vec![0, 1]);
1053    /// }
1054    ///
1055    /// assert_eq!(moved(value.a), 200);
1056    /// assert_eq!(moved(value.b), None);
1057    /// assert_eq!(moved(value.c), vec![2, 3]);
1058    ///
1059    /// ```
1060    unsafe fn f_replace_raw<F>(self, offset: FieldOffset<Self::Target, F, A>, value: F) -> F;
1061
1062    /// Swaps a field (determined by `offset`) from `self` with the same field in `right`.
1063    ///
1064    /// # Safety
1065    ///
1066    /// You must ensure these properties:
1067    ///
1068    /// - `self` and `source` must point to an allocated object (this includes the stack)
1069    /// allocated at lest up to the field (inclusive).
1070    ///
1071    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
1072    /// (because it is for an aligned field), both `self` and `source` must be aligned pointers.
1073    ///
1074    /// - The field in `self` and the same field in `source` must be writable
1075    /// (if in doubt, all of the pointed-to value must be writble).
1076    ///
1077    ///
1078    /// [`core::ptr::swap`] describes what happens when `self` ànd `source` overlap.
1079    ///
1080    ///
1081    /// [`core::ptr::swap`]: https://doc.rust-lang.org/core/ptr/fn.swap.html
1082    ///
1083    ///
1084    /// # Example
1085    ///
1086    /// ```rust
1087    /// # #![deny(safe_packed_borrows)]
1088    /// use repr_offset::{
1089    ///     for_examples::ReprC,
1090    ///     ROExtRawMutOps, off,
1091    /// };
1092    ///
1093    /// let mut left = ReprC {
1094    ///     a: 3u128,
1095    ///     b: Some(5u64),
1096    ///     c: &[8, 13, 21][..],
1097    ///     d: (),
1098    /// };
1099    /// let mut right = ReprC {
1100    ///     a: 55,
1101    ///     b: None,
1102    ///     c: &[34, 51, 89][..],
1103    ///     d: (),
1104    /// };
1105    ///
1106    /// let left_ptr: *mut _ = &mut left;
1107    /// unsafe{
1108    ///     left_ptr.f_swap_raw(off!(a), &mut right);
1109    ///     left_ptr.f_swap_raw(off!(b), &mut right);
1110    ///     left_ptr.f_swap_raw(off!(c), &mut right);
1111    /// }
1112    ///
1113    /// assert_eq!(left.a, 55);
1114    /// assert_eq!(right.a, 3);
1115    ///
1116    /// assert_eq!(left.b, None);
1117    /// assert_eq!(right.b, Some(5));
1118    ///
1119    /// assert_eq!(left.c, &[34, 51, 89][..]);
1120    /// assert_eq!(right.c, &[8, 13, 21][..]);
1121    ///
1122    ///
1123    /// ```
1124    ///
1125    unsafe fn f_swap_raw<F>(
1126        self,
1127        offset: FieldOffset<Self::Target, F, A>,
1128        right: *mut Self::Target,
1129    );
1130
1131    /// Swaps a field (determined by `offset`) from `self` with the same field in `right`.
1132    /// `self` and `right` must not overlap.
1133    ///
1134    ///
1135    /// # Safety
1136    ///
1137    /// You must ensure these properties:
1138    ///
1139    /// - `self` and `source` must point to an allocated object (this includes the stack)
1140    /// allocated at lest up to the field (inclusive).
1141    ///
1142    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
1143    /// (because it is for an aligned field), both `self` and `source` must be aligned pointers.
1144    ///
1145    /// - The field in `self` and the same field in `source` must be writable
1146    /// (if in doubt, all of the pointed-to value must be writble).
1147    ///
1148    /// - The field in `self` and the same field in `source` must not overlap,
1149    /// (if in doubt, the pointers must not point to overlapping memory).
1150    ///
1151    ///
1152    /// # Example
1153    ///
1154    /// ```rust
1155    /// # #![deny(safe_packed_borrows)]
1156    /// use repr_offset::{
1157    ///     for_examples::ReprPacked,
1158    ///     utils::moved,
1159    ///     ROExtRawMutOps, off,
1160    /// };
1161    ///
1162    /// let mut left = ReprPacked {
1163    ///     a: false,
1164    ///     b: None,
1165    ///     c: "foo",
1166    ///     d: (),
1167    /// };
1168    /// let mut right = ReprPacked {
1169    ///     a: true,
1170    ///     b: Some('?'),
1171    ///     c: "bar",
1172    ///     d: (),
1173    /// };
1174    ///
1175    /// let left_ptr: *mut _ = &mut left;
1176    /// unsafe{
1177    ///     left_ptr.f_swap_nonoverlapping(off!(a), &mut right);
1178    ///     left_ptr.f_swap_nonoverlapping(off!(b), &mut right);
1179    ///     left_ptr.f_swap_nonoverlapping(off!(c), &mut right);
1180    /// }
1181    ///
1182    /// assert_eq!(moved(left.a), true);
1183    /// assert_eq!(moved(right.a), false);
1184    ///
1185    /// assert_eq!(moved(left.b), Some('?'));
1186    /// assert_eq!(moved(right.b), None);
1187    ///
1188    /// assert_eq!(moved(left.c), "bar");
1189    /// assert_eq!(moved(right.c), "foo");
1190    ///
1191    ///
1192    /// ```
1193    ///
1194    unsafe fn f_swap_nonoverlapping<F>(
1195        self,
1196        offset: FieldOffset<Self::Target, F, A>,
1197        right: *mut Self::Target,
1198    );
1199}