use core::{fmt::Debug, marker::PhantomData, ptr::NonNull};
use crate::{RecCell, RecToken, utils::into_ok};
pub trait Sealed {}
pub trait CellLike<'t>: Sealed {
type Cursor<'a>
where
't: 'a,
Self: 'a;
type CursorMut<'a>
where
't: 'a,
Self: 'a;
fn as_cursor<'a>(&'a self, token: &'a RecToken<'t>) -> Self::Cursor<'a>;
fn as_cursor_mut<'a>(&'a self, token: &'a mut RecToken<'t>) -> Self::CursorMut<'a>;
}
impl<T> Sealed for RecCell<'_, T> {}
impl<'t, T> CellLike<'t> for RecCell<'t, T> {
type Cursor<'a>
= Cursor<'a, 't, T>
where
't: 'a,
Self: 'a;
type CursorMut<'a>
= CursorMut<'a, 't, T>
where
't: 'a,
Self: 'a;
fn as_cursor<'a>(&'a self, token: &'a RecToken<'t>) -> Cursor<'a, 't, T> {
self.cursor(token)
}
fn as_cursor_mut<'a>(&'a self, token: &'a mut RecToken<'t>) -> CursorMut<'a, 't, T> {
self.cursor_mut(token)
}
}
impl<T> Sealed for [RecCell<'_, T>] {}
impl<'t, T> CellLike<'t> for [RecCell<'t, T>] {
type Cursor<'a>
= SliceCursor<'a, 't, T>
where
't: 'a,
Self: 'a;
type CursorMut<'a>
= SliceCursorMut<'a, 't, T>
where
't: 'a,
Self: 'a;
fn as_cursor<'a>(&'a self, token: &'a RecToken<'t>) -> Self::Cursor<'a> {
SliceCursor::new(self, token)
}
fn as_cursor_mut<'a>(&'a self, token: &'a mut RecToken<'t>) -> Self::CursorMut<'a> {
SliceCursorMut::new(self, token)
}
}
impl<T, const N: usize> Sealed for [RecCell<'_, T>; N] {}
impl<'t, T, const N: usize> CellLike<'t> for [RecCell<'t, T>; N] {
type Cursor<'a>
= Cursor<'a, 't, [T; N]>
where
't: 'a,
Self: 'a;
type CursorMut<'a>
= CursorMut<'a, 't, [T; N]>
where
't: 'a,
Self: 'a;
fn as_cursor<'a>(&'a self, token: &'a RecToken<'t>) -> Self::Cursor<'a> {
RecCell::from_array_of_cells(self).cursor(token)
}
fn as_cursor_mut<'a>(&'a self, token: &'a mut RecToken<'t>) -> Self::CursorMut<'a> {
RecCell::from_array_of_cells(self).cursor_mut(token)
}
}
impl<'t, T> RecCell<'t, T> {
pub const fn cursor<'a>(&'a self, token: &'a RecToken<'t>) -> Cursor<'a, 't, T> {
Cursor {
cell: self,
token: RecTokenRef::new(token),
}
}
pub const fn cursor_mut<'a>(&'a self, token: &'a mut RecToken<'t>) -> CursorMut<'a, 't, T> {
CursorMut {
cell: self,
token: RecTokenMut::new(token),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct RecTokenRef<'a, 't>(PhantomData<&'a RecToken<'t>>);
impl Debug for RecTokenRef<'_, '_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Debug::fmt(self.get(), f)
}
}
impl<'a, 't> RecTokenRef<'a, 't> {
const fn new(_: &'a RecToken<'t>) -> Self {
Self(PhantomData)
}
#[allow(clippy::unused_self, clippy::trivially_copy_pass_by_ref)]
const fn get(&self) -> &RecToken<'t> {
unsafe { NonNull::dangling().as_ref() }
}
#[allow(clippy::unused_self)]
const fn into_inner(self) -> &'a RecToken<'t> {
unsafe { NonNull::dangling().as_ref() }
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct RecTokenMut<'a, 't>(PhantomData<&'a mut RecToken<'t>>);
impl Debug for RecTokenMut<'_, '_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Debug::fmt(self.get(), f)
}
}
impl<'a, 't> RecTokenMut<'a, 't> {
const fn new(_: &'a mut RecToken<'t>) -> Self {
Self(PhantomData)
}
#[allow(clippy::unused_self)]
const fn get(&self) -> &RecToken<'t> {
unsafe { NonNull::dangling().as_ref() }
}
#[allow(clippy::unused_self)]
const fn get_mut(&mut self) -> &mut RecToken<'t> {
unsafe { NonNull::dangling().as_mut() }
}
#[allow(clippy::unused_self)]
const fn into_inner(self) -> &'a mut RecToken<'t> {
unsafe { NonNull::dangling().as_mut() }
}
}
pub struct Cursor<'a, 't, T> {
cell: &'a RecCell<'t, T>,
token: RecTokenRef<'a, 't>,
}
impl<T> Debug for Cursor<'_, '_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Cursor")
.field("cell", &self.cell)
.field("token", &self.token)
.finish()
}
}
impl<'a, 't, T> Cursor<'a, 't, T> {
#[must_use]
pub const fn into_inner(self) -> (&'a RecCell<'t, T>, &'a RecToken<'t>) {
(self.cell, self.token.into_inner())
}
#[must_use]
pub const fn get(&self) -> &T {
self.cell.borrow(self.token.get())
}
pub fn map<C: CellLike<'t>>(self, f: impl FnOnce(&T) -> &'a C) -> C::Cursor<'a> {
into_ok(self.try_map(|t| Ok(f(t))))
}
pub fn try_map<C: CellLike<'t>, E>(
self,
f: impl FnOnce(&T) -> Result<&'a C, E>,
) -> Result<C::Cursor<'a>, E> {
let (cell, token) = self.into_inner();
let new_cell = f(cell.borrow(token))?;
Ok(new_cell.as_cursor(token))
}
pub fn update(&mut self, f: impl FnOnce(&T) -> &'a RecCell<'t, T>) {
into_ok(self.try_update(|t| Ok(f(t))));
}
pub fn try_update<E>(
&mut self,
f: impl FnOnce(&T) -> Result<&'a RecCell<'t, T>, E>,
) -> Result<(), E> {
self.cell = f(self.cell.borrow(self.token.get()))?;
Ok(())
}
pub fn map_cell<C: CellLike<'t>>(
self,
f: impl FnOnce(&'a RecCell<'t, T>) -> &'a C,
) -> C::Cursor<'a> {
into_ok(self.try_map_cell(|c| Ok(f(c))))
}
pub fn try_map_cell<C: CellLike<'t>, E>(
self,
f: impl FnOnce(&'a RecCell<'t, T>) -> Result<&'a C, E>,
) -> Result<C::Cursor<'a>, E> {
let (cell, token) = self.into_inner();
let new_cell = f(cell)?;
Ok(new_cell.as_cursor(token))
}
}
pub struct CursorMut<'a, 't, T> {
cell: &'a RecCell<'t, T>,
token: RecTokenMut<'a, 't>,
}
impl<T> Debug for CursorMut<'_, '_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("CursorMut")
.field("cell", &self.cell)
.field("token", &self.token)
.finish()
}
}
impl<'a, 't, T> CursorMut<'a, 't, T> {
pub const fn new(cell: &'a RecCell<'t, T>, token: &'a mut RecToken<'t>) -> Self {
Self {
cell,
token: RecTokenMut::new(token),
}
}
#[must_use]
pub const fn into_inner(self) -> (&'a RecCell<'t, T>, &'a mut RecToken<'t>) {
(self.cell, self.token.into_inner())
}
#[must_use]
pub const fn get(&self) -> &T {
self.cell.borrow(self.token.get())
}
pub const fn get_mut(&mut self) -> &mut T {
self.cell.borrow_mut(self.token.get_mut())
}
pub const fn replace(&mut self, value: T) -> T {
core::mem::replace(self.get_mut(), value)
}
pub fn take(&mut self) -> T
where
T: Default,
{
core::mem::take(self.get_mut())
}
pub fn map<C: CellLike<'t>>(self, f: impl FnOnce(&mut T) -> &'a C) -> C::CursorMut<'a> {
into_ok(self.try_map(|t| Ok(f(t))))
}
pub fn try_map<C: CellLike<'t>, E>(
self,
f: impl FnOnce(&mut T) -> Result<&'a C, E>,
) -> Result<C::CursorMut<'a>, E> {
let (cell, token) = self.into_inner();
let new_cell = f(cell.borrow_mut(token))?;
Ok(new_cell.as_cursor_mut(token))
}
pub fn update(&mut self, f: impl FnOnce(&mut T) -> &'a RecCell<'t, T>) {
into_ok(self.try_update(|t| Ok(f(t))));
}
pub fn try_update<E>(
&mut self,
f: impl FnOnce(&mut T) -> Result<&'a RecCell<'t, T>, E>,
) -> Result<(), E> {
self.cell = f(self.cell.borrow_mut(self.token.get_mut()))?;
Ok(())
}
pub fn map_cell<C: CellLike<'t>>(
self,
f: impl FnOnce(&'a RecCell<'t, T>) -> &'a C,
) -> C::CursorMut<'a> {
into_ok(self.try_map_cell(|c| Ok(f(c))))
}
pub fn try_map_cell<C: CellLike<'t>, E>(
self,
f: impl FnOnce(&'a RecCell<'t, T>) -> Result<&'a C, E>,
) -> Result<C::CursorMut<'a>, E> {
let (cell, token) = self.into_inner();
let new_cell = f(cell)?;
Ok(new_cell.as_cursor_mut(token))
}
}
pub struct SliceCursor<'a, 't, T> {
cells: &'a [RecCell<'t, T>],
token: RecTokenRef<'a, 't>,
}
impl<T> Clone for SliceCursor<'_, '_, T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for SliceCursor<'_, '_, T> {}
impl<T> Debug for SliceCursor<'_, '_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SliceCursor")
.field("cells", &self.cells)
.field("token", &self.token)
.finish()
}
}
impl<'a, 't, T> SliceCursor<'a, 't, T> {
pub const fn new(cells: &'a [RecCell<'t, T>], token: &'a RecToken<'t>) -> Self {
Self {
cells,
token: RecTokenRef::new(token),
}
}
#[must_use]
pub const fn into_inner(self) -> (&'a [RecCell<'t, T>], &'a RecToken<'t>) {
(self.cells, self.token.into_inner())
}
#[must_use]
pub const fn get(&self) -> &[T] {
RecCell::borrow_slice(self.cells, self.token.get())
}
pub fn map<C: CellLike<'t>>(self, f: impl FnOnce(&[T]) -> &'a C) -> C::Cursor<'a> {
into_ok(self.try_map(|values| Ok(f(values))))
}
pub fn try_map<C: CellLike<'t>, E>(
self,
f: impl FnOnce(&[T]) -> Result<&'a C, E>,
) -> Result<C::Cursor<'a>, E> {
let (cells, token) = self.into_inner();
let new_cell = f(RecCell::borrow_slice(cells, token))?;
Ok(new_cell.as_cursor(token))
}
pub fn update(&mut self, f: impl FnOnce(&[T]) -> &'a [RecCell<'t, T>]) {
into_ok(self.try_update(|values| Ok(f(values))));
}
pub fn try_update<E>(
&mut self,
f: impl FnOnce(&[T]) -> Result<&'a [RecCell<'t, T>], E>,
) -> Result<(), E> {
self.cells = f(RecCell::borrow_slice(self.cells, self.token.get()))?;
Ok(())
}
pub fn map_cell<C: CellLike<'t>>(
self,
f: impl FnOnce(&'a [RecCell<'t, T>]) -> &'a C,
) -> C::Cursor<'a> {
into_ok(self.try_map_cell(|cells| Ok(f(cells))))
}
pub fn try_map_cell<C: CellLike<'t>, E>(
self,
f: impl FnOnce(&'a [RecCell<'t, T>]) -> Result<&'a C, E>,
) -> Result<C::Cursor<'a>, E> {
let (cells, token) = self.into_inner();
let new_cell = f(cells)?;
Ok(new_cell.as_cursor(token))
}
}
pub struct SliceCursorMut<'a, 't, T> {
cells: &'a [RecCell<'t, T>],
token: RecTokenMut<'a, 't>,
}
impl<T> Debug for SliceCursorMut<'_, '_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SliceCursorMut")
.field("cells", &self.cells)
.field("token", &self.token)
.finish()
}
}
impl<'a, 't, T> SliceCursorMut<'a, 't, T> {
pub const fn new(cells: &'a [RecCell<'t, T>], token: &'a mut RecToken<'t>) -> Self {
Self {
cells,
token: RecTokenMut::new(token),
}
}
#[must_use]
pub const fn into_inner(self) -> (&'a [RecCell<'t, T>], &'a mut RecToken<'t>) {
(self.cells, self.token.into_inner())
}
#[must_use]
pub const fn get(&self) -> &[T] {
RecCell::borrow_slice(self.cells, self.token.get())
}
pub const fn get_mut(&mut self) -> &mut [T] {
RecCell::borrow_slice_mut(self.cells, self.token.get_mut())
}
pub fn map<C: CellLike<'t>>(self, f: impl FnOnce(&mut [T]) -> &'a C) -> C::CursorMut<'a> {
into_ok(self.try_map(|values| Ok(f(values))))
}
pub fn try_map<C: CellLike<'t>, E>(
self,
f: impl FnOnce(&mut [T]) -> Result<&'a C, E>,
) -> Result<C::CursorMut<'a>, E> {
let (cells, token) = self.into_inner();
let new_cell = f(RecCell::borrow_slice_mut(cells, token))?;
Ok(new_cell.as_cursor_mut(token))
}
pub fn update(&mut self, f: impl FnOnce(&mut [T]) -> &'a [RecCell<'t, T>]) {
into_ok(self.try_update(|values| Ok(f(values))));
}
pub fn try_update<E>(
&mut self,
f: impl FnOnce(&mut [T]) -> Result<&'a [RecCell<'t, T>], E>,
) -> Result<(), E> {
self.cells = f(RecCell::borrow_slice_mut(self.cells, self.token.get_mut()))?;
Ok(())
}
pub fn map_cell<C: CellLike<'t>>(
self,
f: impl FnOnce(&'a [RecCell<'t, T>]) -> &'a C,
) -> C::CursorMut<'a> {
into_ok(self.try_map_cell(|cells| Ok(f(cells))))
}
pub fn try_map_cell<C: CellLike<'t>, E>(
self,
f: impl FnOnce(&'a [RecCell<'t, T>]) -> Result<&'a C, E>,
) -> Result<C::CursorMut<'a>, E> {
let (cells, token) = self.into_inner();
let new_cell = f(cells)?;
Ok(new_cell.as_cursor_mut(token))
}
}