Trait deferred_reference::DeferMut[][src]

pub unsafe trait DeferMut: Defer {
    unsafe fn defer_mut(&self) -> Deferred<&mut Self::Target>;
}

The DeferMut trait offers easy access to deferred mutable references to types that implement DeferMut. This trait is already implemented on all types T: ?Sized for UnsafeCell<T> out-of-the-box and this should be sufficient for most purposes, but it is also possible to implement the Defer and DeferMut traits for your own types, please see the documentation of this trait on how to do this safely.

Safety

This trait may only be implemented for:

  1. All types that support interior mutability. Concretely, this means that for types that have interior mutability, the type must contain an UnsafeCell or one of of its derivatives, such as those in the Rust standard library like RefCell, RwLock or Mutex.
  2. Other smart-pointers which do not “own” their data. Smart-pointers which contain a mutable pointer *mut T don’t need to wrap the mutable pointer in an UnsafeCell, because dereferencing a mutable pointer does not constitute interior mutability.

Additionally, all types that implement DeferMut must uphold the following invariants:

  • The type must also implement the Defer trait.
  • The deferred reference that the DeferMut::defer_mut method returns, must point to the same location as the Deferred returned by Defer::defer.
  • Both the Defer and DeferMut trait implementations may not create any references to the location where the returned Deferred points, nor may the location be accessed in any way (e.g. dereferencing). Taking an immutable shared reference to a wrapping UnsafeCell is okay, but creating a reference to the contents of the UnsafeCell is not! Creating a mutable reference to the wrapping UnsafeCell is also not okay, because UnsafeCell only protects shared references to a place that may be mutated, it does not weaken the rules for mutable references, which say that a mutable reference must be exclusive in order to stay clear of undefined behavior.

Example

Here is an example for how to implement this trait for custom smart pointers.

use deferred_reference::{Defer, DeferMut, Deferred};
/// `MemoryMappedBuffer` is a simplified representation of a memory mapped slice of bytes.
/// Proper implementations would also contain a `MemoryMappedBuffer::new` constructor
/// which sets up the owned memory map and `MemoryMappedBuffer` should also implement
/// the `Drop` trait to properly clean up the memory map when `MemoryMappedBuffer`
/// goes out of scope.
pub struct MemoryMappedBuffer {
    ptr: *mut u8,
    length: usize,
}
impl Defer for MemoryMappedBuffer {
    type Target = [u8];
    fn defer(&self) -> Deferred<&[u8]> {
        let slice_ptr = core::ptr::slice_from_raw_parts(self.ptr as *const u8, self.length);
        // SAFETY: this is safe because the Deferred occupies a shared reference to the
        // SAFETY: smart pointer `MemoryMappedBuffer` for the duration of lifetime of &self,
        // SAFETY: which means no other callers can safely obtain a mutable reference
        // SAFETY: the MemoryMappedBuffer instance.
        unsafe { Deferred::from_raw(slice_ptr) }
    }
}
// SAFETY: this is safe, because the invariant of `Deferred` is upheld.
// SAFETY: this is only safe if the memory mapped region is properly aligned and initialized
// SAFETY: and `ptr` is non-null and not dangling (i.e. it must point to a valid memory region).
unsafe impl DeferMut for MemoryMappedBuffer {
    unsafe fn defer_mut(&self) -> Deferred<&mut [u8]> {
        let slice_mut_ptr = core::ptr::slice_from_raw_parts_mut(self.ptr, self.length);
        Deferred::from_raw_mut(slice_mut_ptr)
    }
}

If you want to build your own custom smart pointer that also owns the backing memory, then you can use Vec, Box and UnsafeCell to do so through interior mutability like this:

use deferred_reference::{Defer, DeferMut, Deferred};
use core::ops::{Deref, DerefMut};
use core::cell::UnsafeCell;
pub struct MyBuffer {
    memory: Box<UnsafeCell<[u8]>>,
}
impl MyBuffer {
    fn new(capacity: usize) -> Self {
        let mut vector = Vec::with_capacity(capacity);
        // we have to initialize the full vector, otherwise it is undefined behavior
        // when we give out references to the backing slice of bytes.
        vector.resize(capacity, 0u8);
        let boxed_slice: Box<[u8]> = vector.into_boxed_slice();
        // SAFETY: UnsafeCell is #[repr(transparent)] so this is safe.
        let memory: Box<UnsafeCell<[u8]>> = unsafe { core::mem::transmute(boxed_slice) };
        Self { memory }
    }
}
// we only need to implement Deref, because the Defer and DeferMut
// traits are already implemented for UnsafeCell<[u8]>.
impl Deref for MyBuffer {
    type Target = UnsafeCell<[u8]>;
    fn deref(&self) -> &Self::Target {
        self.memory.deref()
    }
}
// we also implement DerefMut just to illustrate the invalidation of
// Deferred when taking out a mutable borrow. this is optional.
impl DerefMut for MyBuffer {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.memory.deref_mut()
    }
}
fn main() {
    let mut my_buffer = MyBuffer::new(1024 * 100); // 100kb buffer
    // SAFETY: this is safe, because there exist no references to the slice.
    let deferred_mut: Deferred<&mut [u8]> = unsafe { my_buffer.defer_mut() };
    // the next line implicitly calls Deref::deref() on `my_buffer`.
    // this is also okay, because the slice sits inside an UnsafeCell.
    let deferred: Deferred<&[u8]> = my_buffer.defer();
    // the next statement is also safe, because by taking out a `&mut self` on MyBuffer
    // the deferred references are invalidated due to their lifetimes.
    // this implicitly calls DerefMut::deref_mut() and then UnsafeCell::get_mut():
    let mut_ref: &mut [u8] = my_buffer.get_mut();
    // with the next statement uncommmented, the above statement will error:
    // "cannot borrow `my_buffer` as mutable because it is also borrowed as immutable"
    //let mut_ref2: &mut [u8] = deferred_mut.deref_mut(); // uncomment for error
}

Required methods

unsafe fn defer_mut(&self) -> Deferred<&mut Self::Target>[src]

Obtain a deferred mutable reference to Defer::Target.

Example

use deferred_reference::{Defer, DeferMut};
use core::cell::UnsafeCell;
let buffer = UnsafeCell::new([0u8; 1024]);
// calling defer() or defer_mut() immutably borrows `buffer` for as long
// as the returned `Deferred` is in use.
let deferred = buffer.defer();
// SAFETY: this is safe, because we promise not to create an overlapping mutable reference
let mut deferred_mut = unsafe { buffer.defer_mut() };
// both `deferred` and `deferred_mut` can be safely immutably dereferenced simultaneously:
assert_eq!(&deferred[0], &deferred_mut[0]);
// we can mutate the `buffer` through `deferred_mut` as any other array.
// this implicity creates a temporary mutable reference into the array inside `buffer`.
// even though an immutable reference to `buffer` exists, this is okay because
// the inner array sits inside an `UnsafeCell` which allows interior mutability:
deferred_mut[0] = 42; 
// and observe the change through `deferred`:
assert_eq!(deferred[0], 42);
// all this time, both deferred references are alive, but because
// these are not actual references, this doesn't violate the Rust borrow
// rules and this is not undefined behavior. The lifetimes of the mutable
// and immutable references derived from the Deferred do not overlap,
// so the Rust borrow rules are respected all this time.
assert_eq!(&deferred[0], &deferred_mut[0]);
// this also works for multiple deferred mutable references!
// SAFETY: this is safe, because we promise not to create overlapping references
let mut deferred_mut2 = unsafe { buffer.defer_mut() };
// we can mutate the buffer through 2 distinct deferred mutable references
// (as long as we don't do this at the same time!)
deferred_mut[0] += 1;
deferred_mut2[0] += 1;
assert_eq!(44, deferred[0]);
assert_eq!(deferred_mut[0], deferred_mut2[0]);
// because `Deferred` implements the `Index` and `IndexMut` trait, it is possible
// to create two references that overlap in lifetime, but are disjoint in index:
assert_eq!(&mut deferred_mut[1], &mut deferred_mut2[2]); // indices are disjoint, so no UB

Safety

This method is unsafe, because it is possible to call it more than once. This is in contrast to the regular Rust borrowing rules, where it is only allowed to have one mutable borrow at a time. Deferred instances are not actual references and this is why this is not considered undefined behavior. However, the absence of instant undefined behavior does not make this method safe. Deferred also implements the DerefMut trait, which lets anyone call <Deferred as DerefMut>::deref_mut(&mut self) on the Deferred and this creates an actual mutable reference from safe code. Hence, this method must be marked as unsafe, otherwise it could lead to unsoundness when creating multiple mutable references from safe code. The caller must take special care not to create any references (mutable or immutable) that may overlap with the actual mutable reference created from the returned Deferred<&mut T>. Note that overlap means a reference to the same region during the same lifetime. If two Deferred both create a reference to the same region, but with disjoint lifetimes, then this is safe.

Loading content...

Implementations on Foreign Types

impl<T: ?Sized> DeferMut for UnsafeCell<T>[src]

Loading content...

Implementors

impl<T: ?Sized> DeferMut for Deferred<&mut T>[src]

Loading content...