2 个稳定版本
5.0.0 | 2020 年 12 月 23 日 |
---|---|
4.0.0 | 2020 年 9 月 27 日 |
3.0.0 |
|
2.0.0 |
|
1.0.2 |
|
#558 在 Rust 模式
114,595 每月下载量
在 96 个crate中使用 (直接使用 10)
23KB
284 行
cooked-waker
cooked_waker 提供了与 [std::task::Waker
][waker] 交互的安全 traits,并从常规、安全的 Rust 结构体创建这些 waker。它处理 RawWaker
和 RawWakerVTable
,使它们可以安全地使用。
它提供了 Wake
和 WakeRef
traits,分别对应于 std::task::Waker
上的 wake
和 wake_by_ref
方法,并为常见的引用 & 指针类型 (Arc
,Rc
,&'static
等) 提供了这些类型的实现。
此外,它提供了 IntoWaker
,可以将任何 Wake + Clone
类型转换为 Waker
。这个 trait 对于任何 Wake + Clone + Send + Sync + 'static
类型都会自动推导。
基本示例
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 示例
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);