diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ebf346a..6b69dee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,7 @@ jobs: if: startsWith(matrix.rust, 'nightly') run: cargo check -Z features=dev_dep - run: cargo test + - run: cargo test --features portable-atomic msrv: runs-on: ubuntu-latest @@ -82,6 +83,10 @@ jobs: env: MIRIFLAGS: -Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation RUSTFLAGS: ${{ env.RUSTFLAGS }} -Z randomize-layout + - run: cargo miri test --features portable-atomic + env: + MIRIFLAGS: -Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation + RUSTFLAGS: ${{ env.RUSTFLAGS }} -Z randomize-layout security_audit: permissions: diff --git a/Cargo.toml b/Cargo.toml index 15c2e0d..99642f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,10 @@ documentation = "https://docs.rs/waker-fn" keywords = ["async", "waker", "wake", "closure", "callback"] categories = ["concurrency"] exclude = ["/.*"] + +[features] +# Uses portable-atomic polyfill atomics on targets without them +portable-atomic = ["portable-atomic-util"] + +[dependencies] +portable-atomic-util = { version = "0.2", optional = true, default-features = false, features = ["alloc"] } diff --git a/src/lib.rs b/src/lib.rs index 6f7a813..d83344e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,11 +12,14 @@ html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png" )] +#[cfg(not(feature = "portable-atomic"))] extern crate alloc; -use alloc::sync::Arc; -use alloc::task::Wake; +#[cfg(not(feature = "portable-atomic"))] +use alloc::{sync::Arc, task::Wake}; use core::task::Waker; +#[cfg(feature = "portable-atomic")] +use portable_atomic_util::{task::Wake, Arc}; /// Converts a closure into a [`Waker`]. /// @@ -38,6 +41,7 @@ pub fn waker_fn(f: F) -> Waker { struct Helper(F); +#[cfg(not(feature = "portable-atomic"))] impl Wake for Helper { fn wake(self: Arc) { (self.0)(); @@ -47,3 +51,16 @@ impl Wake for Helper { (self.0)(); } } +// Note: Unlike std::task::Wake, all methods take `this:` instead of `self:`. +// This is because using portable_atomic_util::Arc as a receiver requires the +// unstable arbitrary_self_types feature. +#[cfg(feature = "portable-atomic")] +impl Wake for Helper { + fn wake(this: Arc) { + (this.0)(); + } + + fn wake_by_ref(this: &Arc) { + (this.0)(); + } +}