//! `GhostCell` and `GhostToken`, as per <https://plv.mpi-sws.org/rustbelt/ghostcell/>.
//!
//! Reference implementation at <https://gitlab.mpi-sws.org/FP/ghostcell/-/tree/master/ghostcell>.
use core::{cell::UnsafeCell, marker::PhantomData, mem};
/// A `GhostToken<'x>` is _the_ key to access the content of any `&GhostCell<'x, _>` sharing the same brand.
///
/// Each `GhostToken<'x>` is created alongside a unique brand (its lifetime), and each `GhostCell<'x, T>` is associated
/// to one, and only one, `GhostToken` at a time via this brand. The entire set of `GhostCell<'x, T>` associated to a
/// given `GhostToken<'x>` creates a pool of cells all being accessible solely through the one token they are associated
/// to.
///
/// The pool of `GhostCell` associated to a token need not be homogeneous, each may own a value of a different type.
pub struct GhostToken<'brand> {
_marker: InvariantLifetime<'brand>,
}
impl<'brand> GhostToken<'brand> {
/// Creates a fresh token to which `GhostCell`s can be tied to later.
///
/// Due to the use of a lifetime, the `GhostCell`s tied to a given token can only live within the confines of the
/// invocation of the `fun` closure.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let n = 12;
///
/// let value = GhostToken::new(|mut token| {
/// let cell = GhostCell::new(42);
///
/// let vec: Vec<_> = (0..n).map(|_| &cell).collect();
///
/// *vec[n / 2].borrow_mut(&mut token) = 33;
///
/// *cell.borrow(&token)
/// });
///
/// assert_eq!(33, value);
/// ```
#[allow(clippy::new_ret_no_self)]
pub fn new<R, F>(fun: F) -> R
where
for<'new_brand> F: FnOnce(GhostToken<'new_brand>) -> R,
{
let token = Self {
_marker: InvariantLifetime::default(),
};
fun(token)
}
}
/// A `GhostToken` is stateless, therefore it can safely be passed across threads.
unsafe impl<'brand> Send for GhostToken<'brand> {}
/// A `GhostToken` is stateless, therefore it can safely be accessed from different threads.
unsafe impl<'brand> Sync for GhostToken<'brand> {}
/// Branded wrapper for a value, whose type is `T`.
///
/// A `GhostCell<'x, T>` owns an instance of type `T`:
/// - Unique access to the cell allows unimpeded access to the contained value.
/// - Shared access to the cell requires mediating access through the associated `GhostToken<'x, T>` which will
/// enforce at compile-time the aliasing XOR mutability safety property.
#[repr(transparent)]
pub struct GhostCell<'brand, T: ?Sized> {
_marker: InvariantLifetime<'brand>,
value: UnsafeCell<T>,
}
impl<'brand, T> GhostCell<'brand, T> {
/// Wraps some `T` into a `GhostCell` with brand `'brand` which associates it to one, and only one, `GhostToken`.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// GhostToken::new(|token| {
/// let cell = GhostCell::new(42);
///
/// assert_eq!(42, *cell.borrow(&token));
/// });
/// ```
pub const fn new(value: T) -> Self {
let _marker = PhantomData;
let value = UnsafeCell::new(value);
Self { _marker, value }
}
/// Turns an owned `GhostCell` back into owned data.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let value = GhostToken::new(|mut token| {
/// let cell = GhostCell::new(42);
///
/// cell.into_inner()
/// });
///
/// assert_eq!(42, value);
/// ```
pub fn into_inner(self) -> T {
self.value.into_inner()
}
}
impl<'brand, T: ?Sized> GhostCell<'brand, T> {
/// Immutably borrows the `GhostCell` with the same-branded token.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let n = 12;
///
/// let value = GhostToken::new(|mut token| {
/// let cell = GhostCell::new(42);
///
/// let vec: Vec<_> = (0..n).map(|_| &cell).collect();
///
/// let one: &i32 = vec[1].borrow(&token);
/// let two: &i32 = vec[2].borrow(&token);
///
/// *one + *two
/// });
///
/// assert_eq!(84, value);
/// ```
pub fn borrow<'a>(&'a self, _: &'a GhostToken<'brand>) -> &'a T {
// Safety:
// - The cell is borrowed immutably by this call, it therefore cannot already be borrowed mutably.
// - The token is borrowed immutably by this call, it therefore cannot be already borrowed mutably.
// - `self.value` therefore cannot be already borrowed mutably, as doing so requires calling either:
// - `borrow_mut`, which would borrow the token mutably.
// - `get_mut`, which would borrow the cell mutably.
unsafe { &*self.value.get() }
}
/// Mutably borrows the `GhostCell` with the same-branded token.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let n = 12;
///
/// let value = GhostToken::new(|mut token| {
/// let cell = GhostCell::new(42);
///
/// let vec: Vec<_> = (0..n).map(|_| &cell).collect();
///
/// let reference: &mut i32 = vec[n / 2].borrow_mut(&mut token);
/// *reference = 33;
///
/// *cell.borrow(&token)
/// });
///
/// assert_eq!(33, value);
/// ```
pub fn borrow_mut<'a>(&'a self, _: &'a mut GhostToken<'brand>) -> &'a mut T {
// Safety:
// - The cell is borrowed immutably by this call, it therefore cannot already be borrowed mutably.
// - The token is borrowed mutably by this call, it therefore cannot be already borrowed.
// - `self.value` therefore cannot already be borrowed, as doing so requires calling either:
// - `borrow` or `borrow_mut`, which would borrow the token.
// - `get_mut`, which would borrow the cell mutably.
unsafe { &mut *self.value.get() }
}
/// Returns a raw pointer to the contained value.
pub const fn as_ptr(&self) -> *mut T {
self.value.get()
}
/// Turns a mutably borrowed `GhostCell` into mutably borrowed data.
///
/// `self` is mutably borrowed for the lifetime of the result, ensuring the absence of aliasing.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let value = GhostToken::new(|mut token| {
/// let mut cell = GhostCell::new(42);
///
/// *cell.get_mut() = 33;
///
/// *cell.borrow(&token)
/// });
///
/// assert_eq!(33, value);
/// ```
pub fn get_mut(&mut self) -> &mut T {
// Safety:
// - `self` is mutably borrowed for the duration.
// - `GhostCell<'_, T>` has the same in-memory representation as `T`.
unsafe { mem::transmute(self) }
}
/// Turns mutably borrowed data into a mutably borrowed `GhostCell`.
///
/// `t` is mutably borrowed for the lifetime of the result, ensuring the absence of aliasing.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let n = 12;
/// let mut value = 42;
///
/// GhostToken::new(|mut token| {
/// let cell = GhostCell::from_mut(&mut value);
///
/// let vec: Vec<_> = (0..n).map(|_| &cell).collect();
///
/// *vec[n / 2].borrow_mut(&mut token) = 33;
/// });
///
/// assert_eq!(33, value);
/// ```
pub fn from_mut(t: &mut T) -> &mut Self {
// Safety:
// - `t` is mutably borrowed for the duration.
// - `GhostCell<'_, T>` has the same in-memory representation as `T`.
unsafe { mem::transmute(t) }
}
}
// Safe convenience methods
#[forbid(unsafe_code)]
impl<'brand, T> GhostCell<'brand, T> {
/// Returns the value, replacing it by the supplied one.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let n = 12;
///
/// let value = GhostToken::new(|mut token| {
/// let cell = GhostCell::new(42);
///
/// let vec: Vec<_> = (0..n).map(|_| &cell).collect();
///
/// let previous = vec[n / 2].replace(33, &mut token);
/// assert_eq!(42, previous);
///
/// *cell.borrow(&token)
/// });
///
/// assert_eq!(33, value);
/// ```
pub fn replace(&self, value: T, token: &mut GhostToken<'brand>) -> T {
mem::replace(self.borrow_mut(token), value)
}
/// Returns the value, replacing it with the default value.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let n = 12;
///
/// let value = GhostToken::new(|mut token| {
/// let cell = GhostCell::new(42);
///
/// let vec: Vec<_> = (0..n).map(|_| &cell).collect();
///
/// let previous = vec[n / 2].take(&mut token);
/// assert_eq!(42, previous);
///
/// *cell.borrow(&token)
/// });
///
/// assert_eq!(0, value);
/// ```
pub fn take(&self, token: &mut GhostToken<'brand>) -> T
where
T: Default,
{
self.replace(T::default(), token)
}
/// Swaps the values of two cells.
///
/// If the cells fully overlap, i.e. they have the same address, they are "swapped" (a no-op) and `Ok` is returned.
/// `Err` is returned if they overlap in any other way and can't be swapped.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let n = 12;
///
/// let value = GhostToken::new(|mut token| {
/// let cell1 = GhostCell::new(42);
/// let cell2 = GhostCell::new(33);
///
/// let vec: Vec<_> = (0..n).flat_map(|_| [&cell1, &cell2]).collect();
///
/// vec[n / 2].swap(&vec[n / 2 + 1], &mut token).expect("overlapping references");
///
/// *cell1.borrow(&token)
/// });
///
/// assert_eq!(33, value);
/// ```
#[cfg(feature = "experimental-multiple-mutable-borrows")]
pub fn swap(
&self,
other: &Self,
token: &mut GhostToken<'brand>,
) -> Result<(), crate::ghost_borrow_mut::GhostAliasingError> {
// Ignore full overlap.
if core::ptr::eq(self, other) {
return Ok(());
}
crate::ghost_borrow_mut::GhostBorrowMut::borrow_mut((self, other), token).map(|(a, b)| mem::swap(a, b))
}
}
impl<'brand, T: Default> Default for GhostCell<'brand, T> {
fn default() -> Self {
Self::new(T::default())
}
}
impl<'brand, T> GhostCell<'brand, [T]> {
/// Returns a slice of cells from a cell containing a slice.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let n = 12;
///
/// let value = GhostToken::new(|mut token| {
/// let mut vec: Vec<_> = (0..n).collect();
/// let cell = GhostCell::from_mut(&mut vec[..]);
///
/// let slice = cell.as_slice_of_cells();
///
/// *slice[n / 2].borrow_mut(&mut token) = 33;
///
/// vec[n / 2]
/// });
///
/// assert_eq!(33, value);
/// ```
pub fn as_slice_of_cells(&self) -> &[GhostCell<'brand, T>] {
// Safety:
// - Same lifetime.
// - `GhostCell<'_, T>` has the same in-memory representation as `T`.
unsafe { &*(self.as_ptr() as *mut [GhostCell<'brand, T>]) }
}
/// Returns a cell containing a slice from slice of cells.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let n = 12;
///
/// let value = GhostToken::new(|mut token| {
/// let mut vec: Vec<_> = (0..n).collect();
/// let cell = GhostCell::from_mut(&mut vec[..]);
/// let all_elements = cell.as_slice_of_cells();
///
/// let quad = GhostCell::from_slice_of_cells(&all_elements[4..][..4]);
/// quad.borrow_mut(&mut token).copy_from_slice(&33u32.to_be_bytes());
///
/// vec.iter().position(|&v| v == 33)
/// });
///
/// assert_eq!(Some(7), value);
/// ```
pub fn from_slice_of_cells<'slice>(slice: &'slice [GhostCell<'brand, T>]) -> &'slice Self {
// Safety:
// - Same lifetime.
// - `GhostCell<'_, T>` has the same in-memory representation as `T`.
unsafe { &*(slice as *const _ as *const GhostCell<'brand, [T]>) }
}
}
impl<'brand, T, const N: usize> GhostCell<'brand, [T; N]> {
/// Returns a reference to an array of cells from a cell containing an array.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let value = GhostToken::new(|mut token| {
/// let mut array = [0, 1, 2, 3, 5];
/// let n = array.len();
///
/// let cell = GhostCell::from_mut(&mut array);
///
/// let inner = cell.as_array_of_cells();
///
/// *inner[n / 2].borrow_mut(&mut token) = 33;
///
/// array[n / 2]
/// });
///
/// assert_eq!(33, value);
/// ```
pub fn as_array_of_cells(&self) -> &[GhostCell<'brand, T>; N] {
// Safety:
// - Same lifetime.
// - `GhostCell<'_, T>` has the same in-memory representation as `T`.
unsafe { &*(self.as_ptr() as *mut [GhostCell<'brand, T>; N]) }
}
/// Returns a cell containing an array from an array of cells.
///
/// # Example
///
/// ```rust
/// use ghost_cell::{GhostToken, GhostCell};
///
/// let value = GhostToken::new(|mut token| {
/// let mut array = [0, 1, 2, 3, 5];
/// let n = array.len();
///
/// let cell = GhostCell::from_mut(&mut array);
///
/// let inner = cell.as_array_of_cells();
///
/// let inner = GhostCell::from_array_of_cells(&inner);
///
/// inner.borrow_mut(&mut token)[n / 2] = 33;
///
/// array[n / 2]
/// });
///
/// assert_eq!(33, value);
/// ```
pub fn from_array_of_cells<'a>(array: &'a [GhostCell<'brand, T>; N]) -> &'a Self {
// Safety:
// - Same lifetime.
// - `GhostCell<'_, T>` has the same in-memory representation as `T`.
unsafe { &*(array as *const [GhostCell<'brand, T>; N] as *const Self) }
}
}
macro_rules! ghost_cell_transpose_tuple {
($($t:ident),*) => {
impl<'brand, $($t),*> GhostCell<'brand, ($($t,)*)> {
/// Returns a reference to a tuple of cells from a cell containing a tuple.
pub fn as_tuple_of_cells(&self) -> &($(GhostCell<'brand, $t>,)*) {
// Safety:
// - Same lifetime.
// - `GhostCell<'_, T>` has the same in-memory representation as `T`.
unsafe { &*(self.as_ptr() as *mut ($(GhostCell<'brand, $t>,)*)) }
}
/// Returns a cell containing a tuple from a tuple of cells.
#[allow(clippy::needless_lifetimes)]
pub fn from_tuple_of_cells<'a>(tuple: &'a ($(GhostCell<'brand, $t>,)*)) -> &'a Self {
// Safety:
// - Same lifetime.
// - `GhostCell<'_, T>` has the same in-memory representation as `T`.
unsafe { &*(tuple as *const ($(GhostCell<'brand, $t>,)*) as *const Self) }
}
}
}
}
ghost_cell_transpose_tuple!();
ghost_cell_transpose_tuple!(T0);
ghost_cell_transpose_tuple!(T0, T1);
ghost_cell_transpose_tuple!(T0, T1, T2);
ghost_cell_transpose_tuple!(T0, T1, T2, T3);
ghost_cell_transpose_tuple!(T0, T1, T2, T3, T4);
ghost_cell_transpose_tuple!(T0, T1, T2, T3, T4, T5);
ghost_cell_transpose_tuple!(T0, T1, T2, T3, T4, T5, T6);
ghost_cell_transpose_tuple!(T0, T1, T2, T3, T4, T5, T6, T7);
ghost_cell_transpose_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
ghost_cell_transpose_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
ghost_cell_transpose_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
ghost_cell_transpose_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
impl<'brand, T: ?Sized> AsMut<T> for GhostCell<'brand, T> {
fn as_mut(&mut self) -> &mut T {
self.get_mut()
}
}
impl<'brand, T> From<T> for GhostCell<'brand, T> {
fn from(t: T) -> Self {
Self::new(t)
}
}
/// A `GhostCell<'_, T>` owns a `T`, so it cannot be sent across threads if `T` cannot.
///
/// Conversely, a `GhostCell` does not add any state on top of `T`, so if `T` can be sent across threads, so can
/// `GhostCell<'_, T>`
unsafe impl<'brand, T: ?Sized + Send> Send for GhostCell<'brand, T> {}
/// A `GhostCell<'_, T>` owns a `T`, so it cannot be accessed from different threads if `T` cannot.
///
/// Conversely, a `GhostCell` does not add any state on top of `T`, so if `T` can be accessed from different threads,
/// so can `GhostCell<'_, T>`. `T` also needs to be sendable across threads,
/// because a `T` can be extracted from a `&GhostCell<'brand, T>` via [`GhostCell::replace`].
unsafe impl<'brand, T: ?Sized + Send + Sync> Sync for GhostCell<'brand, T> {}
//
// Implementation
//
type InvariantLifetime<'brand> = PhantomData<fn(&'brand ()) -> &'brand ()>;
#[doc(hidden)]
pub mod compile_tests {
/// ```compile_fail
/// use ghost_cell::{GhostToken, GhostCell};
///
/// GhostToken::new(|token| token);
/// ```
pub fn token_noescape() {}
/// ```compile_fail
/// use ghost_cell::{GhostToken, GhostCell};
///
/// GhostToken::new(|mut token| {
/// let cell = GhostCell::new(42);
///
/// *cell.borrow_mut(&mut token) = 33;
///
/// cell
/// });
/// ```
pub fn cell_noescape() {}
/// ```compile_fail,E0505
/// use ghost_cell::{GhostToken, GhostCell};
///
/// GhostToken::new(|token| {
/// let cell = GhostCell::new(42);
///
/// let r = cell.borrow(&token);
/// std::mem::drop(token);
///
/// *r
/// });
/// ```
pub fn cell_borrow_borrows_token() {}
/// ```compile_fail,E0502
/// use ghost_cell::{GhostToken, GhostCell};
///
/// GhostToken::new(|mut token| {
/// let one = GhostCell::new(1);
/// let two = GhostCell::new(2);
///
/// let r = one.borrow_mut(&mut token);
/// assert_eq!(2, *two.borrow(&token));
///
/// *r = 33;
/// });
/// ```
pub fn cell_borrow_mut_borrows_token_mutably() {}
/// ```compile_fail,E0505
/// use ghost_cell::{GhostToken, GhostCell};
///
/// GhostToken::new(|token| {
/// let cell = GhostCell::new(42);
///
/// let r = cell.borrow(&token);
/// std::mem::drop(cell);
///
/// *r
/// });
/// ```
pub fn cell_borrow_borrows_cell() {}
/// ```compile_fail,E0505
/// use ghost_cell::{GhostToken, GhostCell};
///
/// GhostToken::new(|mut token| {
/// let cell = GhostCell::new(42);
///
/// let r = cell.borrow_mut(&mut token);
/// std::mem::drop(cell);
///
/// *r
/// });
/// ```
pub fn cell_borrow_mut_borrows_cell() {}
/// ```compile_fail,E0502
/// use ghost_cell::{GhostToken, GhostCell};
///
/// GhostToken::new(|token| {
/// let mut cell = GhostCell::new(42);
///
/// let r = cell.get_mut();
/// assert_eq!(42, *cell.borrow(&token));
///
/// *r = 33;
/// });
/// ```
pub fn cell_get_mut_borrows_cell_mutably() {}
/// ```compile_fail,E0502
/// use ghost_cell::{GhostToken, GhostCell};
///
/// GhostToken::new(|token| {
/// let mut value = 42;
///
/// let cell = GhostCell::from_mut(&mut value);
///
/// assert_eq!(42, value);
/// assert_eq!(42, *cell.borrow(&token));
/// });
/// ```
pub fn cell_from_mut_borrows_value_mutably() {}
} // mod compile_tests