Working version

This commit is contained in:
2026-01-31 12:25:19 +01:00
parent f468f06899
commit 51d7b6c5a8
2 changed files with 84 additions and 9 deletions
+18 -1
View File
@@ -1,2 +1,19 @@
# access-cell # access-cell
A synchronous, single-threaded Mutex&lt;T> anti-locking system A synchronous, single-threaded Mutex<T> anti-locking system
```rust
let value = Arc::new(AccessCell::new(0));
value.access({
let value = value.clone();
move |_| {
// normally this would cause a deadlock
value.access(|v| {
*v = 10;
})
}
});
assert_eq!(*value.access_ref(), 10);
```
+66 -8
View File
@@ -1,14 +1,72 @@
pub fn add(left: u64, right: u64) -> u64 { use std::{
left + right cell::{Cell, UnsafeCell},
collections::VecDeque,
sync::Mutex,
};
pub struct AccessCell<T> {
value: UnsafeCell<T>,
running: Cell<bool>,
queue: Mutex<VecDeque<Box<dyn FnOnce(&mut T)>>>,
} }
#[cfg(test)] impl<T> AccessCell<T> {
mod tests { pub fn new(value: T) -> Self {
use super::*; Self {
value: UnsafeCell::new(value),
running: Cell::new(false),
queue: Mutex::new(VecDeque::new()),
}
}
pub fn access(&self, f: impl FnOnce(&mut T) + 'static) {
// already inside → enqueue
if self.running.get() {
self.queue.lock().unwrap().push_back(Box::new(f));
return;
}
// first entrant = executor
self.running.set(true);
// call current
f(self.access_mut());
// drain queued re-entrant calls
while let Some(job) = self.queue.lock().unwrap().pop_front() {
let value = self.access_mut();
job(value);
}
self.running.set(false);
}
pub fn access_mut(&self) -> &mut T {
unsafe { &mut *self.value.get() }
}
pub fn access_ref(&self) -> &T {
unsafe { &*self.value.get() }
}
}
mod tests {
#[test] #[test]
fn it_works() { fn test_access() {
let result = add(2, 2); let value = std::sync::Arc::new(crate::AccessCell::new(0));
assert_eq!(result, 4);
value.access({
let value = value.clone();
move |_| {
// normally this would cause a deadlock
value.access(|v| {
*v = 10;
})
}
});
assert_eq!(*value.access_ref(), 10);
} }
} }