Expand description
This crate provides two new cell-like types, TakeCell and TakeOwnCell.
Both may store arbitrary non-Copy types, can be read from at most once and
provide direct unique access to the stored contents. The core API looks
roughly like this (and there’s much more inside, read on!):
impl<T> TakeCell<T> {
const fn new(v: T) -> Self { ... }
}
impl<T: ?Sized> TakeCell<T> {
fn take(&self) -> Option<&mut T> { ... }
}
impl<T> TakeOwnCell<T> {
const fn new(v: T) -> Self { ... }
fn take(&self) -> Option<T> { ... }
}Note that, like with RefCell and Mutex, the take method requires only
a shared reference. Because of the single read restriction take can
return a &mut T or T instead of RefMut<T> or MutexGuard<T>. In some
sense TakeCell can be thought as a Mutex without unlocking (or rather
with unlocking requiring unique access to the Mutex, see heal).
This crate is #![no_std] and only requires little sychronization via 8-bit
atomic.
§Usage examples
§Singletons
TakeCell is Sync (when T: Sync) and as such it may be used in
statics. This can be used to create singletons:
use takecell::TakeCell;
#[non_exhaustive]
pub struct Peripherals {
pub something: Something,
}
pub static PEREPHERALS: TakeCell<Peripherals> = TakeCell::new(Peripherals {
something: Something,
});
let peripherals: &'static mut _ = PEREPHERALS.take().unwrap();§Doing work only once
use once_cell::sync::OnceCell;
use std::sync::{Arc, Condvar, Mutex};
use takecell::TakeCell;
#[derive(Clone)]
struct Job {
// Input can be a type which requires unique access to be used (e.g.: `dyn Read`)
input: Arc<TakeCell<Input>>,
output: Arc<OnceCell<Output>>,
wait: Arc<(Mutex<bool>, Condvar)>,
}
fn execute(job: Job) -> Output {
match job.input.take() {
Some(input) => {
// Nobody has started executing the job yet, so execute it
let output = input.process();
// Write the output
job.output.set(output);
// Notify other threads that the job is done
let (lock, cvar) = &*job.wait;
let mut done = lock.lock().unwrap();
*done = true;
}
None => {
// Wait for the other thread to do the job
let (lock, cvar) = &*job.wait;
let mut done = lock.lock().unwrap();
// As long as the value inside the `Mutex<bool>` is `false`, we wait
while !*done {
done = cvar.wait(done).unwrap();
}
}
}
// Read the output
job.output.get().unwrap().clone()
}
impl Input {
fn process(&mut self) -> Output {
// ...
}
}Structs§
- Take
Cell - A cell type which value can be taken only once.
- Take
OwnCell - A cell type which value can be taken only once.