The shared_cell crate is my newest project, in trying to discover an API for Cell that doesn't rely so heavily on
Clone. My original attempt at making a similar API, requires a macro polyfill for const expressions, and that crate is called pure_cell, originally trying to be an alternative in the same space as ghost-cell (not my crate). What I'm trying to accomplish now is a bit different, though - to be able to have multiple asynchronous tasks running together on the same thread, and sharing data. This isn't a new problem-space for me, and I had solved the "inverse" of the problem with 100% safe code in pasts, by separating the data mutation into synchronous functions that are called upon receiving asynchronous notifications. But, shared_cell allows mutating the data from within (a synchronous context within) the asynchronous context, which makes some new things possible. It does require one line of unsafe, which I believe to have proven the soundness of to the best of my ability.
Ok, so how does it work? The API is inspired by
LocalKey::with() in the standard library, with the additional constraint that the closure is
Send + Sync (bounds which are crucial to proving the API's safety). Except, instead of getting a shared reference in the closure, you get a unique (
&mut) reference, the lifetime of which can't escape the closure. So, now by having a shared reference on multiple tasks, you can mutably modify the data without copying it from each task, and without "locking" / runtime-borrow-checking an
Rc<RefCell<T>> or similar (which would be extra susceptible to deadlocks).
One thing this crate enables is "Concurrent Actors". An actor that can process multiple requests at the same time, each modifying the actor's owned data without locking, using the
shared_cell::TaskGroup API very loosely inspired by
tokio::task::LocalSet, except lower-level and more flexible (doesn't require
'static lifetime, and not tied to a specific async runtime). The example in the shared_cell crate
TaskGroup documentation only has one possible command to send to the actor, but it can be switched out for an enum.
What do you think?