SlotCell

Struct SlotCell 

Source
pub struct SlotCell<T> { /* private fields */ }
Expand description

A cell type that enforces borrowing semantics (take/put) for interior mutability.

SlotCell<T> wraps a value that can be temporarily “taken out” and later “put back”. This is useful for scenarios where you need to move a value out of a structure temporarily, perform operations on it, and then return it. In practice SlotCell fills the same role as RefCell and acts more like a “lockless mutex”, while:

  • Since backed by a simple Cell
    • Potentially more memory efficient depending on alignment
    • Faster for small stack values (1 register, <= 8 bytes)
    • Comparable for medium stack values (2 - 3 registers, <= 24 bytes)
    • Slower for large stack values (Consider RefCell or moving data to heap if performance is the main concern)
  • allowing owned access.

Unlike Cell<T> or Cell<Option<T>>:

  • T does not need to implement Copy/Clone/Default, or a separate T needed, to take the value out.
  • Implements Debug, PartialEq, Eq, PartialOrd, Ord, Hash, and Default if T does.
  • Does not implement Clone or Copy, or require T to be Clone or Copy for certain operations.
  • Enforces a correct usage patterns that mimics “borrow semantics” with a runtime check.

Unlike RefCell<T>:

  • No borrow counting is used
  • Owned values rather references are returned
  • No multiple read references

High level

  • Owned values are used over guards with references/lifetimes. Thus, it is up to the programmer to follow semantics around taking and returning values or it will panic otherwise.
  • A value can only be taken once (until put back)
  • A value can only be put back when the slot is empty
  • A value can only be replaced when not already empty

In debug builds, SlotCell tracks the location of the last modification, providing helpful panic messages when usage rules are violated.

§Examples


let cell = SlotCell::new(42);
let value = cell.take();
assert_eq!(value, 42);

// Put the value back
cell.put(100);

// Take it again
let value = cell.take();
assert_eq!(value, 100);

§Panics

This type will panic if usage rules are violated (taking when empty, putting when full, etc.). In debug builds, panic messages include the location of the last modification.

Implementations§

Source§

impl<T> SlotCell<T>

Source

pub fn new(val: T) -> Self

Creates a new SlotCell containing the given value.

§Examples

let cell = SlotCell::new(42);
assert!(!cell.is_empty());
Source

pub fn empty() -> Self

Creates a new SlotCell that starts empty (without a value).

This is useful for late initialization patterns where the value will be provided later via put().

§Examples

let cell: SlotCell<i32> = SlotCell::empty();
assert!(cell.is_empty());

cell.put(42);
assert!(!cell.is_empty());
Source

pub fn take(&self) -> T

Takes the value out of the cell, leaving it empty.

After calling this method, the cell will be empty until put() is called.

§Panics

Panics if the slot is already empty. In debug builds, the panic message includes the location of the last modification.

§Examples

let cell = SlotCell::new(42);
let value = cell.take();
assert_eq!(value, 42);
Source

pub fn is_empty(&self) -> bool

Checks whether the slot is currently empty.

Returns true if the cell currently empty, false if it’s filled.

§Examples

let cell = SlotCell::new(42);
assert!(!cell.is_empty());  // Has value, not taken

let _value = cell.take();
assert!(cell.is_empty());   // Now empty/taken
Source

pub fn is_filled(&self) -> bool

Checks whether the slot is currently empty.

Returns true if the cell currently contains a value, false if it’s empty.

§Examples

let cell = SlotCell::new(42);
assert!(cell.is_filled());  // Has value, not taken

let _value = cell.take();
assert!(!cell.is_filled());   // Now empty/taken
Source

pub fn put(&self, val: T)

Puts a value into the cell, filling an empty slot.

This is used to return a value that was previously removed via take(), or to initialize a cell created with empty().

§Panics

Panics if the slot is already filled. SlotCell enforces that a value must be taken before a new one can be put back. In debug builds, the panic message includes the location of the last modification.

§Examples

let cell = SlotCell::empty();
cell.put(42); // Initialize empty slot

let _ = cell.take();
cell.put(100); // Put back after taking
Source

pub fn replace(&self, val: T) -> T

Replaces the current value in the cell with a new one.

Unlike put(), this method requires the cell to currently contain a value. It is used to update the contents without changing the “filled” state of the slot.

§Panics

Panics if the slot is already empty. To fill an empty cell, use put() instead. In debug builds, the panic message includes the location of the last modification.

§Examples

let cell = SlotCell::new(42);
cell.replace(100);

assert_eq!(cell.take(), 100);
Source

pub fn swap(&self, other: &Self)

Swaps the values between two full SlotCells.

This efficiently exchanges the contents of self and other without requiring an intermediate take() or put() call.

§Panics

Panics if either self or other is currently empty. In debug builds, the panic message includes the location of the last modification for the empty cell.

§Examples

let cell_a = SlotCell::new(1);
let cell_b = SlotCell::new(2);

cell_a.swap(&cell_b);

assert_eq!(cell_a.take(), 2);
assert_eq!(cell_b.take(), 1);
Source

pub fn with<R>(&self, f: impl FnOnce(&mut T) -> R) -> R

Executes a closure with a mutable reference to the value inside the cell.

This method provides a way to modify the contents of the SlotCell or perform operations on it without needing to manually call take() and put().

Because SlotCell works by moving values, this method internally takes the value out of the cell, passes it to your closure, and automatically puts it back once the closure returns.

§Panics

Panics if the cell is currently empty or if already filled when attempting to return the value. In debug builds, the panic message includes the location of the last modification.

§Examples

let cell = SlotCell::new(String::from("Hello"));

cell.with(|s| {
    s.push_str(", World!");
});

assert_eq!(cell.into_inner(), "Hello, World!");

It can also return a value from the closure:

let cell = SlotCell::new(10);
let is_even = cell.with(|x| *x % 2 == 0);
assert!(is_even);
Source

pub fn update(&self, f: impl FnOnce(T) -> T)

Updates the value inside the cell by applying a transformation function.

This method takes ownership of the value, passes it to the closure, and puts the result back into the cell.

Unlike with, which provides a mutable reference, update allows you to consume the value and return a new one of the same type.

§Panics

Panics if the cell is currently empty or if already filled when attempting to return the value. In debug builds, the panic message includes the location of the last modification.

§Examples

let cell = SlotCell::new(5);

// Multiply the value by 2
cell.update(|v| v * 2);

assert_eq!(cell.take(), 10);

It can also be used to swap out owned data like a String or Vec:

let cell = SlotCell::new(vec![1, 2, 3]);

cell.update(|mut v| {
    v.push(4);
    v
});

assert_eq!(cell.into_inner().len(), 4);
Source

pub fn into_inner(self) -> T

Unwraps the value, consuming the cell.

§Panics

Panics if self is empty. In debug builds, the panic message includes the location of the last modification for the empty cell.

§Examples

let c = SlotCell::new(5);
let five = c.into_inner();

assert_eq!(five, 5);

Trait Implementations§

Source§

impl<T> Debug for SlotCell<T>
where T: Debug,

Source§

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

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

impl<T> Default for SlotCell<T>

Source§

fn default() -> Self

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

impl<T> Drop for SlotCell<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T> From<Option<T>> for SlotCell<T>

Source§

fn from(value: Option<T>) -> Self

Converts to this type from the input type.
Source§

impl<T> From<SlotCell<T>> for Option<T>

Source§

fn from(value: SlotCell<T>) -> Self

Converts to this type from the input type.
Source§

impl<T> From<T> for SlotCell<T>

Source§

fn from(value: T) -> Self

Converts to this type from the input type.
Source§

impl<T> Hash for SlotCell<T>
where T: Hash,

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<T> Ord for SlotCell<T>
where T: Ord,

Source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl<T> PartialEq for SlotCell<T>
where T: PartialEq,

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T> PartialOrd for SlotCell<T>
where T: PartialOrd,

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl<T> Eq for SlotCell<T>
where T: Eq,

Auto Trait Implementations§

§

impl<T> !Freeze for SlotCell<T>

§

impl<T> !RefUnwindSafe for SlotCell<T>

§

impl<T> Send for SlotCell<T>
where T: Send,

§

impl<T> !Sync for SlotCell<T>

§

impl<T> Unpin for SlotCell<T>
where T: Unpin,

§

impl<T> UnwindSafe for SlotCell<T>
where T: UnwindSafe,

Blanket Implementations§

§

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

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

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

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

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

§

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

Mutably borrows from an owned value. Read more
§

impl<T> From<!> for T

§

fn from(t: !) -> T

Converts to this type from the input type.
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

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

§

fn into(self) -> U

Calls U::from(self).

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

§

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

§

type Error = Infallible

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

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

Performs the conversion.
§

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

§

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

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

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

Performs the conversion.