#waker #wake #task #async #safe #pointers #traits

cooked-waker

创建异步 Waker 的安全接口

2 个稳定版本

5.0.0 2020 年 12 月 23 日
4.0.0 2020 年 9 月 27 日
3.0.0 2020 年 8 月 12 日
2.0.0 2020 年 4 月 7 日
1.0.2 2020 年 2 月 11 日

#558Rust 模式

Download history 22911/week @ 2024-03-25 28812/week @ 2024-04-01 22264/week @ 2024-04-08 21245/week @ 2024-04-15 21075/week @ 2024-04-22 16052/week @ 2024-04-29 20195/week @ 2024-05-06 25890/week @ 2024-05-13 33463/week @ 2024-05-20 27163/week @ 2024-05-27 19417/week @ 2024-06-03 32046/week @ 2024-06-10 26606/week @ 2024-06-17 18451/week @ 2024-06-24 30555/week @ 2024-07-01 34008/week @ 2024-07-08

114,595 每月下载量
96 个crate中使用 (直接使用 10)

MPL-2.0 许可证

23KB
284

Travis (.com) GitHub stars Crates.io docs.rs license

cooked-waker

cooked_waker 提供了与 [std::task::Waker][waker] 交互的安全 traits,并从常规、安全的 Rust 结构体创建这些 waker。它处理 RawWakerRawWakerVTable,使它们可以安全地使用。

它提供了 WakeWakeRef traits,分别对应于 std::task::Waker 上的 wakewake_by_ref 方法,并为常见的引用 & 指针类型 (ArcRc&'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);

无运行时依赖