twinsies
Twinsies is a special shared pointer, similar to an Arc
, where two specific objects (called [Joint
]) share joint ownership of the underlying object. The key difference compared to an Arc
is that the underlying object is dropped when either of the [Joint
] objects go out of scope.
Because a single [Joint
] cannot, by itself, keep the shared object alive, it cannot be dereferenced directly like an Arc
. Instead, it must be locked with .lock()
. While locked, the object is guaranteed to stay alive as long as the [JointLock
] is alive. If the a [Joint
] is dropped while its partner is locked, the object stays alive, but it dropped immediately as soon as the other [Joint
] is no longer locked.
Twinsies is intended to be used for things like unbuffered channels, join handles, and async Waker
- cases where some piece of shared state should only be preserved as long as both halves are still interested in it.
Example
use twinsies::Joint;
use std::cell::Cell;
let (first, second) = Joint::new(Cell::new(0));
assert_eq!(first.lock().unwrap().get(), 0);
first.lock().unwrap().set(10);
assert_eq!(second.lock().unwrap().get(), 10);
drop(second);
// Once `second` is dropped, the shared value is gone
assert!(first.lock().is_none())
Locks preserve liveness
use twinsies::Joint;
use std::cell::Cell;
let (first, second) = Joint::new(Cell::new(0));
let lock = first.lock().unwrap();
lock.set(10);
assert_eq!(second.lock().unwrap().get(), 10);
second.lock().unwrap().set(20);
assert_eq!(lock.get(), 20);
drop(second);
assert_eq!(lock.get(), 20);
lock.set(30);
assert_eq!(lock.get(), 30);
// As soon as the lock is dropped, the shared value is gone, since `second`
// was dropped earlier
drop(lock);
assert!(first.lock().is_none());