slot-cell

Crates.ioslot-cell
lib.rsslot-cell
version0.1.2
created_at2025-12-19 04:04:49.268567+00
updated_at2025-12-20 08:50:40.671955+00
descriptionSlotCell - an interior mutability container. It acts as a "Runtime-Checked Move Cell", providing owned access to data rather than references.
homepage
repositoryhttps://github.com/mcmah309/slot-cell
max_upload_size
id1994202
size56,166
Henry (mcmah309)

documentation

README

SlotCell

github crates.io docs.rs test status

SlotCell<T> provides move-based interior mutability. It acts as a "Runtime-Checked Move Cell", providing a alternative to RefCell when you need owned access to data rather than references. It is particularly useful for types that don't implement Copy or Default, where a standard Cell would be unusable.

Supports no_std.


Key Features

  • Owned Access: Unlike RefCell, which gives you a RefMut guard, SlotCell allows you to move the value out of the container entirely.
  • Memory Efficient: Depending on the alignment of T, it may be smaller than RefCell.
  • No Constraints on T: Unlike Cell<T>, your type T does not need to implement Copy, Clone, or Default.
  • Debug Tracking: In debug builds, SlotCell tracks the file and line number of the last modification. If you try to take a value that is already gone, it tells you exactly where it was taken.

Comparison with RefCell

Feature SlotCell<T> RefCell<T>
Access Pattern Move (Ownership) Borrow reference (&T / &mut T)
Overhead Occupancy Check (Full/Empty) Borrow Check (Read/Write)
Ergonomics No lifetime/guard Uses Ref/RefMut guards
Best For Small/Medium stack types Large stack types, multiple reads

Usage

Basic Workflow

use slot_cell::SlotCell;

// Create a cell
let cell = SlotCell::new(String::from("Hello"));
let cell_ref: &SlotCell<String> = &cell;

// Take the value (cell is now empty)
let mut s: String = cell_ref.take();
s.push_str(" World");

// Put it back
cell_ref.put(s);

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

Late Initialization

use slot_cell::SlotCell;

let cell = SlotCell::empty();

// ... later ...
cell.put(42);

Performance Considerations

SlotCell is optimized for small stack-allocated values. Because take() and put() move the data:

  • Fast: For types bytes (like i32, String, Vec).
  • Slower: For very large structs (e.g., arrays), where the cost of moving data exceeds the cost of RefCell's reference management. For large types, consider wrapping them in a Box before putting them in a SlotCell.

Benchmarks

Measured on a standard Criterion suite comparing SlotCell<T>::take/put vs RefCell<T>::borrow_mut.

Type Scenario RefCell (Time) SlotCell (Time) Difference
- Access Overhead 1.31 ns 586.05 ps 2.2x Faster
i32 (4-byte) Primitive Update 1.49 ns 640.77 ps 2.3x Faster
String (24-byte) Push Char 1.34 ns 5.79 ns 4.3x Slower
Large Struct (~1KB) Stack Only 2.24 ns 132.61 ns 59x Slower
Box<Large Struct> (8-byte) Heap 2.24 ns 2.23 ns Parity

Correctness and Panics

SlotCell is strictly !Sync. It ensures correctness by panicking if:

  1. You call take() on an empty cell.
  2. You call put() on a full cell.
  3. You call replace() on an empty cell.

In debug mode, these panics include the stack trace/location of the code that previously emptied or filled the slot, making logic errors easy to debug.

Commit count: 0

cargo fmt