From d9144a8a41cbbf669780a535bf3ad758244893c8 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Tue, 19 Dec 2023 16:56:22 -0800 Subject: [PATCH] feat: Create Listener trait This commit creates the Listener trait and moves most of EventListener's functionality to that trait. Signed-off-by: John Nunley --- benches/bench.rs | 2 +- examples/mutex.rs | 2 +- src/lib.rs | 184 +++++++++++++++++++++++++++------------------- 3 files changed, 110 insertions(+), 78 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index b9b136d..7541b0e 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,7 +1,7 @@ use std::iter; use criterion::{criterion_group, criterion_main, Criterion}; -use event_listener::Event; +use event_listener::{prelude::*, Event}; const COUNT: usize = 8000; diff --git a/examples/mutex.rs b/examples/mutex.rs index bde5ccc..0f2b870 100644 --- a/examples/mutex.rs +++ b/examples/mutex.rs @@ -13,7 +13,7 @@ mod example { use std::thread; use std::time::{Duration, Instant}; - use event_listener::Event; + use event_listener::{Event, Listener}; /// A simple mutex. struct Mutex { diff --git a/src/lib.rs b/src/lib.rs index 3c2e362..26f35db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,7 @@ //! use std::thread; //! use std::time::Duration; //! use std::usize; -//! use event_listener::Event; +//! use event_listener::{Event, prelude::*}; //! //! let flag = Arc::new(AtomicBool::new(false)); //! let event = Arc::new(Event::new()); @@ -108,7 +108,7 @@ pub use notify::{IntoNotification, Notification}; /// Useful traits for notifications. pub mod prelude { - pub use crate::{IntoNotification, Notification}; + pub use crate::{IntoNotification, Listener, Notification}; } /// Inner state of [`Event`]. @@ -213,7 +213,7 @@ impl Event { /// # Examples /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::::with_tag(); /// ``` @@ -230,7 +230,7 @@ impl Event { /// # Examples /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::new(); /// let listener = event.listen(); @@ -254,7 +254,7 @@ impl Event { /// # Examples /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::new(); /// let listener = event.listen(); @@ -283,7 +283,7 @@ impl Event { let inner = ManuallyDrop::new(unsafe { Arc::from_raw(self.inner()) }); // Allocate the listener on the heap and insert it. - let mut listener = Box::pin(Listener { + let mut listener = Box::pin(InnerListener { event: Arc::clone(&inner), listener: None, }); @@ -322,7 +322,7 @@ impl Event { /// Use the default notification strategy: /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::new(); /// @@ -539,7 +539,7 @@ impl Event<()> { /// # Examples /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::new(); /// ``` @@ -576,7 +576,7 @@ impl Event<()> { /// # Examples /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// use std::sync::atomic::{self, Ordering}; /// /// let event = Event::new(); @@ -628,7 +628,7 @@ impl Event<()> { /// # Examples /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::new(); /// @@ -678,7 +678,7 @@ impl Event<()> { /// # Examples /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// use std::sync::atomic::{self, Ordering}; /// /// let event = Event::new(); @@ -720,47 +720,17 @@ impl Drop for Event { } } -/// A guard waiting for a notification from an [`Event`]. -/// -/// There are two ways for a listener to wait for a notification: -/// -/// 1. In an asynchronous manner using `.await`. -/// 2. In a blocking manner by calling [`EventListener::wait()`] on it. +/// A handle that is listening to an [`Event`]. /// -/// If a notified listener is dropped without receiving a notification, dropping will notify -/// another active listener. Whether one *additional* listener will be notified depends on what -/// kind of notification was delivered. -/// -/// The listener is not registered into the linked list inside of the [`Event`] by default if -/// it is created via the `new()` method. It needs to be pinned first before being inserted -/// using the `listen()` method. After the listener has begun `listen`ing, the user can -/// `await` it like a future or call `wait()` to block the current thread until it is notified. -/// -/// This structure allocates the listener on the heap. -pub struct EventListener { - listener: Pin>>>>, -} - -unsafe impl Send for EventListener {} -unsafe impl Sync for EventListener {} - -impl core::panic::UnwindSafe for EventListener {} -impl core::panic::RefUnwindSafe for EventListener {} -impl Unpin for EventListener {} - -impl fmt::Debug for EventListener { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("EventListener").finish_non_exhaustive() - } -} - -impl EventListener { +/// This trait represents a type waiting for a notification from an [`Event`]. See the +/// [`EventListener`] type for more documentation on this trait's usage. +pub trait Listener: Future + __private::Sealed { /// Blocks until a notification is received. /// /// # Examples /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::new(); /// let mut listener = event.listen(); @@ -772,9 +742,7 @@ impl EventListener { /// listener.wait(); /// ``` #[cfg(all(feature = "std", not(target_family = "wasm")))] - pub fn wait(mut self) -> T { - self.listener.as_mut().wait_internal(None).unwrap() - } + fn wait(self) -> T; /// Blocks until a notification is received or a timeout is reached. /// @@ -784,7 +752,7 @@ impl EventListener { /// /// ``` /// use std::time::Duration; - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::new(); /// let mut listener = event.listen(); @@ -793,11 +761,7 @@ impl EventListener { /// assert!(listener.wait_timeout(Duration::from_secs(1)).is_none()); /// ``` #[cfg(all(feature = "std", not(target_family = "wasm")))] - pub fn wait_timeout(mut self, timeout: Duration) -> Option { - self.listener - .as_mut() - .wait_internal(Instant::now().checked_add(timeout)) - } + fn wait_timeout(self, timeout: Duration) -> Option; /// Blocks until a notification is received or a deadline is reached. /// @@ -807,7 +771,7 @@ impl EventListener { /// /// ``` /// use std::time::{Duration, Instant}; - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::new(); /// let mut listener = event.listen(); @@ -816,9 +780,7 @@ impl EventListener { /// assert!(listener.wait_deadline(Instant::now() + Duration::from_secs(1)).is_none()); /// ``` #[cfg(all(feature = "std", not(target_family = "wasm")))] - pub fn wait_deadline(mut self, deadline: Instant) -> Option { - self.listener.as_mut().wait_internal(Some(deadline)) - } + fn wait_deadline(self, deadline: Instant) -> Option; /// Drops this listener and discards its notification (if any) without notifying another /// active listener. @@ -826,9 +788,9 @@ impl EventListener { /// Returns `true` if a notification was discarded. /// /// # Examples - /// + /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::new(); /// let mut listener1 = event.listen(); @@ -839,33 +801,28 @@ impl EventListener { /// assert!(listener1.discard()); /// assert!(!listener2.discard()); /// ``` - pub fn discard(mut self) -> bool { - self.listener.as_mut().discard() - } + fn discard(self) -> bool; /// Returns `true` if this listener listens to the given `Event`. /// /// # Examples /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::new(); /// let listener = event.listen(); /// /// assert!(listener.listens_to(&event)); /// ``` - #[inline] - pub fn listens_to(&self, event: &Event) -> bool { - ptr::eq::>(&*self.listener.event, event.inner.load(Ordering::Acquire)) - } + fn listens_to(&self, event: &Event) -> bool; /// Returns `true` if both listeners listen to the same `Event`. /// /// # Examples /// /// ``` - /// use event_listener::Event; + /// use event_listener::{Event, prelude::*}; /// /// let event = Event::new(); /// let listener1 = event.listen(); @@ -873,7 +830,74 @@ impl EventListener { /// /// assert!(listener1.same_event(&listener2)); /// ``` - pub fn same_event(&self, other: &EventListener) -> bool { + fn same_event(&self, other: &Self) -> bool; +} + +/// A guard waiting for a notification from an [`Event`]. +/// +/// There are two ways for a listener to wait for a notification: +/// +/// 1. In an asynchronous manner using `.await`. +/// 2. In a blocking manner by calling [`EventListener::wait()`] on it. +/// +/// If a notified listener is dropped without receiving a notification, dropping will notify +/// another active listener. Whether one *additional* listener will be notified depends on what +/// kind of notification was delivered. +/// +/// See the [`Listener`] trait for the functionality exposed by this type. +/// +/// The listener is not registered into the linked list inside of the [`Event`] by default if +/// it is created via the `new()` method. It needs to be pinned first before being inserted +/// using the `listen()` method. After the listener has begun `listen`ing, the user can +/// `await` it like a future or call `wait()` to block the current thread until it is notified. +/// +/// This structure allocates the listener on the heap. +pub struct EventListener { + listener: Pin>>>>, +} + +unsafe impl Send for EventListener {} +unsafe impl Sync for EventListener {} + +impl core::panic::UnwindSafe for EventListener {} +impl core::panic::RefUnwindSafe for EventListener {} +impl Unpin for EventListener {} + +impl fmt::Debug for EventListener { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EventListener").finish_non_exhaustive() + } +} + +impl Listener for EventListener { + #[cfg(all(feature = "std", not(target_family = "wasm")))] + fn wait(mut self) -> T { + self.listener.as_mut().wait_internal(None).unwrap() + } + + #[cfg(all(feature = "std", not(target_family = "wasm")))] + fn wait_timeout(mut self, timeout: Duration) -> Option { + self.listener + .as_mut() + .wait_internal(Instant::now().checked_add(timeout)) + } + + #[cfg(all(feature = "std", not(target_family = "wasm")))] + fn wait_deadline(mut self, deadline: Instant) -> Option { + self.listener.as_mut().wait_internal(Some(deadline)) + } + + fn discard(mut self) -> bool { + self.listener.as_mut().discard() + } + + #[inline] + fn listens_to(&self, event: &Event) -> bool { + ptr::eq::>(&*self.listener.event, event.inner.load(Ordering::Acquire)) + } + + #[inline] + fn same_event(&self, other: &EventListener) -> bool { ptr::eq::>(&*self.listener.event, &*other.listener.event) } } @@ -889,7 +913,7 @@ impl Future for EventListener { pin_project_lite::pin_project! { #[project(!Unpin)] #[project = ListenerProject] - struct Listener>> + struct InnerListener>> where B: Unpin, { @@ -904,7 +928,7 @@ pin_project_lite::pin_project! { listener: Option>, } - impl>> PinnedDrop for Listener + impl>> PinnedDrop for InnerListener where B: Unpin, { @@ -916,10 +940,10 @@ pin_project_lite::pin_project! { } } -unsafe impl> + Unpin + Send> Send for Listener {} -unsafe impl> + Unpin + Sync> Sync for Listener {} +unsafe impl> + Unpin + Send> Send for InnerListener {} +unsafe impl> + Unpin + Sync> Sync for InnerListener {} -impl> + Unpin> Listener { +impl> + Unpin> InnerListener { /// Wait until the provided deadline. #[cfg(all(feature = "std", not(target_family = "wasm")))] fn wait_internal(mut self: Pin<&mut Self>, deadline: Option) -> Option { @@ -1225,3 +1249,11 @@ fn __test_send_and_sync() { _assert_send::>(); _assert_sync::>(); } + +#[doc(hidden)] +mod __private { + use super::EventListener; + + pub trait Sealed {} + impl Sealed for EventListener {} +}