Documented
This commit is contained in:
+26
@@ -1,9 +1,20 @@
|
||||
//! A cell that allows mutable access with re-entrancy support.
|
||||
//!
|
||||
//! When you call [`access`](AccessCell::access) with a closure that itself calls `access`
|
||||
//! on the same cell, those nested calls are queued and run after the current closure
|
||||
//! finishes, avoiding deadlock.
|
||||
|
||||
use std::{
|
||||
cell::{Cell, UnsafeCell},
|
||||
collections::VecDeque,
|
||||
sync::Mutex,
|
||||
};
|
||||
|
||||
/// A cell holding a value of type `T` with re-entrant mutable access.
|
||||
///
|
||||
/// The first caller of [`access`](AccessCell::access) runs immediately; any further
|
||||
/// calls to `access` from within that closure (or its queue) are enqueued and
|
||||
/// executed in order after the current work completes.
|
||||
pub struct AccessCell<T> {
|
||||
value: UnsafeCell<T>,
|
||||
running: Cell<bool>,
|
||||
@@ -11,6 +22,7 @@ pub struct AccessCell<T> {
|
||||
}
|
||||
|
||||
impl<T> AccessCell<T> {
|
||||
/// Creates a new `AccessCell` wrapping `value`.
|
||||
pub fn new(value: T) -> Self {
|
||||
Self {
|
||||
value: UnsafeCell::new(value),
|
||||
@@ -19,6 +31,11 @@ impl<T> AccessCell<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs `f` with exclusive mutable access to the inner value.
|
||||
///
|
||||
/// If called while another `access` closure is running (re-entrant call),
|
||||
/// `f` is queued and run after the current closure and any other queued
|
||||
/// closures finish.
|
||||
pub fn access(&self, f: impl FnOnce(&mut T) + 'static) {
|
||||
// already inside → enqueue
|
||||
if self.running.get() {
|
||||
@@ -42,10 +59,19 @@ impl<T> AccessCell<T> {
|
||||
self.running.set(false);
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the inner value.
|
||||
///
|
||||
/// # Safety
|
||||
/// Only call this while you are inside an `access` closure (or while draining
|
||||
/// the queue). Otherwise you may create aliasing mutable references.
|
||||
pub fn access_mut(&self) -> &mut T {
|
||||
unsafe { &mut *self.value.get() }
|
||||
}
|
||||
|
||||
/// Returns an immutable reference to the inner value.
|
||||
///
|
||||
/// Safe to call at any time; no closure is running when you use this for
|
||||
/// read-only access.
|
||||
pub fn access_ref(&self) -> &T {
|
||||
unsafe { &*self.value.get() }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user