From 56456a9de526cd695e88ecf09364afcd724e3849 Mon Sep 17 00:00:00 2001 From: jtnunley Date: Thu, 26 Jan 2023 08:18:01 -0800 Subject: [PATCH 1/3] m: Remove futures-lite dependency --- Cargo.toml | 2 +- src/barrier.rs | 1 - src/lib.rs | 12 ++++++++++++ src/mutex.rs | 1 - src/once_cell.rs | 32 ++++++++++++++++++++++++++------ src/rwlock.rs | 1 - src/semaphore.rs | 1 - 7 files changed, 39 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 139739d..4902514 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,12 +15,12 @@ categories = ["asynchronous", "concurrency"] exclude = ["/.*"] [dependencies] -futures-lite = "1.11.0" event-listener = "2.5.1" [dev-dependencies] async-channel = "1.5.0" fastrand = "1.4.0" +futures-lite = "1.12.0" [target.'cfg(any(target_arch = "wasm32", target_arch = "wasm64"))'.dev-dependencies] wasm-bindgen-test = "0.3" diff --git a/src/barrier.rs b/src/barrier.rs index ff803c7..e993db2 100644 --- a/src/barrier.rs +++ b/src/barrier.rs @@ -1,5 +1,4 @@ use event_listener::{Event, EventListener}; -use futures_lite::ready; use std::fmt; use std::future::Future; diff --git a/src/lib.rs b/src/lib.rs index 8d14e63..aa10d4c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,18 @@ #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] +/// Simple macro to extract the value of `Poll` or return `Pending`. +macro_rules! ready { + ($e:expr) => {{ + use ::core::task::Poll; + + match $e { + Poll::Ready(v) => v, + Poll::Pending => return Poll::Pending, + } + }}; +} + mod barrier; mod mutex; mod once_cell; diff --git a/src/mutex.rs b/src/mutex.rs index 88cc890..142dc86 100644 --- a/src/mutex.rs +++ b/src/mutex.rs @@ -18,7 +18,6 @@ use std::time::{Duration, Instant}; use std::usize; use event_listener::{Event, EventListener}; -use futures_lite::ready; /// An async mutex. /// diff --git a/src/once_cell.rs b/src/once_cell.rs index 463dc62..9b8d658 100644 --- a/src/once_cell.rs +++ b/src/once_cell.rs @@ -9,7 +9,6 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; use event_listener::{Event, EventListener}; -use futures_lite::future; /// The current state of the `OnceCell`. #[derive(Copy, Clone, PartialEq, Eq)] @@ -427,7 +426,7 @@ impl OnceCell { // Slow path: initialize the value. // The futures provided should never block, so we can use `now_or_never`. - now_or_never(self.initialize_or_wait(move || future::ready(closure()), &mut Blocking))?; + now_or_never(self.initialize_or_wait(move || async move { closure() }, &mut Blocking))?; debug_assert!(self.is_initialized()); // SAFETY: We know that the value is initialized, so it is safe to @@ -594,7 +593,7 @@ impl OnceCell { // but we do not have the ability to initialize it. // // We need to wait the initialization to complete. - future::poll_fn(|cx| { + PollFn::new(|cx| { match event_listener.take() { None => { event_listener = Some(self.active_initializers.listen()); @@ -758,7 +757,7 @@ impl Drop for OnceCell { } /// Either return the result of a future now, or panic. -fn now_or_never(f: impl Future) -> T { +fn now_or_never(mut f: impl Future) -> T { const NOOP_WAKER: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); unsafe fn wake(_: *const ()) {} @@ -768,18 +767,39 @@ fn now_or_never(f: impl Future) -> T { } unsafe fn drop(_: *const ()) {} - futures_lite::pin!(f); + // SAFETY: We don't move the future after we pin it here. + let future = unsafe { Pin::new_unchecked(&mut f) }; + let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &NOOP_WAKER)) }; // Poll the future exactly once. let mut cx = Context::from_waker(&waker); - match f.poll(&mut cx) { + match future.poll(&mut cx) { Poll::Ready(value) => value, Poll::Pending => unreachable!("future not ready"), } } +/// A future that runs a function on poll. +struct PollFn(F); + +impl) -> Poll> PollFn { + fn new(f: F) -> Self { + Self(f) + } +} + +impl Unpin for PollFn {} + +impl) -> Poll> Future for PollFn { + type Output = T; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + (self.0)(cx) + } +} + /// The strategy for polling an `event_listener::EventListener`. trait Strategy { /// Poll the event listener. diff --git a/src/rwlock.rs b/src/rwlock.rs index 3d5795b..53bc871 100644 --- a/src/rwlock.rs +++ b/src/rwlock.rs @@ -9,7 +9,6 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::task::{Context, Poll}; use event_listener::{Event, EventListener}; -use futures_lite::ready; use crate::futures::Lock; use crate::{Mutex, MutexGuard}; diff --git a/src/semaphore.rs b/src/semaphore.rs index 15482c4..4174781 100644 --- a/src/semaphore.rs +++ b/src/semaphore.rs @@ -6,7 +6,6 @@ use std::sync::Arc; use std::task::{Context, Poll}; use event_listener::{Event, EventListener}; -use futures_lite::ready; /// A counter for limiting the number of concurrent operations. #[derive(Debug)] From daeed8c39f17d2ea50e5f57d0a73bbbd5294d783 Mon Sep 17 00:00:00 2001 From: jtnunley Date: Thu, 26 Jan 2023 09:28:45 -0800 Subject: [PATCH 2/3] Bump MSRV to 1.48 --- .github/workflows/ci.yml | 2 +- Cargo.toml | 2 +- src/once_cell.rs | 62 +++++++++++++--------------------------- 3 files changed, 22 insertions(+), 44 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c945a75..a0ef02e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: matrix: # When updating this, the reminder to update the minimum supported # Rust version in Cargo.toml. - rust: ['1.43'] + rust: ['1.48'] steps: - uses: actions/checkout@v3 - name: Install Rust diff --git a/Cargo.toml b/Cargo.toml index 4902514..b9f10fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ name = "async-lock" version = "2.6.0" authors = ["Stjepan Glavina "] edition = "2018" -rust-version = "1.43" +rust-version = "1.48" description = "Async synchronization primitives" license = "Apache-2.0 OR MIT" repository = "https://github.com/smol-rs/async-lock" diff --git a/src/once_cell.rs b/src/once_cell.rs index 9b8d658..dee540e 100644 --- a/src/once_cell.rs +++ b/src/once_cell.rs @@ -426,7 +426,9 @@ impl OnceCell { // Slow path: initialize the value. // The futures provided should never block, so we can use `now_or_never`. - now_or_never(self.initialize_or_wait(move || async move { closure() }, &mut Blocking))?; + now_or_never( + self.initialize_or_wait(move || std::future::ready(closure()), &mut Blocking), + )?; debug_assert!(self.is_initialized()); // SAFETY: We know that the value is initialized, so it is safe to @@ -593,22 +595,13 @@ impl OnceCell { // but we do not have the ability to initialize it. // // We need to wait the initialization to complete. - PollFn::new(|cx| { - match event_listener.take() { - None => { - event_listener = Some(self.active_initializers.listen()); - } - Some(evl) => { - if let Err(evl) = strategy.poll(evl, cx) { - event_listener = Some(evl); - return Poll::Pending; - } - } + match event_listener.take() { + None => { + event_listener = Some(self.active_initializers.listen()); } - Poll::Ready(()) - }) - .await; + Some(evl) => strategy.poll(evl).await, + } } State::Uninitialized => { // Try to move the cell into the initializing state. @@ -781,38 +774,24 @@ fn now_or_never(mut f: impl Future) -> T { } } -/// A future that runs a function on poll. -struct PollFn(F); - -impl) -> Poll> PollFn { - fn new(f: F) -> Self { - Self(f) - } -} - -impl Unpin for PollFn {} - -impl) -> Poll> Future for PollFn { - type Output = T; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - (self.0)(cx) - } -} - /// The strategy for polling an `event_listener::EventListener`. trait Strategy { + /// The future that can be polled to wait on the listener. + type Fut: Future; + /// Poll the event listener. - fn poll(&mut self, evl: EventListener, ctx: &mut Context<'_>) -> Result<(), EventListener>; + fn poll(&mut self, evl: EventListener) -> Self::Fut; } /// The strategy for blocking the current thread on an `EventListener`. struct Blocking; impl Strategy for Blocking { - fn poll(&mut self, evl: EventListener, _: &mut Context<'_>) -> Result<(), EventListener> { + type Fut = std::future::Ready<()>; + + fn poll(&mut self, evl: EventListener) -> Self::Fut { evl.wait(); - Ok(()) + std::future::ready(()) } } @@ -820,10 +799,9 @@ impl Strategy for Blocking { struct NonBlocking; impl Strategy for NonBlocking { - fn poll(&mut self, mut evl: EventListener, ctx: &mut Context<'_>) -> Result<(), EventListener> { - match Pin::new(&mut evl).poll(ctx) { - Poll::Pending => Err(evl), - Poll::Ready(()) => Ok(()), - } + type Fut = EventListener; + + fn poll(&mut self, evl: EventListener) -> Self::Fut { + evl } } From df3b7fd4014eaecfadce2a9bc2baeb2e75256b4a Mon Sep 17 00:00:00 2001 From: John Nunley Date: Thu, 26 Jan 2023 13:59:31 -0800 Subject: [PATCH 3/3] Update src/lib.rs Co-authored-by: Zeeshan Ali Khan --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index aa10d4c..6a4b3a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,8 @@ #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] /// Simple macro to extract the value of `Poll` or return `Pending`. +/// +/// TODO: Drop in favor of `core::task::ready`, once MSRV is bumped to 1.64. macro_rules! ready { ($e:expr) => {{ use ::core::task::Poll;