Crate shared_cell
source ·Expand description
Interior mutability between concurrent tasks on the same thread
This is essentially an alternative to RefCell
without runtime borrow checking. Instead of using borrow guards, uses a
closure API inspired by LocalKey::with()
for greater guarantees in the
asynchronous context (prevents holding onto the mutable reference over an
.await
point that yields to other tasks that have access to the Cell
).
How It Works / Why It’s Safe
A Cell
makes it possible to have multiple references data with interior
mutability. Being !Sync
, it is impossible to call methods on Cell
from another thread, preventing data races.
The lifetime of the mutable reference is bound by the closure’s scope,
making it impossible to drop()
the interior data while borrowed. Since
Cell
doesn’t let you get an immutable reference to the interior data,
not having any existing immutable references is guaranteed, making it safe
to construct a mutable reference to pass into the closure.
Taking advantage of the fact that Cell
is !Sync
, by requiring Sync
in the closure provided to CellExt::with()
, it is impossible to create a
second mutable reference to the data through a reëntrant borrow.
Reëntrant Borrow Prevention Example
use core::cell::Cell;
use shared_cell::CellExt;
struct Context {
stuff: u32,
}
fn main() {
let cell = Cell::new(Context { stuff: 42 });
cell.with(|context| {
println!("Before: {}", context.stuff);
context.stuff += 1;
println!("After: {}", context.stuff);
// Will not compile
/* cell.with(|context| {
context.stuff += 1;
}); */
});
}
Structs
- A set of tasks that run together on the same thread, with shared data.
Traits
- Cell extension trait for thread-local-inspired API