Skip to main content

RecCell

Struct RecCell 

Source
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>

Source

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);
Source

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");
Source

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");
});
Source

pub fn new_cyclic_with_mut<'a, R>( uninit: &'a mut MaybeUninit<T>, token: &mut RecToken<'t>, scope: impl FnOnce(&'a Self) -> (R, T), ) -> R
where 't: 'a,

Available on crate feature 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, ());
});
Source

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);
});
Source

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);
Source

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]);
Source

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);
Source

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);
Source

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());
Source

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);
Source

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);
});
Source

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]);
});
Source

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);
});
Source

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]);
});
Source

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);
Source

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]>

Source

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);
});
Source

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]);
Source

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]);
});
Source

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>

Source

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);
});
Source

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: AsMut<U>, U: ?Sized> AsMut<U> for RecCell<'_, T>

Source§

fn as_mut(&mut self) -> &mut U

Converts this type into a mutable reference of the (usually inferred) input type.
Source§

impl<'t, T> CellLike<'t> for RecCell<'t, T>

Source§

type Cursor<'a> = Cursor<'a, 't, T> where Self: 'a, 't: 'a

The read-only cursor for this cell shape.
Source§

type CursorMut<'a> = CursorMut<'a, 't, T> where Self: 'a, 't: 'a

The mutable cursor for this cell shape.
Source§

fn as_cursor<'a>(&'a self, token: &'a RecToken<'t>) -> Cursor<'a, 't, T>

Creates a read-only cursor while borrowing token immutably.
Source§

fn as_cursor_mut<'a>( &'a self, token: &'a mut RecToken<'t>, ) -> CursorMut<'a, 't, T>

Creates a mutable cursor while borrowing token mutably.
Source§

impl<T> Debug for RecCell<'_, T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: Default> Default for RecCell<'_, T>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<T> Drop for RecCell<'_, T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<T> From<T> for RecCell<'_, T>

Source§

fn from(value: T) -> Self

Converts to this type from the input type.
Source§

impl<T: Send> Send for RecCell<'_, T>

Source§

impl<T: Send + Sync> Sync for RecCell<'_, T>

Auto Trait Implementations§

§

impl<'t, T> !Freeze for RecCell<'t, T>

§

impl<'t, T> !RefUnwindSafe for RecCell<'t, T>

§

impl<'t, T> Unpin for RecCell<'t, T>
where T: Unpin,

§

impl<'t, T> UnsafeUnpin for RecCell<'t, T>
where T: UnsafeUnpin,

§

impl<'t, T> UnwindSafe for RecCell<'t, T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<!> for T

Source§

fn from(t: !) -> T

Converts to this type from the input type.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.