Smart Pointers

Cell<T>

std::cell::Cell<T> is a zero-overhead single-threaded interior mutability container that enables mutating an inner value through a shared reference (&Cell<T>) by moving or copying values in and out rather than handing out references to the inner data.

Why Cell<T> Cannot Produce Dangling References

Because no safe method on &Cell<T> ever returns a reference &T or &mut T pointing inside the cell, there is never an active borrow that could be invalidated by a concurrent write on the same thread. As a result, Cell<T> needs no runtime borrow counter, has the exact same size and alignment as T (#[repr(transparent)] over UnsafeCell<T>), and can never panic at runtime.

&Cell<T> Operations (No inner &T reference ever escapes):

          set(new_val) / replace(new_val)
                 |
                 v
        +------------------+
        |     Cell<T>      |
        |   inner value T  |
        +------------------+
                 |
                 v
       get() (if T: Copy) / take() (if T: Default)

Core Cell<T> Methods by Trait Bound

Cell<T> works with any type T (including non-Copy types like String or Vec<T>), with additional convenience methods unlocked when T: Copy or T: Default:

Method Required Bound on T Signature Behavior
Cell::new(val) Any T const fn new(value: T) -> Cell<T> Creates a new Cell<T>
.set(val) Any T fn set(&self, val: T) Replaces and drops the old value
.replace(val) Any T fn replace(&self, val: T) -> T Swaps in val and returns the previous value
.swap(&other) Any T fn swap(&self, other: &Cell<T>) Swaps contents of two Cell<T> instances
.into_inner() Any T (consumes Cell) fn into_inner(self) -> T Unwraps the Cell and returns T
.get_mut() Any T (requires &mut Cell) fn get_mut(&mut self) -> &mut T Zero-cost mutable access when exclusive &mut is held
.get() T: Copy fn get(&self) -> T Returns a bitwise copy of the current value
.update(f) T: Copy fn update(&self, f: impl FnOnce(T) -> T) -> T Reads copy, applies f, writes result, and returns new value
.take() T: Default fn take(&self) -> T Moves out the current value and leaves T::default() in its place

Mutating Copy and Non-Copy Fields Through &self

use std::cell::Cell;

struct ClientSession {
    request_count: Cell<u32>,
    last_token: Cell<String>,
}

impl ClientSession {
    fn record_request(&self, new_token: String) -> String {
        // `u32` is `Copy`, so `.get()` and `.set()` work directly:
        self.request_count.set(self.request_count.get() + 1);

        // `String` is not `Copy`, but `.replace()` moves the old String out
        // and moves `new_token` in without any borrow checks:
        self.last_token.replace(new_token)
    }
}

fn main() {
    let session = ClientSession {
        request_count: Cell::new(0),
        last_token: Cell::new(String::from("init-token")),
    };

    let prev1 = session.record_request(String::from("token-alpha"));
    let prev2 = session.record_request(String::from("token-beta"));

    println!("requests:   {}", session.request_count.get());
    println!("prev1:      {}", prev1);
    println!("prev2:      {}", prev2);
    println!("current:    {}", session.last_token.take());
    println!("after take: {:?}", session.last_token.into_inner());
}
requests:   2
prev1:      init-token
prev2:      token-alpha
current:    token-beta
after take: ""

Slice Projection with Cell::from_mut and Cell::as_slice_of_cells

A unique mutable reference &mut [T] can be converted into &Cell<[T]> via Cell::from_mut, and then projected into &[Cell<T>] via .as_slice_of_cells(). This enables in-place mutation of multiple elements of a slice through shared references without index borrow conflicts:

use std::cell::Cell;

fn main() {
    let mut data = [10, 20, 30, 40];
    let cell_slice: &[Cell<i32>] = Cell::from_mut(&mut data[..]).as_slice_of_cells();

    cell_slice[0].set(cell_slice[0].get() + cell_slice[3].get());
    cell_slice[1].swap(&cell_slice[2]);

    println!("modified data: {:?}", data);
}
modified data: [50, 30, 20, 40]