toast-cell 0.4.0

Zero-cost type-branded cell with no runtime checks
Documentation
//! A type-branded cell for aliasing checked at compile-time.
//!
//! It's based on the prior work of [GhostCell], but trades lifetime brands for
//! type brands.
//!
//! [GhostCell]: https://plv.mpi-sws.org/rustbelt/ghostcell/
//!
//! # Usage
//!
//! The interface of this crate is very similar to that of GhostCell. The main
//! difference is that "tokens" are type brands from
//! [`type-factory`](type_factory) instead of lifetime brands.
//!
//! ```
//! use toast_cell::{type_factory, Cell};
//!
//! // Create a unique token.
//! type_factory::with(|mut token| {
//!     let cell = Cell::new(0);
//!
//!     // These are all references to the same cell, but we can still mutate it safely!
//!     let references = [&cell, &cell, &cell];
//!     for cell in references {
//!         *cell.borrow_mut(&mut token) += 1;
//!     }
//!
//!     assert_eq!(cell.into_inner(), 3);
//! });
//! ```
//!
//! As <code>impl [Unique]</code> brand types cannot be copied and are
//! exclusively borrowed for mutation, [`Cell`]s of the same brand are
//! guaranteed to never alias.
//!
//! ```compile_fail,E0499
//! # use toast_cell::{type_factory, Cell};
//! type_factory::with(|mut token| {
//!     let cell = Cell::new("Ghost");
//!     let borrow1 = cell.borrow_mut(&mut token);
//!     let borrow2 = cell.borrow_mut(&mut token);
//!
//!     // error: cannot borrow `token` as mutable more than once at a time
//!     *borrow1 = "Toast";
//! });
//! ```
//!
//! It is also guaranteed that cells used with one brand are incompatible with
//! other brands.
//!
//! ```compile_fail,E0308
//! # use toast_cell::{type_factory, Cell};
//! type_factory::with(|token| {
//!     let (mut token, mut other_token) = type_factory::split(token);
//!
//!     let cell = Cell::new(41);
//!     *cell.borrow_mut(&mut token) += 1;       // ✅
//!     *cell.borrow_mut(&mut other_token) -= 1; // ❌
//! });
//! ```
//!
//! # How does it work?
//!
//! The documentation of this crate is currently rather sparse. I recommend
//! reading the documentation of
//! [`ghost-cell`](https://crates.io/crates/ghost-cell) for more information on
//! the exact properties of GhostCell.
//!
//! # Safety
//!
//! Unlike GhostCell, this crate has not been formally proven. Use at your own
//! risk.
//!
//! # Minimum supported Rust version
//!
//! The MSRV is currently 1.83.
//!
//! This may change between minor releases.
//!
//! # License
//!
//! This crate is licensed under the
//! [Blue Oak Model License 1.0.0](https://blueoakcouncil.org/license/1.0.0).

// Attributes
#![cfg_attr(not(any(doc, test)), no_std)]
// Lints
#![deny(
	clippy::multiple_unsafe_ops_per_block,
	clippy::undocumented_unsafe_blocks,
	unsafe_op_in_unsafe_fn
)]

use {
	core::{cell::UnsafeCell, marker::PhantomData, mem},
	type_factory::Unique,
};

#[cfg(any(doctest, test))]
mod tests;

pub use type_factory;

#[repr(transparent)]
pub struct Cell<T, B>
where
	T: ?Sized,
	B: Unique,
{
	marker: PhantomData<fn() -> B>,
	inner: UnsafeCell<T>,
}

impl<T, B> Cell<T, B>
where
	B: Unique,
{
	pub const fn new(value: T) -> Self {
		Self {
			marker: PhantomData,
			inner: UnsafeCell::new(value),
		}
	}

	pub fn into_inner(self) -> T {
		self.inner.into_inner()
	}

	pub fn take(&self, token: &mut B) -> T
	where
		T: Default,
	{
		mem::take(self.borrow_mut(token))
	}

	pub const fn replace(&self, value: T, token: &mut B) -> T {
		mem::replace(self.borrow_mut(token), value)
	}
}

impl<T, B> Cell<T, B>
where
	T: ?Sized,
	B: Unique,
{
	pub const fn from_mut(value: &mut T) -> &mut Self {
		// SAFETY: `Cell<T, B>` is `repr(transparent)` over `T`.
		unsafe { &mut *(value as *mut T as *mut Self) }
	}

	pub const fn get_mut(&mut self) -> &mut T {
		self.inner.get_mut()
	}

	pub const fn as_ptr(&self) -> *mut T {
		self.inner.get()
	}

	pub const fn borrow<'a>(&'a self, #[allow(unused_variables)] token: &'a B) -> &'a T {
		// SAFETY: The token is immutably borrowed so there is no aliasing.
		unsafe { &*self.inner.get() }
	}

	pub const fn borrow_mut<'a>(
		&'a self,
		#[allow(unused_variables)] token: &'a mut B,
	) -> &'a mut T {
		// SAFETY: The token is mutably borrowed so there is no aliasing.
		unsafe { &mut *self.inner.get() }
	}
}

impl<T, B> AsMut<T> for Cell<T, B>
where
	T: ?Sized,
	B: Unique,
{
	fn as_mut(&mut self) -> &mut T {
		self.get_mut()
	}
}

impl<T, B> Default for Cell<T, B>
where
	T: Default,
	B: Unique,
{
	fn default() -> Self {
		Self::new(T::default())
	}
}

impl<T, B> From<T> for Cell<T, B>
where
	B: Unique,
{
	fn from(value: T) -> Self {
		Self::new(value)
	}
}

// SAFETY: `Cell<T>` owns `T`, so it can be sent across threads if `T` can.
unsafe impl<T, B> Send for Cell<T, B>
where
	T: ?Sized + Send,
	B: Unique,
{
}

// SAFETY: `Cell<T>` owns `T`, so it can be accessed from different threads
//         if `T` can. `T` must also be `Send` as it can be extracted from
//         methods such as `Cell::replace`
unsafe impl<T, B> Sync for Cell<T, B>
where
	T: ?Sized + Send + Sync,
	B: Unique,
{
}