repr_offset 0.2.2

Offsets of fields for types with a stable layout.
Documentation
//! Extension traits that use `FieldOffset` parameters to operate on fields.
//!
//! These are the extension traits for each kind of type:
//!
//! - non-pointer / `&T` / `&mut T`: [`ROExtAcc`] and [`ROExtOps`]
//!
//! - `*const T` and `*mut T`: [`ROExtRawAcc`] and [`ROExtRawOps`]
//!
//! - `*mut T`: [`ROExtRawMutAcc`] and [`ROExtRawMutOps`]
//!
//! # Imports
//!
//! Here is the code to import all of the extension traits for convenience:
//! ```rust
//! use repr_offset::{ROExtAcc, ROExtOps, ROExtRawAcc, ROExtRawMutAcc, ROExtRawOps, ROExtRawMutOps};
//! ```
//!
//! # Examples
//!
//! # Initializing Types
//!
//! ```rust
//! use repr_offset::{
//!     for_examples::ReprC,
//!     off,
//!     ROExtRawMutOps,
//! };
//!
//! use std::mem::MaybeUninit;
//!
//! type This = ReprC<String, Vec<u8>, usize, Option<char>>;
//!
//! let this = unsafe{
//!     let mut uninit = MaybeUninit::<This>::uninit();
//!     initialize_this(uninit.as_mut_ptr());
//!     uninit.assume_init()
//! };
//!
//! assert_eq!(this.a, "foo");
//! assert_eq!(this.b, [3, 5, 8]);
//! assert_eq!(this.c, 13);
//! assert_eq!(this.d, Some('_'));
//!
//! /// Initializes `this`
//! ///
//! /// # Safety
//! ///
//! /// The passed in pointer must point to an aligned, allocated `This` (including on the stack).
//! unsafe fn initialize_this(this: *mut This) {
//!     this.f_write(off!(a), "foo".to_string());
//!     this.f_write(off!(b), vec![3, 5, 8]);
//!     this.f_write(off!(c), 13_usize);
//!     this.f_write(off!(d), Some('_'));
//! }
//!
//! ```
//!
//!
//!
//! [`ROExtAcc`]: ./trait.ROExtAcc.html
//! [`ROExtOps`]: ./trait.ROExtOps.html
//! [`ROExtRawAcc`]: ./trait.ROExtRawAcc.html
//! [`ROExtRawMutAcc`]: ./trait.ROExtRawMutAcc.html
//! [`ROExtRawOps`]: ./trait.ROExtRawOps.html
//! [`ROExtRawMutOps`]: ./trait.ROExtRawMutOps.html
//!
//! [`FieldOffset`]: ../struct.FieldOffset.html

use crate::{Aligned, FieldOffset};

/// Extension trait for (mutable) references to access fields generically,
/// where the field is determined by a [`FieldOffset`] parameter.
///
///
/// # Safety
///
/// This trait must not to be implemented outside the `repr_offset` crate.
///
/// # Examples
///
/// ### Unaligned field pointers
///
/// Getting raw pointers to all fields in a packed struct.
///
/// ```rust
/// # #![deny(safe_packed_borrows)]
/// use repr_offset::{
///     for_examples::ReprPacked,
///     ROExtAcc,
///     off,
/// };
///
/// type This = ReprPacked<u8, Option<usize>, &'static [u16], &'static str>;
///
/// let value: This = ReprPacked {
///     a: 3,
///     b: Some(5),
///     c: &[0, 1, 2],
///     d: "hello",
/// };
///
/// unsafe {
///     let (a_ptr, b_ptr, c_ptr, d_ptr) = get_field_ptrs(&value);
///     assert_eq!(a_ptr.read_unaligned(), 3);
///     assert_eq!(b_ptr.read_unaligned(), Some(5));
///     assert_eq!(c_ptr.read_unaligned(), &[0, 1, 2]);
///     assert_eq!(d_ptr.read_unaligned(), "hello");
/// }
///
/// // Note: the mutable version of this function couldn't use `f_get_mut_ptr`,
/// //       it must use `ROExtRawMutAcc::f_raw_get_mut`
/// fn get_field_ptrs(
///     this: &This,
/// ) -> (*const u8, *const Option<usize>, *const &'static [u16], *const &'static str) {
///     (
///         this.f_get_ptr(off!(a)),
///         this.f_get_ptr(off!(b)),
///         this.f_get_ptr(off!(c)),
///         this.f_get_ptr(off!(d)),
///     )
/// }
///
/// ```
///
/// [`FieldOffset`]: ../struct.FieldOffset.html
//
// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
//
pub unsafe trait ROExtAcc: Sized {
    /// Gets a reference to a field, determined by `offset`.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprC,
    ///     ROExtAcc, off,
    /// };
    ///
    /// let value = ReprC {
    ///     a: 3,
    ///     b: "foo",
    ///     c: ReprC {
    ///         a: 5,
    ///         b: "bar",
    ///         c: 8,
    ///         d: 13,
    ///     },
    ///     d: false,
    /// };
    ///
    /// assert_eq!(value.f_get(off!(a)), &3);
    /// assert_eq!(value.f_get(off!(c.a)), &5);
    /// assert_eq!(value.f_get(off!(c.b)), &"bar");
    ///
    ///
    /// ```
    fn f_get<F>(&self, offset: FieldOffset<Self, F, Aligned>) -> &F;

    /// Gets a muatble reference to a field, determined by `offset`.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::{ReprAlign4, ReprC},
    ///     ROExtAcc, off,
    /// };
    ///
    /// use std::cmp::Ordering;
    ///
    /// let mut value = ReprC {
    ///     a: 3,
    ///     b: Some(5),
    ///     c: Ordering::Less,
    ///     d: ReprAlign4 {
    ///         a: 8,
    ///         b: "bar",
    ///         c: 13,
    ///         d: 21,
    ///     },
    /// };
    ///
    /// let foo = value.f_get_mut(off!(a));
    /// assert_eq!(foo, &mut 3);
    /// *foo += 100;
    /// assert_eq!(value.a, 103);
    ///
    /// let bar = value.f_get_mut(off!(d.a));
    /// assert_eq!(bar, &mut 8);
    ///
    /// let baz = value.f_get_mut(off!(d.d));
    /// assert_eq!(baz, &mut 21);
    /// *baz += 300;
    /// assert_eq!(value.d.d, 321);
    ///
    /// ```
    ///
    fn f_get_mut<F>(&mut self, offset: FieldOffset<Self, F, Aligned>) -> &mut F;

    /// Gets a const pointer to a field,
    /// the field is determined by `offset`.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprC,
    ///     ROExtAcc, off,
    /// };
    ///
    /// let value = ReprC {
    ///     a: 3,
    ///     b: "foo",
    ///     c: ReprC {
    ///         a: 5,
    ///         b: "bar",
    ///         c: 8,
    ///         d: 13,
    ///     },
    ///     d: false,
    /// };
    ///
    /// unsafe {
    ///     assert_eq!(value.f_get_ptr(off!(a)).read(), 3);
    ///     assert_eq!(value.f_get_ptr(off!(c.a)).read(), 5);
    ///     assert_eq!(value.f_get_ptr(off!(c.b)).read(), "bar");
    /// }
    ///
    /// ```
    fn f_get_ptr<F, A>(&self, offset: FieldOffset<Self, F, A>) -> *const F;

    /// Gets a mutable pointer to a field, determined by `offset`.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::{ReprC, ReprPacked},
    ///     utils::moved,
    ///     ROExtAcc, off,
    /// };
    ///
    /// use std::cmp::Ordering;
    ///
    /// let mut value = ReprPacked {
    ///     a: 3,
    ///     b: Some(5),
    ///     c: Ordering::Less,
    ///     d: ReprC {
    ///         a: 8,
    ///         b: "bar",
    ///         c: 13,
    ///         d: 21,
    ///     },
    /// };
    ///
    /// unsafe {
    ///     let foo = value.f_get_mut_ptr(off!(a));
    ///     let old_a = foo.read_unaligned();
    ///     assert_eq!(old_a, 3);
    ///     foo.write_unaligned(old_a + 100);
    ///     // the `moved` function prevents the creation of a reference to the packed field.
    ///     assert_eq!(moved(value.a), 103);
    ///     
    ///     let baz = value.f_get_mut_ptr(off!(d.d));
    ///     let old_dd = baz.read_unaligned();
    ///     assert_eq!(old_dd, 21);
    ///     baz.write_unaligned(old_dd + 300);
    ///     // the `moved` function prevents the creation of a reference to the packed field.
    ///     assert_eq!(moved(value.d.d), 321);
    /// }
    /// ```
    fn f_get_mut_ptr<F, A>(&mut self, offset: FieldOffset<Self, F, A>) -> *mut F;
}

/// Extension trait for (mutable) references to do generic field operations,
/// where the field is determined by a [`FieldOffset`] parameter.
///
///
/// # Safety
///
/// This trait must not to be implemented outside the `repr_offset` crate.
///
/// # Alignment
///
/// The `A` type parameter is the [`Alignment`] of the field,
/// used to implement methods differently depending on whether the field is
/// [`Aligned`] or [`Unaligned`].
///
/// [`FieldOffset`]: ../struct.FieldOffset.html
/// [`Alignment`]: ../alignment/trait.Alignment.html
/// [`Aligned`]: ../alignment/struct.Aligned.html
/// [`Unaligned`]: ../alignment/struct.Unaligned.html
///
///
//
// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
//
pub unsafe trait ROExtOps<A>: ROExtAcc {
    /// Replaces a field (determined by `offset`) with `value`,
    /// returning the previous value of the field.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprPacked,
    ///     utils::moved,
    ///     ROExtOps, off,
    /// };
    ///
    /// let mut value = ReprPacked {
    ///     a: 3u128,
    ///     b: Some(5u64),
    ///     c: vec![0, 1],
    ///     d: (),
    /// };
    ///
    /// assert_eq!(value.f_replace(off!(a), 200), 3);
    /// assert_eq!(moved(value.a), 200);
    ///
    /// assert_eq!(value.f_replace(off!(b), None), Some(5));
    /// assert_eq!(moved(value.b), None);
    ///
    /// assert_eq!(value.f_replace(off!(c), vec![2, 3]), vec![0, 1]);
    /// assert_eq!(moved(value.c), vec![2, 3]);
    ///
    /// ```
    fn f_replace<F>(&mut self, offset: FieldOffset<Self, F, A>, value: F) -> F;

    /// Swaps a field (determined by `offset`) with the same field in `right`.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprC,
    ///     ROExtOps, off,
    /// };
    ///
    /// let mut left = ReprC {
    ///     a: 3u128,
    ///     b: Some(5u64),
    ///     c: vec![0, 1],
    ///     d: (),
    /// };
    /// let mut right = ReprC {
    ///     a: 55,
    ///     b: None,
    ///     c: vec![89, 144],
    ///     d: (),
    /// };
    ///
    /// left.f_swap(off!(a), &mut right);
    /// assert_eq!(left.a, 55);
    /// assert_eq!(right.a, 3);
    ///
    /// left.f_swap(off!(b), &mut right);
    /// assert_eq!(left.b, None);
    /// assert_eq!(right.b, Some(5));
    ///
    /// left.f_swap(off!(c), &mut right);
    /// assert_eq!(left.c, vec![89, 144]);
    /// assert_eq!(right.c, vec![0, 1]);
    ///
    /// ```
    fn f_swap<F>(&mut self, offset: FieldOffset<Self, F, A>, right: &mut Self);

    /// Gets a copy of a field (determined by `offset`).
    /// The field is determined by `offset`.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprPacked,
    ///     ROExtOps, off,
    /// };
    ///
    /// let value = ReprPacked {
    ///     a: 3,
    ///     b: "foo",
    ///     c: 'g',
    ///     d: false,
    /// };
    ///
    /// assert_eq!(value.f_get_copy(off!(a)), 3);
    /// assert_eq!(value.f_get_copy(off!(b)), "foo");
    /// assert_eq!(value.f_get_copy(off!(c)), 'g');
    /// assert_eq!(value.f_get_copy(off!(d)), false);
    ///
    ///
    /// ```
    fn f_get_copy<F>(&self, offset: FieldOffset<Self, F, A>) -> F
    where
        F: Copy;
}

/////////////////////////////////////////////////////////////////////////////////

/// Extension trait for raw pointers to access fields generically,
/// where the field is determined by a [`FieldOffset`] parameter.
///
///
/// # Safety
///
/// This trait must not to be implemented outside the `repr_offset` crate.
///
/// # Example
///
/// This example shows how you can get references to known aligned fields from a raw pointer
/// to a partially initialized value..
///
/// ```rust
/// # #![deny(safe_packed_borrows)]
/// use repr_offset::{
///     for_examples::ReprC,
///     off,
///     ROExtRawAcc, ROExtRawMutOps,
/// };
///
/// use std::mem::MaybeUninit;
///
/// type This = ReprC<u8, Option<usize>, &'static [u16], &'static str>;
///
/// let mut uninit = MaybeUninit::<This>::uninit();
///
/// unsafe {
///     let ptr = uninit.as_mut_ptr();
///     ptr.f_write(off!(a), 3);
///     ptr.f_write(off!(b), Some(5));
///
///     let (a, b) = get_init_refs(&uninit);
///     assert_eq!(*a, 3);
///     assert_eq!(*b, Some(5));
/// }
///
/// /// # Safety
/// ///
/// /// The fields up to and including `b` must be initialized.
/// unsafe fn get_init_refs(this: &MaybeUninit<This>) -> (&u8, &Option<usize>) {
///     let this = this.as_ptr();
///
///     (
///         &*this.f_raw_get(off!(a)),
///         &*this.f_raw_get(off!(b)),
///     )
/// }
///
/// ```
///
///
/// [`FieldOffset`]: ../struct.FieldOffset.html
//
// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
pub unsafe trait ROExtRawAcc: crate::utils::PointerTarget {
    /// Gets a raw pointer to a field (determined by `offset`) from this raw pointer.
    ///
    /// # Safety
    ///
    /// `self` must point to some allocated object,
    /// allocated at least up to the field (inclusive).
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::{ReprC, ReprPacked},
    ///     tstr::TS,
    ///     GetPubFieldOffset, FieldType,
    ///     ROExtRawAcc,
    ///     pub_off,
    /// };
    ///
    /// use std::cmp::Ordering;
    ///
    /// let value = ReprPacked {
    ///     a: 3,
    ///     b: Some(5),
    ///     c: Ordering::Less,
    ///     d: ReprC {
    ///         a: 8,
    ///         b: "bar",
    ///         c: 13,
    ///         d: 21,
    ///     },
    /// };
    ///
    /// unsafe {
    ///     assert_eq!(copy_fields(&value), (3, 13));
    /// }
    ///
    ///
    /// /// Copies the `a` and `d.c` fields in this.
    /// ///
    /// /// # Safety
    /// ///
    /// /// The `a` and `d.c` fields in this must be initialized
    /// unsafe fn copy_fields<T, O, U>(
    ///     this: *const T,
    /// ) -> (O, U)
    /// where
    ///     T: GetPubFieldOffset<TS!(a), Type = O>,
    ///     T: GetPubFieldOffset<TS!(d,c), Type = U>,
    ///     O: Copy,
    ///     U: Copy,
    /// {
    ///     (
    ///         this.f_raw_get(pub_off!(a)).read_unaligned(),
    ///         this.f_raw_get(pub_off!(d.c)).read_unaligned(),
    ///     )
    /// }
    ///
    ///
    /// ```
    ///
    unsafe fn f_raw_get<F, A>(self, offset: FieldOffset<Self::Target, F, A>) -> *const F;
}

/// Extension trait for mutable raw pointers to access fields generically,
/// where the field is determined by a [`FieldOffset`] parameter.
///
///
/// # Safety
///
/// This trait must not to be implemented outside the `repr_offset` crate.
///
/// # Example
///
/// This example demonstrates how you can get mutable references to the known initialized
/// parts of a struct.
///
/// ```rust
/// # #![deny(safe_packed_borrows)]
/// use repr_offset::{
///     for_examples::ReprC,
///     tstr::TS,
///     off,
///     ROExtRawOps, ROExtRawMutAcc, ROExtRawMutOps,
/// };
///
/// use std::mem::MaybeUninit;
///
/// type This = ReprC<u8, Option<usize>, &'static [u16], &'static str>;
///
/// let mut uninit = MaybeUninit::<This>::uninit();
///
/// unsafe {
///     let ptr = uninit.as_mut_ptr();
///     ptr.f_write(off!(a), 3);
///     ptr.f_write(off!(b), Some(5));
/// }
/// {
///     // Safety: We know that the a and b fields were initialized above.
///     let (a, b) = unsafe{ get_mut_refs(&mut uninit) };
///     assert_eq!(*a, 3);
///     assert_eq!(*b, Some(5));
///     *a += 100;
///     *b.as_mut().unwrap() += 200;
/// }
/// unsafe {
///     let ptr = uninit.as_ptr();
///     assert_eq!(ptr.f_read_copy(off!(a)), 103);
///     assert_eq!(ptr.f_read_copy(off!(b)), Some(205));
/// }
///
/// /// Gets mutable references to the `a` and `b` fields in `this`
/// ///
/// /// # Safety
/// ///
/// /// The fields up to and including `b` must be initialized.
/// unsafe fn get_mut_refs(this: &mut MaybeUninit<This>) -> (&mut u8, &mut Option<usize>) {
///     let this = this.as_mut_ptr();
///
///     let ptrs = (
///         this.f_raw_get_mut(off!(a)),
///         this.f_raw_get_mut(off!(b)),
///     );
///
///     (&mut *ptrs.0, &mut *ptrs.1)
/// }
///
/// ```
///
/// [`FieldOffset`]: ../struct.FieldOffset.html
//
// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
pub unsafe trait ROExtRawMutAcc: ROExtRawAcc {
    /// Gets a muatble pointer to a field (determined by `offset`) from this mutable pointer.
    ///
    /// # Safety
    ///
    /// `self` must point to some allocated object,
    /// allocated at least up to the field (inclusive).
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::{ReprC, ReprPacked},
    ///     utils::moved,
    ///     tstr::TS,
    ///     GetPubFieldOffset, FieldType,
    ///     ROExtRawMutAcc,
    ///     off,
    /// };
    ///
    /// use std::mem::MaybeUninit;
    ///
    /// type This = ReprPacked<Option<char>, ReprC<u32, u64, String, Vec<u32>>, bool>;
    ///
    /// let mut uninit = MaybeUninit::<This>::uninit();
    ///
    /// /// Initializes a `This` through a pointer
    /// ///
    /// /// # Safety
    /// ///
    /// /// You must pass a pointer to allocated (and writable) memory for `This`.
    /// unsafe fn initialize(this: *mut This) {
    ///     this.f_raw_get_mut(off!(a)).write_unaligned(None);
    ///     this.f_raw_get_mut(off!(b.a)).write_unaligned(3);
    ///     this.f_raw_get_mut(off!(b.b)).write_unaligned(5);
    ///     this.f_raw_get_mut(off!(b.c)).write_unaligned("8".to_string());
    ///     this.f_raw_get_mut(off!(b.d)).write_unaligned(vec![13, 21]);
    ///     this.f_raw_get_mut(off!(c)).write_unaligned(false);
    /// }
    ///
    /// let value = unsafe{
    ///     initialize(uninit.as_mut_ptr());
    ///     uninit.assume_init()
    /// };
    ///
    /// assert_eq!(moved(value.a), None);
    /// assert_eq!(moved(value.b.a), 3);
    /// assert_eq!(moved(value.b.b), 5);
    /// assert_eq!(moved(value.b.c), "8".to_string());
    /// assert_eq!(moved(value.b.d), vec![13, 21]);
    /// assert_eq!(moved(value.c), false);
    ///
    /// ```
    ///
    unsafe fn f_raw_get_mut<F, A>(self, offset: FieldOffset<Self::Target, F, A>) -> *mut F;
}

/// Extension trait for raw pointers to do generic field operations,
/// where the field is determined by a [`FieldOffset`] parameter.
///
///
/// # Safety
///
/// This trait must not to be implemented outside the `repr_offset` crate.
///
/// # Alignment
///
/// The `A` type parameter is the [`Alignment`] of the field,
/// used to implement methods differently depending on whether the field is
/// [`Aligned`] or [`Unaligned`].
///
/// [`FieldOffset`]: ../struct.FieldOffset.html
/// [`Alignment`]: ../alignment/trait.Alignment.html
/// [`Aligned`]: ../alignment/struct.Aligned.html
/// [`Unaligned`]: ../alignment/struct.Unaligned.html
//
// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
pub unsafe trait ROExtRawOps<A>: ROExtRawAcc {
    /// Copies a field (determined by `offset`) from `self`.
    ///
    /// # Safety
    ///
    /// You must ensure these properties about the pointed-to value:
    ///
    /// - The value must be in an allocated object (this includes the stack)
    /// allocated at least up to the field (inclusive).
    ///
    /// - The field must be initialized
    ///
    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
    /// (because it is for an aligned field), `self` must be an aligned pointer.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprPacked,
    ///     ROExtRawOps, off,
    /// };
    ///
    /// use std::cmp::Ordering;
    ///
    /// let mut value = ReprPacked {
    ///     a: 3,
    ///     b: Some(5),
    ///     c: Ordering::Less,
    ///     d: (),
    /// };
    ///
    /// let ptr: *const _ = &value;
    /// unsafe {
    ///     assert_eq!(ptr.f_read_copy(off!(a)), 3);
    ///     assert_eq!(ptr.f_read_copy(off!(b)), Some(5));
    ///     assert_eq!(ptr.f_read_copy(off!(c)), Ordering::Less);
    /// }
    /// ```
    ///
    unsafe fn f_read_copy<F>(self, offset: FieldOffset<Self::Target, F, A>) -> F
    where
        F: Copy;

    /// Reads a copy of a field (determined by `offset`) from `self`,
    /// without mutating or moving the field.
    ///
    /// # Safety
    ///
    /// You must ensure these properties about the pointed-to value:
    ///
    /// - The value must be in an allocated object (this includes the stack)
    /// allocated at least up to the field (inclusive).
    ///
    /// - The field must be initialized
    ///
    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
    /// (because it is for an aligned field), `self` must be an aligned pointer.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprPacked,
    ///     ROExtRawOps, off,
    /// };
    ///
    /// use std::{cmp::Ordering, mem::ManuallyDrop};
    ///
    /// let mut value = ManuallyDrop::new(ReprPacked {
    ///     a: 3,
    ///     b: Some(5),
    ///     c: "hello".to_string(),
    ///     d: vec![0, 1, 2],
    /// });
    ///
    /// let ptr: *const ReprPacked<_, _, _, _> = &*value;
    /// unsafe {
    ///     assert_eq!(ptr.f_read(off!(a)), 3);
    ///     assert_eq!(ptr.f_read(off!(b)), Some(5));
    ///     assert_eq!(ptr.f_read(off!(c)), "hello".to_string());
    ///     assert_eq!(ptr.f_read(off!(d)), vec![0, 1, 2]);
    /// }
    /// ```
    ///
    unsafe fn f_read<F>(self, offset: FieldOffset<Self::Target, F, A>) -> F;
}

/// Extension trait for mutable raw pointers to do generic field operations,
/// where the field is determined by a [`FieldOffset`] parameter.
///
/// # Safety
///
/// This trait must not to be implemented outside the `repr_offset` crate.
///
/// # Alignment
///
/// The `A` type parameter is the [`Alignment`] of the field,
/// used to implement methods differently depending on whether the field is
/// [`Aligned`] or [`Unaligned`].
///
/// [`FieldOffset`]: ../struct.FieldOffset.html
/// [`Alignment`]: ../alignment/trait.Alignment.html
/// [`Aligned`]: ../alignment/struct.Aligned.html
/// [`Unaligned`]: ../alignment/struct.Unaligned.html
///
/// # Example
///
/// This example shows how you can do the equivalent of `std::mem::replace`
/// in partially initialized structs.
///
/// ```rust
/// # #![deny(safe_packed_borrows)]
/// use repr_offset::{
///     for_examples::ReprPacked,
///     utils::moved,
///     ROExtRawMutOps, off,
/// };
///
/// let mut value = ReprPacked {
///     a: false,
///     b: None,
///     c: "",
///     d: [0u64; 10],
/// };
///
/// let (a, b) = unsafe{ replace_fields(&mut value, true, Some('!')) };
///
/// assert_eq!(moved(a), false);
/// assert_eq!(moved(value.a), true);
///
/// assert_eq!(moved(b), None);
/// assert_eq!(moved(value.b), Some('!'));
///
/// assert_eq!(moved(value.c), "");
///
///
/// /// Replaces the `a` and `b` fields in `this`
/// ///
/// /// # Safety
/// ///
/// /// The fields up to and including `b` must be initialized.
/// unsafe fn replace_fields(
///     this: *mut ReprPacked<bool, Option<char>, &'static str, [u64; 10]>,
///     a: bool,
///     b: Option<char>,
/// ) -> (bool, Option<char>) {
///     (
///         this.f_replace_raw(off!(a), a),
///         this.f_replace_raw(off!(b), b),
///     )
/// }
/// ```
///
//
// This trait is implemented in src/struct_field_offset/repr_offset_ext_impls.rs
pub unsafe trait ROExtRawMutOps<A>: ROExtRawMutAcc {
    /// Overwrites the value of a field (determined by `offset`) from `self`,
    /// without dropping the previous value.
    ///
    /// # Safety
    ///
    /// You must ensure these properties:
    ///
    /// - `self` must point to an allocated object (this includes the stack)
    /// allocated at least up to the field (inclusive).
    ///
    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
    /// (because it is for an aligned field), `self` must be an aligned pointer.
    ///
    /// - The field must be writable(if in doubt, all of the pointed-to value).
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprC,
    ///     utils::moved,
    ///     ROExtRawMutOps, off,
    /// };
    ///
    /// let mut value = ReprC {
    ///     a: 0,
    ///     b: None::<u32>,
    ///     c: Vec::new(),
    ///     d: String::new(),
    /// };
    ///
    /// let ptr: *mut _ = &mut value;
    /// unsafe{
    ///     ptr.f_write(off!(a), 3);
    ///     ptr.f_write(off!(b), Some(5));
    ///     ptr.f_write(off!(c), vec![8, 13]);
    ///     ptr.f_write(off!(d), "world".to_string());
    /// }
    ///
    /// assert_eq!(value.a, 3);
    /// assert_eq!(value.b, Some(5));
    /// assert_eq!(value.c, vec![8, 13]);
    /// assert_eq!(value.d, "world".to_string());
    ///
    /// ```
    ///
    unsafe fn f_write<F>(self, offset: FieldOffset<Self::Target, F, A>, value: F);

    /// Copies a field (determined by `offset`) from `source` to `self`.
    ///
    /// # Safety
    ///
    /// You must ensure these properties:
    ///
    /// - `self` and `source` must point to an allocated object (this includes the stack)
    /// allocated at lest up to the field (inclusive).
    ///
    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
    /// (because it is for an aligned field), both `self` and `source` must be aligned pointers.
    ///
    /// - The field must be writable (if in doubt, all of the pointed-to value must be writble).
    ///
    /// [`core::ptr::copy`] describes what happens when `self` ànd `source` overlap.
    ///
    ///
    /// [`core::ptr::copy`]: https://doc.rust-lang.org/core/ptr/fn.copy.html
    ///
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprC,
    ///     ROExtRawMutOps, off,
    /// };
    ///
    /// let mut left = ReprC {
    ///     a: 3u128,
    ///     b: Some(5u64),
    ///     c: &[8, 13, 21][..],
    ///     d: (),
    /// };
    /// let right = ReprC {
    ///     a: 55,
    ///     b: None,
    ///     c: &[34, 51, 89][..],
    ///     d: (),
    /// };
    ///
    /// let left_ptr: *mut _ = &mut left;
    /// unsafe{
    ///     left_ptr.f_copy_from(off!(a), &right);
    ///     left_ptr.f_copy_from(off!(b), &right);
    ///     left_ptr.f_copy_from(off!(c), &right);
    /// }
    ///
    /// assert_eq!(left.a, 55);
    /// assert_eq!(right.a, 55);
    ///
    /// assert_eq!(left.b, None);
    /// assert_eq!(right.b, None);
    ///
    /// assert_eq!(left.c, &[34, 51, 89][..]);
    /// assert_eq!(right.c, &[34, 51, 89][..]);
    ///
    ///
    /// ```
    ///
    unsafe fn f_copy_from<F>(
        self,
        offset: FieldOffset<Self::Target, F, A>,
        source: *const Self::Target,
    );

    /// Copies a field (determined by `offset`) from `source` to `self`.
    ///
    /// # Safety
    ///
    /// You must ensure these properties:
    ///
    /// - `self` and `source` must point to an allocated object (this includes the stack)
    /// allocated at lest up to the field (inclusive).
    ///
    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
    /// (because it is for an aligned field), both `self` and `source` must be aligned pointers.
    ///
    /// - The field must be writable (if in doubt, all of the pointed-to value must be writble).
    ///
    /// - The field in `self` and the same field in `source` must not overlap,
    /// (if in doubt, the pointers must not point to overlapping memory).
    ///
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprPacked,
    ///     utils::moved,
    ///     ROExtRawMutOps, off,
    /// };
    ///
    /// let mut left = ReprPacked {
    ///     a: false,
    ///     b: None,
    ///     c: "foo",
    ///     d: (),
    /// };
    /// let right = ReprPacked {
    ///     a: true,
    ///     b: Some('?'),
    ///     c: "bar",
    ///     d: (),
    /// };
    ///
    /// let left_ptr: *mut _ = &mut left;
    /// unsafe{
    ///     left_ptr.f_copy_from_nonoverlapping(off!(a), &right);
    ///     left_ptr.f_copy_from_nonoverlapping(off!(b), &right);
    ///     left_ptr.f_copy_from_nonoverlapping(off!(c), &right);
    /// }
    ///
    /// assert_eq!(moved(left.a), true);
    /// assert_eq!(moved(right.a), true);
    ///
    /// assert_eq!(moved(left.b), Some('?'));
    /// assert_eq!(moved(right.b), Some('?'));
    ///
    /// assert_eq!(moved(left.c), "bar");
    /// assert_eq!(moved(right.c), "bar");
    ///
    ///
    /// ```
    ///
    unsafe fn f_copy_from_nonoverlapping<F>(
        self,
        offset: FieldOffset<Self::Target, F, A>,
        source: *const Self::Target,
    );

    /// Replaces a field (determined by `offset`) with `value`,
    /// returning the previous value of the field.
    ///
    /// # Safety
    ///
    /// You must ensure these properties:
    ///
    /// - `self` must point to an allocated object (this includes the stack)
    /// allocated at lest up to the field (inclusive).
    ///
    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
    /// (because it is for an aligned field), `self` must be an aligned pointers.
    ///
    /// [`core::ptr::copy`]: https://doc.rust-lang.org/core/ptr/fn.copy.html
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprPacked,
    ///     utils::moved,
    ///     ROExtRawMutOps, off,
    /// };
    ///
    /// let mut value = ReprPacked {
    ///     a: 3u128,
    ///     b: Some(5u64),
    ///     c: vec![0, 1],
    ///     d: (),
    /// };
    ///
    /// let ptr: *mut _ = &mut value;
    /// unsafe {
    ///     assert_eq!(ptr.f_replace_raw(off!(a), 200), 3);
    ///     assert_eq!(ptr.f_replace_raw(off!(b), None), Some(5));
    ///     assert_eq!(ptr.f_replace_raw(off!(c), vec![2, 3]), vec![0, 1]);
    /// }
    ///
    /// assert_eq!(moved(value.a), 200);
    /// assert_eq!(moved(value.b), None);
    /// assert_eq!(moved(value.c), vec![2, 3]);
    ///
    /// ```
    unsafe fn f_replace_raw<F>(self, offset: FieldOffset<Self::Target, F, A>, value: F) -> F;

    /// Swaps a field (determined by `offset`) from `self` with the same field in `right`.
    ///
    /// # Safety
    ///
    /// You must ensure these properties:
    ///
    /// - `self` and `source` must point to an allocated object (this includes the stack)
    /// allocated at lest up to the field (inclusive).
    ///
    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
    /// (because it is for an aligned field), both `self` and `source` must be aligned pointers.
    ///
    /// - The field in `self` and the same field in `source` must be writable
    /// (if in doubt, all of the pointed-to value must be writble).
    ///
    ///
    /// [`core::ptr::swap`] describes what happens when `self` ànd `source` overlap.
    ///
    ///
    /// [`core::ptr::swap`]: https://doc.rust-lang.org/core/ptr/fn.swap.html
    ///
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprC,
    ///     ROExtRawMutOps, off,
    /// };
    ///
    /// let mut left = ReprC {
    ///     a: 3u128,
    ///     b: Some(5u64),
    ///     c: &[8, 13, 21][..],
    ///     d: (),
    /// };
    /// let mut right = ReprC {
    ///     a: 55,
    ///     b: None,
    ///     c: &[34, 51, 89][..],
    ///     d: (),
    /// };
    ///
    /// let left_ptr: *mut _ = &mut left;
    /// unsafe{
    ///     left_ptr.f_swap_raw(off!(a), &mut right);
    ///     left_ptr.f_swap_raw(off!(b), &mut right);
    ///     left_ptr.f_swap_raw(off!(c), &mut right);
    /// }
    ///
    /// assert_eq!(left.a, 55);
    /// assert_eq!(right.a, 3);
    ///
    /// assert_eq!(left.b, None);
    /// assert_eq!(right.b, Some(5));
    ///
    /// assert_eq!(left.c, &[34, 51, 89][..]);
    /// assert_eq!(right.c, &[8, 13, 21][..]);
    ///
    ///
    /// ```
    ///
    unsafe fn f_swap_raw<F>(
        self,
        offset: FieldOffset<Self::Target, F, A>,
        right: *mut Self::Target,
    );

    /// Swaps a field (determined by `offset`) from `self` with the same field in `right`.
    /// `self` and `right` must not overlap.
    ///
    ///
    /// # Safety
    ///
    /// You must ensure these properties:
    ///
    /// - `self` and `source` must point to an allocated object (this includes the stack)
    /// allocated at lest up to the field (inclusive).
    ///
    /// - If the passed in `offset` is a `FieldOffset<_, _, Aligned>`
    /// (because it is for an aligned field), both `self` and `source` must be aligned pointers.
    ///
    /// - The field in `self` and the same field in `source` must be writable
    /// (if in doubt, all of the pointed-to value must be writble).
    ///
    /// - The field in `self` and the same field in `source` must not overlap,
    /// (if in doubt, the pointers must not point to overlapping memory).
    ///
    ///
    /// # Example
    ///
    /// ```rust
    /// # #![deny(safe_packed_borrows)]
    /// use repr_offset::{
    ///     for_examples::ReprPacked,
    ///     utils::moved,
    ///     ROExtRawMutOps, off,
    /// };
    ///
    /// let mut left = ReprPacked {
    ///     a: false,
    ///     b: None,
    ///     c: "foo",
    ///     d: (),
    /// };
    /// let mut right = ReprPacked {
    ///     a: true,
    ///     b: Some('?'),
    ///     c: "bar",
    ///     d: (),
    /// };
    ///
    /// let left_ptr: *mut _ = &mut left;
    /// unsafe{
    ///     left_ptr.f_swap_nonoverlapping(off!(a), &mut right);
    ///     left_ptr.f_swap_nonoverlapping(off!(b), &mut right);
    ///     left_ptr.f_swap_nonoverlapping(off!(c), &mut right);
    /// }
    ///
    /// assert_eq!(moved(left.a), true);
    /// assert_eq!(moved(right.a), false);
    ///
    /// assert_eq!(moved(left.b), Some('?'));
    /// assert_eq!(moved(right.b), None);
    ///
    /// assert_eq!(moved(left.c), "bar");
    /// assert_eq!(moved(right.c), "foo");
    ///
    ///
    /// ```
    ///
    unsafe fn f_swap_nonoverlapping<F>(
        self,
        offset: FieldOffset<Self::Target, F, A>,
        right: *mut Self::Target,
    );
}