# `Poison<T>`
###### tags: `Kitchen Sync`
Use cases:
- `mutex.lock().poison_guard().unwrap()`
- `mutex.lock().poison_guard().unwrap_or_else(|p| p.unpoison(|v| { .. }))`
- `mutex.lock().poison_guard().or_else(|p| p.try_unpoison(|v| Ok(())))`
- `ONCE.get_or_init(|| Poison::catch_unwind(|| { .. }))`
- `ONCE.get_or_init(|| Poison::try_catch_unwind(|guard| Ok(v)))`
- `let p = file.poison_gard()?`
The behavior of synchronization primitives with respect to poisoning is to _do the minimum necessary to uphold their contract_. For `Mutex<T>`, the contract is that only a single thread may hold the lock at a time. For `Once`, the contract is that only a single closure passed to `call_once` will ever get the chance to execute.
## Replacing `sync::Mutex<T>` with `lock::Mutex<Poison<T>>`
With:
```rust
// sync::Mutex<T>
let g = mutex.lock().unwrap();
```
it's not clear what exactly could go wrong. Is the problem that we couldn't acquire the lock?
Instead, we can write:
```rust
// lock::Mutex<Poison<T>>
let g = mutex.lock().poison_guard().unwrap();
```
which makes it more obvious that what we're asserting on is poisoning. It's unrelated to the lock itself.
If we wanted to use `Mutex<()>`, instead of:
```rust
// sync::Mutex<()>
mutex.lock().unwrap()
```
we can write:
```rust
// lock::Mutex<Poison> (we could consider `unwrap` methods directly on `Poison<()>` and implement `Try` for it?)
mutex.lock().poison_guard().unwrap()
```
If we don't care, we simply write:
```rust
// lock::Mutex<T>
let g = mutex.lock();
```
and panics that unwind through the lock's guard will become tainted. Without using `Poison<T>` there's no recovering from this.
## Replacing `sync::Once` with `lazy::Once<Poison<()>>`
The `Once` type is a nifty little synchronization primitive that lets you call a closure exactly once. It also implements poisoning. Instead of:
```rust
// sync::Once
ONCE.call_once(|| { .. })
```
we can write:
```rust
// lazy::Once<Poison>
ONCE.get_or_init(|| Poison::catch_unwind(|| { .. })).poison_guard().unwrap()
```
We could implement something specifically for `lazy::Once<Poison>`:
```rust
// lazy::Once<()>
ONCE.call_once(|| { .. });
// lazy::Once<Poison>
ONCE.call_once(|| { .. }).poison_guard().unwrap()
```
# Refactoring `std::sync` (stage 1)
Create new top-level modules:
- `std::arc` containing `Arc<T>`.
- `std::atomic` containing `Atomic*` (future: consider an `Atomic<T>`).
- `std::lock`:
- containing a new non-poisoning `Mutex<T>`. Reimplement `sync::Mutex<T>` in terms of `lock::Mutex<Poison<T>>`. Allow converting a `sync::MutexGuard<'a, T>` into a `lock::MutexGuard<'a, Poison<T>>`.
- containing a new non-poisoning `RwLock<T>`. Reimplement `sync::RwLock<T>` in terms of `lock::RwLock<Poison<T>>`. Allow converting `sync::RwGuard<'a, T>`s into `lock::RwGuard<'a, Poison<T>>`s.
Refactor `panic`:
- Introduce a `Poison<T = ()>` type. Serving the use-cases of:
- Observing and propagating panics and other early returns
- Specifying consistent behavior on panics and poisoning for locks and other synchronization primitives
- Deprecate `UnwindSafe`, `RefUnwindSafe`, and `AssertUnwindSafe`.
- Remove the `UnwindSafe` bound from `panic::catch_unwind`.
We can implement this plan then issue a crater run to see how much breakage we see just in libraries in the ecosystem.
# Refactoring `std::sync` (stage 2)
Deprecating `sync`:
- Deprecate `Once` in favor of the `lazy` API.
- Deprecate `sync` entirely.
Refactor `lazy`:
- Move `OnceCell` to `cell`.
- Rename `Lazy` to `LazyCell` and move to `cell`.
- Rename `SyncOnceCell` to `Once`.
- Rename `SyncLazy` to `Lazy`.
# Refactoring `std::sync` (stage 3)
- `std::channel` containing some new `mpmc` API.