[−][src]Crate cooked_waker
cooked_waker provides safe traits for working with
std::task::Waker
and, more importantly, a set of derives for
safely converting normal, safe rust types into Waker
instances. 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
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
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(); // 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);
Traits
IntoWaker | Objects that can be converted into an |
Wake | Wakers that can wake by value. This is the primary means of waking a task. |
WakeRef | Wakers that can wake by reference. This trait is used to enable a |