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}