Expand description
Snarc provides a Sendable Non-Atomically Reference-Counted smart-pointer.
§How does it work
In order to be both sendable and non-atomically reference counted, trade-offs must be made. Those trade-offs are as follows.
-
There is only one strong/owning reference and arbitrarily many weak references. By invoking the
entermethod of the strong/owning reference its value may be temporarily bound to the current thread. -
Weak references may only be created and dropped within the
entercontext of a strong/owning reference. This ensures that the required counter increments and decrements are race-free. -
Calling the
getmethod on a weak reference returns anOption<&T>, that isSome(&t)iff called from within theentercontext of a strong reference.
§What is it good for?
The use case that motivated the implementation of snarc is quite niche. It looks something like the following.
// We have an async task.
let task = async {
// This task is creating and executing subtasks.
let subtasks = FuturesUnordered::new();
// `x.method()` is returning 'static Futures that share mutable state
subtasks.push(x.method());
subtasks.push(x.method());
// Somewhere within the same task, the subtasks are executed.
subtasks.for_each(|x| async { /* ... */ });
};Because the futures returned by x.method() share mutable state, that state
must be wrapped in a RefCell. And because the futures also have a
'static lifetime, that RefCell must be wrapped by a reference counted
smart pointer.
§Alternatives
Given the problem statement above, here are the alternative solutions.
§Use &RefCell<T> after all
This isn’t really a solution to the problem statement, but maybe you can
relax your requirements? Maybe you don’t need the returned futures to have a
'static lifetime?
Advantages
- no overhead/maximally efficient
Drawbacks
taskwill be!Send- addresses a different problem
§Use Rc<RefCell<T>>
Advantages
- highly efficient, minor overhead of reference counting
Drawbacks
taskwill be!Send
§Use Arc<Mutex<T>>
Advantages
taskwill beSend- highly ergonomical
- subtasks can even be turned into tasks of their own and executed on a different thread
Drawbacks
- inefficient, due to locking overhead
§Use Snarc<RefCell<T> and SnarcRef<RefCell<T>>
Advantages
- highly efficient, minor overhead of reference counting
taskcan beSend
Drawbacks
- the ergonomics are iffy
Macros§
- snarc
- Defines three structs, each named by one parameter.
Structs§
- Erased
Narc - A unsendable
Snarc<T>whose type argument was erased. - Erased
Snarc - A
Snarc<T>whose type argument was erased.