use core::{
cell::UnsafeCell,
marker::PhantomData,
mem,
};
pub struct GhostToken<'brand> { _marker: InvariantLifetime<'brand> }
impl<'brand> GhostToken<'brand> {
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)
}
}
unsafe impl<'brand> Send for GhostToken<'brand> {}
unsafe impl<'brand> Sync for GhostToken<'brand> {}
pub struct GhostCell<'brand, T: ?Sized> {
_marker: InvariantLifetime<'brand>,
value: UnsafeCell<T>,
}
impl<'brand, T> GhostCell<'brand, T> {
pub fn new(value: T) -> Self {
let _marker = InvariantLifetime::default();
let value = UnsafeCell::new(value);
Self { _marker, value, }
}
pub fn into_inner(self) -> T { self.value.into_inner() }
pub fn borrow<'a>(&'a self, _: &'a GhostToken<'brand>) -> &'a T {
unsafe{ &*self.value.get() }
}
pub fn borrow_mut<'a>(&'a self, _: &'a mut GhostToken<'brand>) -> &'a mut T {
unsafe{ &mut *self.value.get() }
}
}
impl<'brand, T: ?Sized> GhostCell<'brand, T> {
pub const fn as_ptr(&self) -> *mut T { self.value.get() }
pub fn get_mut(&mut self) -> &mut T {
unsafe { mem::transmute(self) }
}
pub fn from_mut(t: &mut T) -> &mut Self {
unsafe { mem::transmute(t) }
}
}
#[forbid(unsafe_code)]
impl<'brand, T> GhostCell<'brand, T> {
pub fn replace(&self, value: T, token: &mut GhostToken<'brand>) -> T {
mem::replace(self.borrow_mut(token), value)
}
pub fn take(&self, token: &mut GhostToken<'brand>) -> T
where
T: Default,
{
self.replace(T::default(), token)
}
}
impl<'brand, T> GhostCell<'brand, [T]> {
pub fn as_slice_of_cells(&self) -> &[GhostCell<'brand, T>] {
unsafe { &*(self.as_ptr() as *mut [GhostCell<'brand, T>]) }
}
}
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) }
}
unsafe impl<'brand, T: Send> Send for GhostCell<'brand, T> {}
unsafe impl<'brand, T: Send + Sync> Sync for GhostCell<'brand, T> {}
type InvariantLifetime<'brand> = PhantomData<fn(&'brand ()) -> &'brand ()>;
#[doc(hidden)]
pub mod compile_tests {
pub fn token_noescape() {}
pub fn cell_noescape() {}
pub fn cell_borrow_borrows_token() {}
pub fn cell_borrow_mut_borrows_token_mutably() {}
pub fn cell_borrow_borrows_cell() {}
pub fn cell_borrow_mut_borrows_cell() {}
pub fn cell_get_mut_borrows_cell_mutably() {}
pub fn cell_from_mut_borrows_value_mutably() {}
}