cooked-waker 5.0.0

A safe interface for creating async Wakers
Documentation
[![Travis (.com)](https://img.shields.io/travis/com/Lucretiel/cooked-waker.svg?logo=travis)](https://travis-ci.com/Lucretiel/cooked-waker/) [![GitHub stars](https://img.shields.io/github/stars/Lucretiel/cooked-waker.svg?label=stars&logo=github&logoColor=white)](https://github.com/Lucretiel/cooked-waker) [![Crates.io](https://img.shields.io/crates/d/cooked-waker.svg?logo=rust&logoColor=white&label=crates.io)](https://crates.io/crates/cooked-waker) [![docs.rs](https://docs.rs/cooked-waker/badge.svg)](https://docs.rs/cooked-waker) [![license](https://img.shields.io/github/license/Lucretiel/cooked-waker.svg)](https://crates.io/crates/cooked-waker/)

# cooked-waker

cooked_waker provides safe traits for working with [`std::task::Waker`][waker] and creating those wakers out of regular, safe Rust structs. It cooks `RawWaker` and `RawWakerVTable`, making them safe for consumption.

It provides the `Wake` and `WakeRef` traits, which correspond to the `wake` and `wake_by_ref` methods on `std::task::Waker`, and it provides implenetations of these types for the common reference & pointer types (`Arc`, `Rc`, `&'static`, etc).

Additionally, it provides `IntoWaker`, which allows converting any `Wake + Clone` type into a `Waker`. This trait is automatically derived for any `Wake + Clone + Send + Sync + 'static` type.

# Basic example

```rust
use cooked_waker::{Wake, WakeRef, IntoWaker};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::Waker;

static wake_ref_count: AtomicUsize = AtomicUsize::new(0);
static wake_value_count: AtomicUsize = AtomicUsize::new(0);
static drop_count: AtomicUsize = AtomicUsize::new(0);

// A simple Waker struct that atomically increments the relevant static
// counters.
#[derive(Debug, Clone)]
struct StaticWaker;

impl WakeRef for StaticWaker {
    fn wake_by_ref(&self) {
        wake_ref_count.fetch_add(1, Ordering::SeqCst);
    }
}

impl Wake for StaticWaker {
    fn wake(self) {
        wake_value_count.fetch_add(1, Ordering::SeqCst);
    }
}

impl Drop for StaticWaker {
    fn drop(&mut self) {
        drop_count.fetch_add(1, Ordering::SeqCst);
    }
}

assert_eq!(drop_count.load(Ordering::SeqCst), 0);

let waker = StaticWaker;
{
    let waker1: Waker = waker.into_waker();

    waker1.wake_by_ref();
    assert_eq!(wake_ref_count.load(Ordering::SeqCst), 1);

    let waker2: Waker = waker1.clone();
    waker2.wake_by_ref();
    assert_eq!(wake_ref_count.load(Ordering::SeqCst), 2);

    waker1.wake();
    assert_eq!(wake_value_count.load(Ordering::SeqCst), 1);
    assert_eq!(drop_count.load(Ordering::SeqCst), 1);
}
assert_eq!(drop_count.load(Ordering::SeqCst), 2);
```

# Arc example

```rust
use cooked_waker::{Wake, WakeRef, IntoWaker};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::task::Waker;

// A simple struct that counts the number of times it is awoken. Can't
// be awoken by value (because that would discard the counter), so we
// must instead wrap it in an Arc.
#[derive(Debug, Default)]
struct Counter {
    // We use atomic usize because we need Send + Sync and also interior
    // mutability
    count: AtomicUsize,
}

impl Counter {
    fn get(&self) -> usize {
        self.count.load(Ordering::SeqCst)
    }
}

impl WakeRef for Counter {
    fn wake_by_ref(&self) {
        let _prev = self.count.fetch_add(1, Ordering::SeqCst);
    }
}

let counter_handle = Arc::new(Counter::default());

// Create an std::task::Waker
let waker: Waker = counter_handle.clone().into_waker();

waker.wake_by_ref();
waker.wake_by_ref();

let waker2 = waker.clone();
waker2.wake_by_ref();

// Because IntoWaker wrap the pointer directly, without additional
// boxing, we can use will_wake
assert!(waker.will_wake(&waker2));

// This calls Counter::wake_by_ref because the Arc doesn't have exclusive
// ownership of the underlying Counter
waker2.wake();

assert_eq!(counter_handle.get(), 4);
```