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 <dev@notgull.net>
This commit is contained in:
John Nunley 2023-12-19 16:56:22 -08:00 committed by John Nunley
parent 86b778074c
commit d9144a8a41
3 changed files with 150 additions and 118 deletions

View File

@ -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;

View File

@ -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<T> {

View File

@ -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<T> Event<T> {
/// # Examples
///
/// ```
/// use event_listener::Event;
/// use event_listener::{Event, prelude::*};
///
/// let event = Event::<usize>::with_tag();
/// ```
@ -230,7 +230,7 @@ impl<T> Event<T> {
/// # Examples
///
/// ```
/// use event_listener::Event;
/// use event_listener::{Event, prelude::*};
///
/// let event = Event::new();
/// let listener = event.listen();
@ -254,7 +254,7 @@ impl<T> Event<T> {
/// # Examples
///
/// ```
/// use event_listener::Event;
/// use event_listener::{Event, prelude::*};
///
/// let event = Event::new();
/// let listener = event.listen();
@ -283,7 +283,7 @@ impl<T> Event<T> {
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<T> Event<T> {
/// 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,6 +720,119 @@ impl<T> Drop for Event<T> {
}
}
/// A handle that is listening to an [`Event`].
///
/// 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<T>: Future<Output = T> + __private::Sealed {
/// Blocks until a notification is received.
///
/// # Examples
///
/// ```
/// use event_listener::{Event, prelude::*};
///
/// let event = Event::new();
/// let mut listener = event.listen();
///
/// // Notify `listener`.
/// event.notify(1);
///
/// // Receive the notification.
/// listener.wait();
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
fn wait(self) -> T;
/// Blocks until a notification is received or a timeout is reached.
///
/// Returns `true` if a notification was received.
///
/// # Examples
///
/// ```
/// use std::time::Duration;
/// use event_listener::{Event, prelude::*};
///
/// let event = Event::new();
/// let mut listener = event.listen();
///
/// // There are no notification so this times out.
/// assert!(listener.wait_timeout(Duration::from_secs(1)).is_none());
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
fn wait_timeout(self, timeout: Duration) -> Option<T>;
/// Blocks until a notification is received or a deadline is reached.
///
/// Returns `true` if a notification was received.
///
/// # Examples
///
/// ```
/// use std::time::{Duration, Instant};
/// use event_listener::{Event, prelude::*};
///
/// let event = Event::new();
/// let mut listener = event.listen();
///
/// // There are no notification so this times out.
/// assert!(listener.wait_deadline(Instant::now() + Duration::from_secs(1)).is_none());
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
fn wait_deadline(self, deadline: Instant) -> Option<T>;
/// Drops this listener and discards its notification (if any) without notifying another
/// active listener.
///
/// Returns `true` if a notification was discarded.
///
/// # Examples
///
/// ```
/// use event_listener::{Event, prelude::*};
///
/// let event = Event::new();
/// let mut listener1 = event.listen();
/// let mut listener2 = event.listen();
///
/// event.notify(1);
///
/// assert!(listener1.discard());
/// assert!(!listener2.discard());
/// ```
fn discard(self) -> bool;
/// Returns `true` if this listener listens to the given `Event`.
///
/// # Examples
///
/// ```
/// use event_listener::{Event, prelude::*};
///
/// let event = Event::new();
/// let listener = event.listen();
///
/// assert!(listener.listens_to(&event));
/// ```
fn listens_to(&self, event: &Event<T>) -> bool;
/// Returns `true` if both listeners listen to the same `Event`.
///
/// # Examples
///
/// ```
/// use event_listener::{Event, prelude::*};
///
/// let event = Event::new();
/// let listener1 = event.listen();
/// let listener2 = event.listen();
///
/// assert!(listener1.same_event(&listener2));
/// ```
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:
@ -731,6 +844,8 @@ impl<T> Drop for Event<T> {
/// 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
@ -738,7 +853,7 @@ impl<T> Drop for Event<T> {
///
/// This structure allocates the listener on the heap.
pub struct EventListener<T = ()> {
listener: Pin<Box<Listener<T, Arc<Inner<T>>>>>,
listener: Pin<Box<InnerListener<T, Arc<Inner<T>>>>>,
}
unsafe impl<T: Send> Send for EventListener<T> {}
@ -754,126 +869,35 @@ impl<T> fmt::Debug for EventListener<T> {
}
}
impl<T> EventListener<T> {
/// Blocks until a notification is received.
///
/// # Examples
///
/// ```
/// use event_listener::Event;
///
/// let event = Event::new();
/// let mut listener = event.listen();
///
/// // Notify `listener`.
/// event.notify(1);
///
/// // Receive the notification.
/// listener.wait();
/// ```
impl<T> Listener<T> for EventListener<T> {
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub fn wait(mut self) -> T {
fn wait(mut self) -> T {
self.listener.as_mut().wait_internal(None).unwrap()
}
/// Blocks until a notification is received or a timeout is reached.
///
/// Returns `true` if a notification was received.
///
/// # Examples
///
/// ```
/// use std::time::Duration;
/// use event_listener::Event;
///
/// let event = Event::new();
/// let mut listener = event.listen();
///
/// // There are no notification so this times out.
/// 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<T> {
fn wait_timeout(mut self, timeout: Duration) -> Option<T> {
self.listener
.as_mut()
.wait_internal(Instant::now().checked_add(timeout))
}
/// Blocks until a notification is received or a deadline is reached.
///
/// Returns `true` if a notification was received.
///
/// # Examples
///
/// ```
/// use std::time::{Duration, Instant};
/// use event_listener::Event;
///
/// let event = Event::new();
/// let mut listener = event.listen();
///
/// // There are no notification so this times out.
/// 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<T> {
fn wait_deadline(mut self, deadline: Instant) -> Option<T> {
self.listener.as_mut().wait_internal(Some(deadline))
}
/// Drops this listener and discards its notification (if any) without notifying another
/// active listener.
///
/// Returns `true` if a notification was discarded.
///
/// # Examples
///
/// ```
/// use event_listener::Event;
///
/// let event = Event::new();
/// let mut listener1 = event.listen();
/// let mut listener2 = event.listen();
///
/// event.notify(1);
///
/// assert!(listener1.discard());
/// assert!(!listener2.discard());
/// ```
pub fn discard(mut self) -> bool {
fn discard(mut self) -> bool {
self.listener.as_mut().discard()
}
/// Returns `true` if this listener listens to the given `Event`.
///
/// # Examples
///
/// ```
/// use event_listener::Event;
///
/// let event = Event::new();
/// let listener = event.listen();
///
/// assert!(listener.listens_to(&event));
/// ```
#[inline]
pub fn listens_to(&self, event: &Event<T>) -> bool {
fn listens_to(&self, event: &Event<T>) -> bool {
ptr::eq::<Inner<T>>(&*self.listener.event, event.inner.load(Ordering::Acquire))
}
/// Returns `true` if both listeners listen to the same `Event`.
///
/// # Examples
///
/// ```
/// use event_listener::Event;
///
/// let event = Event::new();
/// let listener1 = event.listen();
/// let listener2 = event.listen();
///
/// assert!(listener1.same_event(&listener2));
/// ```
pub fn same_event(&self, other: &EventListener<T>) -> bool {
#[inline]
fn same_event(&self, other: &EventListener<T>) -> bool {
ptr::eq::<Inner<T>>(&*self.listener.event, &*other.listener.event)
}
}
@ -889,7 +913,7 @@ impl<T> Future for EventListener<T> {
pin_project_lite::pin_project! {
#[project(!Unpin)]
#[project = ListenerProject]
struct Listener<T, B: Borrow<Inner<T>>>
struct InnerListener<T, B: Borrow<Inner<T>>>
where
B: Unpin,
{
@ -904,7 +928,7 @@ pin_project_lite::pin_project! {
listener: Option<sys::Listener<T>>,
}
impl<T, B: Borrow<Inner<T>>> PinnedDrop for Listener<T, B>
impl<T, B: Borrow<Inner<T>>> PinnedDrop for InnerListener<T, B>
where
B: Unpin,
{
@ -916,10 +940,10 @@ pin_project_lite::pin_project! {
}
}
unsafe impl<T: Send, B: Borrow<Inner<T>> + Unpin + Send> Send for Listener<T, B> {}
unsafe impl<T: Send, B: Borrow<Inner<T>> + Unpin + Sync> Sync for Listener<T, B> {}
unsafe impl<T: Send, B: Borrow<Inner<T>> + Unpin + Send> Send for InnerListener<T, B> {}
unsafe impl<T: Send, B: Borrow<Inner<T>> + Unpin + Sync> Sync for InnerListener<T, B> {}
impl<T, B: Borrow<Inner<T>> + Unpin> Listener<T, B> {
impl<T, B: Borrow<Inner<T>> + Unpin> InnerListener<T, B> {
/// Wait until the provided deadline.
#[cfg(all(feature = "std", not(target_family = "wasm")))]
fn wait_internal(mut self: Pin<&mut Self>, deadline: Option<Instant>) -> Option<T> {
@ -1225,3 +1249,11 @@ fn __test_send_and_sync() {
_assert_send::<EventListener<()>>();
_assert_sync::<EventListener<()>>();
}
#[doc(hidden)]
mod __private {
use super::EventListener;
pub trait Sealed {}
impl<T> Sealed for EventListener<T> {}
}