pub struct RecCell<'t, T> { /* private fields */ }Expand description
A cell that can be used to create recursive data structures.
RecCell stores a value that can only be accessed through a matching
RecToken. This makes it useful for self-referential or mutually
recursive structures where you want controlled shared or mutable access to
otherwise interior-mutable data.
§Examples
Construction, shared/mutable borrowing, direct exclusive access, and extraction:
use rec_cell::{RecCell, RecToken};
RecToken::new(|mut token| {
let mut cell = RecCell::new(1);
assert_eq!(*cell.borrow(&token), 1);
*cell.borrow_mut(&mut token) = 2;
*cell.get_mut() = 3;
assert_eq!(cell.into_inner(), 3);
});Reinterpreting existing storage, slices, and arrays:
use rec_cell::{RecCell, RecToken};
RecToken::new(|mut token| {
let mut values = [1, 2];
let cells = RecCell::from_slice_mut(&mut values);
RecCell::borrow_slice_mut(cells, &mut token)[0] = 3;
assert_eq!(RecCell::borrow_slice(cells, &token), &[3, 2]);
let mut array = RecCell::new([4, 5]);
let elements = array.as_array_of_cells_mut();
*elements[1].get_mut() = 6;
assert_eq!(RecCell::from_array_of_cells(elements).borrow(&token), &[4, 6]);
});Implementations§
Source§impl<'t, T> RecCell<'t, T>
impl<'t, T> RecCell<'t, T>
Sourcepub const fn new(value: T) -> Self
pub const fn new(value: T) -> Self
Constructs a new instance of RecCell which will wrap the specified
value.
The cell constructed through this method will drop its inner value when dropped.
§Examples
use rec_cell::RecCell;
let cell = RecCell::new(5);
assert_eq!(cell.into_inner(), 5);Sourcepub const fn into_inner(self) -> T
pub const fn into_inner(self) -> T
Unwraps the value, consuming the cell.
No token is required because consuming the cell proves exclusive access.
§Examples
use rec_cell::RecCell;
assert_eq!(RecCell::new("value").into_inner(), "value");Sourcepub fn new_cyclic<'a, R>(
uninit: &'a mut MaybeUninit<T>,
token: RecToken<'t>,
scope: impl FnOnce(&'a Self) -> (R, T),
) -> (R, RecToken<'t>)where
't: 'a,
pub fn new_cyclic<'a, R>(
uninit: &'a mut MaybeUninit<T>,
token: RecToken<'t>,
scope: impl FnOnce(&'a Self) -> (R, T),
) -> (R, RecToken<'t>)where
't: 'a,
Initializes a recursive cell from uninitialized storage.
This is the infallible form of RecCell::try_new_cyclic. The closure
is given a reference to the not-yet-initialized cell, which can be
used to construct values that refer back to it. The destructor of the
constructed value will not be run unless explicitly called afterwards.
If you want to initialize uninitialized storage but do not need the
self-referential capability, consider
RecCell::from_mut(uninit.write(value)) instead.
This function takes the token by value, rather than by mutable
reference, so that it would be impossible to access the
uninitialized cell within the scope or if the closure panics.
If you want to use &mut RecToken, consider RecCell::new_cyclic_with_mut.
If you want to initialize multiple cells at once, consider
RecToken::make_cyclic.
§Examples
use core::mem::MaybeUninit;
use rec_cell::{RecCell, RecToken};
struct SelfRef<'a, 't>(&'static str, &'a RecCell<'t, Self>);
RecToken::new(|token| {
let mut slot = MaybeUninit::uninit();
let (cell, token) = RecCell::new_cyclic(&mut slot, token, |cell| (cell, SelfRef("value", cell)));
assert_eq!(cell.borrow(&token).0, "value");
assert_eq!(cell.borrow(&token).1.borrow(&token).0, "value");
});Sourcepub fn new_cyclic_with_mut<'a, R>(
uninit: &'a mut MaybeUninit<T>,
token: &mut RecToken<'t>,
scope: impl FnOnce(&'a Self) -> (R, T),
) -> Rwhere
't: 'a,
Available on crate feature cyclic_with_mut only.
pub fn new_cyclic_with_mut<'a, R>(
uninit: &'a mut MaybeUninit<T>,
token: &mut RecToken<'t>,
scope: impl FnOnce(&'a Self) -> (R, T),
) -> Rwhere
't: 'a,
cyclic_with_mut only.Initializes a recursive cell from uninitialized storage, using a mutable reference to the token.
On panic of the closure scope, the process will abort to avoid
returning control while the cell is yet to be initialized.
§Examples
use core::mem::MaybeUninit;
use rec_cell::{RecCell, RecToken};
RecToken::new(|mut token| {
let mut slot = MaybeUninit::uninit();
let value = RecCell::new_cyclic_with_mut(&mut slot, &mut token, |_| ((), 4));
assert_eq!(value, ());
});Sourcepub fn try_new_cyclic<'a, R, E>(
uninit: &'a mut MaybeUninit<T>,
token: RecToken<'t>,
scope: impl FnOnce(&'a Self) -> Result<(R, T), E>,
) -> Result<(R, RecToken<'t>), E>where
't: 'a,
pub fn try_new_cyclic<'a, R, E>(
uninit: &'a mut MaybeUninit<T>,
token: RecToken<'t>,
scope: impl FnOnce(&'a Self) -> Result<(R, T), E>,
) -> Result<(R, RecToken<'t>), E>where
't: 'a,
Initializes a recursive cell from uninitialized storage, allowing failure.
The closure may return an error before the value is written. The token is taken by value so it cannot be used to access the cell while the cell is still uninitialized.
If a failure occurs, the caller will be locked out of accessing any of the cells under the same token. This is because the newly created cell has not been initialized and we cannot distinguish between that and initialized cells.
If you want to initialize multiple cells at once, consider
RecToken::try_make_cyclic.
§Examples
use core::mem::MaybeUninit;
use rec_cell::{RecCell, RecToken};
RecToken::new(|token| {
let mut slot = MaybeUninit::uninit();
let (value, _) = RecCell::try_new_cyclic(&mut slot, token, |_| Ok::<_, ()>((7, 1))).unwrap();
assert_eq!(value, 7);
});A closure may return an error before writing the cell:
use core::mem::MaybeUninit;
use rec_cell::{RecCell, RecToken};
RecToken::new(|token| {
let mut slot = MaybeUninit::<usize>::uninit();
let result = RecCell::try_new_cyclic(
&mut slot,
token,
|_| Err::<((), usize), _>("failed"),
);
assert!(matches!(result, Err("failed")));
});Accessing any slot through the token after an error does not compile, because the slot is yet to be initialized:
use core::mem::MaybeUninit;
use rec_cell::{RecCell, RecToken};
RecToken::new(|token| {
let cell = RecCell::new(42);
let mut slot = MaybeUninit::<usize>::uninit();
let bad_slot = RecCell::try_new_cyclic(
&mut slot,
token,
|slot| Err::<((), usize), _>(slot),
).unwrap_err();
// At this point, bad_slot and &cell have the exact same type.
// We must not access bad_slot, so the following must also fail
// to compile:
assert_eq!(*cell.borrow(&token), 42);
});Sourcepub const fn from_mut(value: &mut T) -> &mut Self
pub const fn from_mut(value: &mut T) -> &mut Self
Converts from &mut T to &mut RecCell<T> without moving the value.
§Examples
use rec_cell::RecCell;
let mut value = 1;
*RecCell::from_mut(&mut value).get_mut() = 2;
assert_eq!(value, 2);Sourcepub const fn from_slice_mut(value: &mut [T]) -> &mut [Self]
pub const fn from_slice_mut(value: &mut [T]) -> &mut [Self]
Converts from &mut [T] to &mut [RecCell<T>] without moving values.
§Examples
use rec_cell::RecCell;
let mut values = [1, 2];
*RecCell::from_slice_mut(&mut values)[0].get_mut() = 3;
assert_eq!(values, [3, 2]);Sourcepub const fn get_mut(&mut self) -> &mut T
pub const fn get_mut(&mut self) -> &mut T
Returns a mutable reference to the underlying data.
This call borrows the RecCell mutably, which guarantees that
no borrows to the underlying data exist.
§Examples
use rec_cell::RecCell;
let mut cell = RecCell::new(1);
*cell.get_mut() = 2;
assert_eq!(cell.into_inner(), 2);Sourcepub const fn get_slice_mut(this: &mut [Self]) -> &mut [T]
pub const fn get_slice_mut(this: &mut [Self]) -> &mut [T]
Returns a mutable reference to the underlying slice.
This call borrows the slice of RecCells mutably.
§Examples
use rec_cell::RecCell;
let mut cells = [RecCell::new(1), RecCell::new(2)];
RecCell::get_slice_mut(&mut cells)[1] = 3;
assert_eq!(cells[1].get_mut(), &mut 3);Sourcepub const fn as_ptr(&self) -> *mut T
pub const fn as_ptr(&self) -> *mut T
Returns a raw pointer to the stored value.
Dereferencing it is unsafe. Do not use it to destroy a cyclically initialized value while its token remains usable.
§Examples
use rec_cell::{RecCell, RecToken};
let cell = RecCell::new(1);
assert!(!cell.as_ptr().is_null());Sourcepub const fn as_slice_ptr(this: &[Self]) -> *mut [T]
pub const fn as_slice_ptr(this: &[Self]) -> *mut [T]
Returns a raw pointer to the stored slice value.
§Examples
use rec_cell::RecCell;
let cells = [RecCell::new(1), RecCell::new(2)];
assert_eq!(RecCell::as_slice_ptr(&cells).len(), 2);Sourcepub const fn borrow<'a>(&'a self, _: &'a RecToken<'t>) -> &'a T
pub const fn borrow<'a>(&'a self, _: &'a RecToken<'t>) -> &'a T
Borrows the stored value with a matching token.
§Examples
use rec_cell::{RecCell, RecToken};
RecToken::new(|token| {
let cell = RecCell::new(1);
assert_eq!(*cell.borrow(&token), 1);
});Sourcepub const fn borrow_slice<'a>(this: &'a [Self], _: &'a RecToken<'t>) -> &'a [T]
pub const fn borrow_slice<'a>(this: &'a [Self], _: &'a RecToken<'t>) -> &'a [T]
Borrows a slice of cells with a matching token.
§Examples
use rec_cell::{RecCell, RecToken};
RecToken::new(|token| {
let cells = [RecCell::new(1), RecCell::new(2)];
assert_eq!(RecCell::borrow_slice(&cells, &token), &[1, 2]);
});Sourcepub const fn borrow_mut<'a>(&'a self, _: &'a mut RecToken<'t>) -> &'a mut T
pub const fn borrow_mut<'a>(&'a self, _: &'a mut RecToken<'t>) -> &'a mut T
Mutably borrows the stored value with a matching token.
§Examples
use rec_cell::{RecCell, RecToken};
RecToken::new(|mut token| {
let cell = RecCell::new(1);
*cell.borrow_mut(&mut token) = 2;
assert_eq!(*cell.borrow(&token), 2);
});Sourcepub const fn borrow_slice_mut<'a>(
this: &'a [Self],
_: &'a mut RecToken<'t>,
) -> &'a mut [T]
pub const fn borrow_slice_mut<'a>( this: &'a [Self], _: &'a mut RecToken<'t>, ) -> &'a mut [T]
Mutably borrows a slice of cells with a matching token.
§Examples
use rec_cell::{RecCell, RecToken};
RecToken::new(|mut token| {
let cells = [RecCell::new(1), RecCell::new(2)];
RecCell::borrow_slice_mut(&cells, &mut token)[0] = 3;
assert_eq!(RecCell::borrow_slice(&cells, &token), &[3, 2]);
});Sourcepub const unsafe fn from_uninit(uninit: &mut MaybeUninit<T>) -> &Self
pub const unsafe fn from_uninit(uninit: &mut MaybeUninit<T>) -> &Self
Creates a reference to an uninitialized RecCell from uninitialized
storage.
This must only be used when the RecToken is guaranteed to be taken
out of circulation. You must call
write_to_uninit on the returned
reference before the RecToken is made available to safe code again,
by wrapping your code with an API similar to RecCell::new_cyclic.
§Safety
The caller must keep the matching token unavailable to safe code until
a value has been written with
write_to_uninit.
§Examples
use core::mem::MaybeUninit;
use rec_cell::RecCell;
let mut slot = MaybeUninit::uninit();
let cell = unsafe { RecCell::from_uninit(&mut slot) };
unsafe { cell.write_to_uninit(1) };
assert_eq!(unsafe { slot.assume_init() }, 1);Sourcepub const unsafe fn write_to_uninit(&self, value: T)
pub const unsafe fn write_to_uninit(&self, value: T)
Writes a value to a cell produced by Self::from_uninit.
This should only be paired with from_uninit to
create a self-referential structure. The RecToken must be taken
out of circulation after from_uninit is called and before this method
is called.
§Safety
self must have been created by Self::from_uninit, must not already
contain a value, and the matching token must remain unavailable.
§Examples
use core::mem::MaybeUninit;
use rec_cell::RecCell;
let mut slot = MaybeUninit::uninit();
let cell = unsafe { RecCell::from_uninit(&mut slot) };
unsafe { cell.write_to_uninit(3) };
assert_eq!(unsafe { slot.assume_init() }, 3);Source§impl<'t, T, const N: usize> RecCell<'t, [T; N]>
impl<'t, T, const N: usize> RecCell<'t, [T; N]>
Sourcepub const fn as_array_of_cells(&self) -> &[RecCell<'t, T>; N]
pub const fn as_array_of_cells(&self) -> &[RecCell<'t, T>; N]
Views an array-valued cell as an array of element cells.
§Examples
use rec_cell::{RecCell, RecToken};
RecToken::new(|token| {
let cell = RecCell::new([1, 2]);
assert_eq!(*cell.as_array_of_cells()[0].borrow(&token), 1);
});Sourcepub const fn as_array_of_cells_mut(&mut self) -> &mut [RecCell<'t, T>; N]
pub const fn as_array_of_cells_mut(&mut self) -> &mut [RecCell<'t, T>; N]
Views an array-valued cell as a mutable array of element cells.
§Examples
use rec_cell::RecCell;
let mut cell = RecCell::new([1, 2]);
*cell.as_array_of_cells_mut()[0].get_mut() = 3;
assert_eq!(cell.into_inner(), [3, 2]);Sourcepub const fn from_array_of_cells<'a>(cells: &'a [RecCell<'t, T>; N]) -> &'a Self
pub const fn from_array_of_cells<'a>(cells: &'a [RecCell<'t, T>; N]) -> &'a Self
Reinterprets an array of element cells as a cell containing the array.
§Examples
use rec_cell::{RecCell, RecToken};
RecToken::new(|token| {
let cells = [RecCell::new(1), RecCell::new(2)];
assert_eq!(RecCell::from_array_of_cells(&cells).borrow(&token), &[1, 2]);
});Sourcepub const fn from_array_of_cells_mut<'a>(
cells: &'a mut [RecCell<'t, T>; N],
) -> &'a mut Self
pub const fn from_array_of_cells_mut<'a>( cells: &'a mut [RecCell<'t, T>; N], ) -> &'a mut Self
Reinterprets a mutable array of element cells as a mutable array-valued cell.
§Examples
use rec_cell::RecCell;
let mut cells = [RecCell::new(1), RecCell::new(2)];
RecCell::from_array_of_cells_mut(&mut cells).get_mut()[0] = 3;
assert_eq!(cells[0].get_mut(), &mut 3);Source§impl<'t, T> RecCell<'t, T>
impl<'t, T> RecCell<'t, T>
Sourcepub const fn cursor<'a>(&'a self, token: &'a RecToken<'t>) -> Cursor<'a, 't, T>
pub const fn cursor<'a>(&'a self, token: &'a RecToken<'t>) -> Cursor<'a, 't, T>
Creates a read-only cursor anchored at this cell.
§Examples
use rec_cell::{RecCell, RecToken};
RecToken::new(|token| {
let cell = RecCell::new(7);
let cursor = cell.cursor(&token);
assert_eq!(cursor.get(), &7);
let (cell, token) = cursor.into_inner();
assert_eq!(cell.borrow(token), &7);
});Sourcepub const fn cursor_mut<'a>(
&'a self,
token: &'a mut RecToken<'t>,
) -> CursorMut<'a, 't, T>
pub const fn cursor_mut<'a>( &'a self, token: &'a mut RecToken<'t>, ) -> CursorMut<'a, 't, T>
Creates a mutable cursor anchored at this cell.
§Examples
use rec_cell::{RecCell, RecToken};
RecToken::new(|mut token| {
let cell = RecCell::new(7);
let mut cursor = cell.cursor_mut(&mut token);
assert_eq!(cursor.get(), &7);
*cursor.get_mut() = 8;
assert_eq!(cursor.replace(9), 8);
assert_eq!(cursor.take(), 9);
let (cell, token) = cursor.into_inner();
assert_eq!(cell.borrow(token), &0);
});Trait Implementations§
Source§impl<'t, T> CellLike<'t> for RecCell<'t, T>
impl<'t, T> CellLike<'t> for RecCell<'t, T>
Source§type Cursor<'a> = Cursor<'a, 't, T>
where
Self: 'a,
't: 'a
type Cursor<'a> = Cursor<'a, 't, T> where Self: 'a, 't: 'a
Source§type CursorMut<'a> = CursorMut<'a, 't, T>
where
Self: 'a,
't: 'a
type CursorMut<'a> = CursorMut<'a, 't, T> where Self: 'a, 't: 'a
Source§fn as_cursor<'a>(&'a self, token: &'a RecToken<'t>) -> Cursor<'a, 't, T>
fn as_cursor<'a>(&'a self, token: &'a RecToken<'t>) -> Cursor<'a, 't, T>
token immutably.Source§fn as_cursor_mut<'a>(
&'a self,
token: &'a mut RecToken<'t>,
) -> CursorMut<'a, 't, T>
fn as_cursor_mut<'a>( &'a self, token: &'a mut RecToken<'t>, ) -> CursorMut<'a, 't, T>
token mutably.