atomic_refcell
A thread-safe analogue of RefCell for Rust with runtime borrow checking
Repository Health
Technical Analysis
atomic_refcell is a small, no_std-compatible Rust crate that brings RefCell-style borrow semantics to values shared across threads. It offers runtime-checked immutable and mutable borrows backed by a single atomic reference count, making it a lighter-weight alternative to RwLock for cases where you can guarantee mutable and immutable borrows never overlap concurrently.
Because it uses just one atomic operation per borrow rather than the multiple atomics a read-write lock needs, AtomicRefCell keeps immutable borrows cheap and supports useful ergonomics like mapping references (AtomicRef::map) that a lock-based design cannot. The implementation carefully handles panics on illegal borrows so that a misuse on one thread never causes undefined behavior on others.
What You Get
- AtomicRefCell<T>, a thread-safe (Sync) cell with RefCell-like borrow semantics
- Runtime-checked borrow() / borrow_mut() plus fallible try_borrow() / try_borrow_mut() variants
- AtomicRef and AtomicRefMut guards with map() support for projecting into fields
- no_std compatibility and optional serde and portable-atomic feature flags
Common Use Cases
- Sharing mutable state across threads where borrows are known never to overlap concurrently
- Replacing RwLock in hot paths to avoid the cost of multiple atomic operations per immutable borrow
- Building Sync data structures on embedded or no_std targets via the portable-atomic feature
- Serializing and deserializing shared cell contents with the optional serde feature
Under The Hood
Architecture - The entire crate lives in a single src/lib.rs (~560 lines) that reimplements RefCell semantics from scratch around a single AtomicUsize counter inside an UnsafeCell<T>. The high bit of the counter encodes a mutable borrow (set via compare-and-swap when the count is zero) while lower bits count immutable borrows via atomic increment; conflicting access panics and mutable release resets the counter to zero, clearing any stray increments left by panicked threads. AtomicRef and AtomicRefMut RAII guards decrement/reset on drop, and both expose map() for reference projection.
Tech Stack - Pure Rust, edition 2021, MSRV 1.60, with zero required runtime dependencies. Optional dependencies are gated behind feature flags: serde (Serialize/Deserialize impls) and portable-atomic (for targets without native compare-and-swap). serde_json is a dev-dependency used only by tests.
Code Quality - The concurrency-critical logic is deliberately segmented and heavily commented to keep the unsafe core small and auditable, with #![deny(missing_docs)] enforcing documentation on the public API. Tests live in tests/basic.rs (~205 lines) and tests/async.rs, covering borrow rules, panic behavior, and async usage. The code is mature and stable, derived by adapting the standard library’s RefCell implementation.
API Design - The public surface mirrors std::cell::RefCell almost exactly (new, borrow, borrow_mut, try_borrow, try_borrow_mut), so Rust developers need no new mental model; the only additions are thread-safety and guard map(). Getting started requires no configuration, and the README concisely documents features and the borrow-invariant contract callers must uphold.