Giter VIP home page Giter VIP logo

cooked-waker's Introduction

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

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

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();

// 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);

cooked-waker's People

Contributors

lucretiel avatar ldr709 avatar

Stargazers

 avatar  avatar hasunwoo avatar Mark Old avatar Sehz avatar Dom Williams avatar Mohammed Makhlouf (Mak) avatar Andrew Lilley Brinker avatar Bryan Woods avatar Ryan James Spencer avatar Tyr Chen avatar  avatar Martin Kröning avatar GAURAV avatar Juri Hahn avatar Sebastian Thiel avatar Josh Huber avatar Zimon Tai avatar Gonçalo Mendes Cabrita avatar Romain Leroux avatar Willi Kappler avatar

Watchers

James Cloos avatar  avatar Martin Kröning avatar  avatar

cooked-waker's Issues

Stowaway needs bumping

❯ cargo build
    Updating crates.io index
error: failed to select a version for the requirement `stowaway = "^1.1.2"`
  candidate versions found which didn't match: 2.0.0, 1.0.0, 0.1.1, ...
  location searched: crates.io index
required by package `cooked-waker v2.0.0`
    ... which is depended on by `tingle v0.1.0 (/Users/james/code/irrustible/tingle)`

Rc example

I have a single-threaded executor that does not use Arc<...>, only Rc<RefCell<...>>, to manage state. I'd like the waker to not need to use Arc. I see that there are impls for Rc in cooked-waker. Yet, the IntoWaker trait requires Send and Sync.

Could we have an example for this single-threaded use case? Thanks!

Add support for `#[derive(Wake, WakeRef)]` for enums.

It's "easy" but just kind of a pain. Don't worry about refactoring with the struct version, we'll do that after we have something that works. My preferred design is that each enum variant either have no fields, or it has a single Waker field. Specifically, I do not want to support MyEnum::variant(w1, w2).

Assertion failure when tested in release mode

When I run cargo test --release on the latest commit (14c562b1010d1aad838dfb011b4956b267ec2131), I get the following assertion failure.

   Doc-tests cooked-waker

running 2 tests
test src/lib.rs - (line 91) ... ok
test src/lib.rs - (line 20) ... FAILED

failures:

---- src/lib.rs - (line 20) stdout ----
warning: static variable `wake_ref_count` should have an upper case name
 --> src/lib.rs:25:8
  |
8 | static wake_ref_count: AtomicUsize = AtomicUsize::new(0);
  |        ^^^^^^^^^^^^^^ help: convert the identifier to upper case: `WAKE_REF_COUNT`
  |
  = note: `#[warn(non_upper_case_globals)]` on by default

warning: static variable `wake_value_count` should have an upper case name
 --> src/lib.rs:26:8
  |
9 | static wake_value_count: AtomicUsize = AtomicUsize::new(0);
  |        ^^^^^^^^^^^^^^^^ help: convert the identifier to upper case: `WAKE_VALUE_COUNT`

warning: static variable `drop_count` should have an upper case name
  --> src/lib.rs:27:8
   |
10 | static drop_count: AtomicUsize = AtomicUsize::new(0);
   |        ^^^^^^^^^^ help: convert the identifier to upper case: `DROP_COUNT`

warning: 3 warnings emitted

Test executable failed (exit code 101).

stderr:
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `4`,
 right: `1`', src/lib.rs:67:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace



failures:
    src/lib.rs - (line 20)

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.21s

Running the tests in debug mode, with cargo test, shows no errors.

$ rustc --version
rustc 1.50.0-nightly (f74583445 2020-12-18)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.