Skip to content

Commit 68be528

Browse files
committed
feat: Add stack-based listener
It is instantiated with the listener!() macro. Signed-off-by: John Nunley <[email protected]>
1 parent d9144a8 commit 68be528

File tree

2 files changed

+187
-66
lines changed

2 files changed

+187
-66
lines changed

examples/mutex.rs

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ mod example {
1313
use std::thread;
1414
use std::time::{Duration, Instant};
1515

16-
use event_listener::{Event, Listener};
16+
use event_listener::{listener, Event, Listener};
1717

1818
/// A simple mutex.
1919
struct Mutex<T> {
@@ -51,74 +51,66 @@ mod example {
5151

5252
/// Blocks until a lock is acquired.
5353
fn lock(&self) -> MutexGuard<'_, T> {
54-
let mut listener = None;
55-
5654
loop {
5755
// Attempt grabbing a lock.
5856
if let Some(guard) = self.try_lock() {
5957
return guard;
6058
}
6159

62-
// Set up an event listener or wait for a notification.
63-
match listener.take() {
64-
None => {
65-
// Start listening and then try locking again.
66-
listener = Some(self.lock_ops.listen());
67-
}
68-
Some(l) => {
69-
// Wait until a notification is received.
70-
l.wait();
71-
}
60+
// Set up an event listener.
61+
listener!(self.lock_ops => listener);
62+
63+
// Try again.
64+
if let Some(guard) = self.try_lock() {
65+
return guard;
7266
}
67+
68+
// Wait for a notification.
69+
listener.wait();
7370
}
7471
}
7572

7673
/// Blocks until a lock is acquired or the timeout is reached.
7774
fn lock_timeout(&self, timeout: Duration) -> Option<MutexGuard<'_, T>> {
7875
let deadline = Instant::now() + timeout;
79-
let mut listener = None;
8076

8177
loop {
8278
// Attempt grabbing a lock.
8379
if let Some(guard) = self.try_lock() {
8480
return Some(guard);
8581
}
8682

87-
// Set up an event listener or wait for an event.
88-
match listener.take() {
89-
None => {
90-
// Start listening and then try locking again.
91-
listener = Some(self.lock_ops.listen());
92-
}
93-
Some(l) => {
94-
// Wait until a notification is received.
95-
l.wait_deadline(deadline)?;
96-
}
83+
// Set up an event listener.
84+
listener!(self.lock_ops => listener);
85+
86+
// Try again.
87+
if let Some(guard) = self.try_lock() {
88+
return Some(guard);
9789
}
90+
91+
// Wait until a notification is received.
92+
listener.wait_deadline(deadline)?;
9893
}
9994
}
10095

10196
/// Acquires a lock asynchronously.
10297
async fn lock_async(&self) -> MutexGuard<'_, T> {
103-
let mut listener = None;
104-
10598
loop {
10699
// Attempt grabbing a lock.
107100
if let Some(guard) = self.try_lock() {
108101
return guard;
109102
}
110103

111-
// Set up an event listener or wait for an event.
112-
match listener.take() {
113-
None => {
114-
// Start listening and then try locking again.
115-
listener = Some(self.lock_ops.listen());
116-
}
117-
Some(l) => {
118-
// Wait until a notification is received.
119-
l.await;
120-
}
104+
// Set up an event listener.
105+
listener!(self.lock_ops => listener);
106+
107+
// Try again.
108+
if let Some(guard) = self.try_lock() {
109+
return guard;
121110
}
111+
112+
// Wait until a notification is received.
113+
listener.await;
122114
}
123115
}
124116
}

src/lib.rs

Lines changed: 159 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ impl<T> Event<T> {
287287
event: Arc::clone(&inner),
288288
listener: None,
289289
});
290-
inner.insert(listener.as_mut().project().listener);
290+
listener.as_mut().listen();
291291

292292
// Return the listener.
293293
EventListener { listener }
@@ -724,7 +724,7 @@ impl<T> Drop for Event<T> {
724724
///
725725
/// This trait represents a type waiting for a notification from an [`Event`]. See the
726726
/// [`EventListener`] type for more documentation on this trait's usage.
727-
pub trait Listener<T>: Future<Output = T> + __private::Sealed {
727+
pub trait Listener<T>: Future<Output = T> + __sealed::Sealed {
728728
/// Blocks until a notification is received.
729729
///
730730
/// # Examples
@@ -833,6 +833,45 @@ pub trait Listener<T>: Future<Output = T> + __private::Sealed {
833833
fn same_event(&self, other: &Self) -> bool;
834834
}
835835

836+
macro_rules! forward_impl_to_listener {
837+
($gen:ident => $ty:ty) => {
838+
impl<$gen> crate::Listener<$gen> for $ty {
839+
#[cfg(all(feature = "std", not(target_family = "wasm")))]
840+
fn wait(mut self) -> $gen {
841+
self.listener_mut().wait_internal(None).unwrap()
842+
}
843+
844+
#[cfg(all(feature = "std", not(target_family = "wasm")))]
845+
fn wait_timeout(mut self, timeout: std::time::Duration) -> Option<$gen> {
846+
self.listener_mut()
847+
.wait_internal(std::time::Instant::now().checked_add(timeout))
848+
}
849+
850+
#[cfg(all(feature = "std", not(target_family = "wasm")))]
851+
fn wait_deadline(mut self, deadline: std::time::Instant) -> Option<$gen> {
852+
self.listener_mut().wait_internal(Some(deadline))
853+
}
854+
855+
fn discard(mut self) -> bool {
856+
self.listener_mut().discard()
857+
}
858+
859+
#[inline]
860+
fn listens_to(&self, event: &Event<$gen>) -> bool {
861+
core::ptr::eq::<Inner<$gen>>(
862+
&*self.listener().event,
863+
event.inner.load(core::sync::atomic::Ordering::Acquire),
864+
)
865+
}
866+
867+
#[inline]
868+
fn same_event(&self, other: &$ty) -> bool {
869+
core::ptr::eq::<Inner<$gen>>(&*self.listener().event, &*other.listener().event)
870+
}
871+
}
872+
};
873+
}
874+
836875
/// A guard waiting for a notification from an [`Event`].
837876
///
838877
/// There are two ways for a listener to wait for a notification:
@@ -869,39 +908,20 @@ impl<T> fmt::Debug for EventListener<T> {
869908
}
870909
}
871910

872-
impl<T> Listener<T> for EventListener<T> {
873-
#[cfg(all(feature = "std", not(target_family = "wasm")))]
874-
fn wait(mut self) -> T {
875-
self.listener.as_mut().wait_internal(None).unwrap()
876-
}
877-
878-
#[cfg(all(feature = "std", not(target_family = "wasm")))]
879-
fn wait_timeout(mut self, timeout: Duration) -> Option<T> {
880-
self.listener
881-
.as_mut()
882-
.wait_internal(Instant::now().checked_add(timeout))
883-
}
884-
885-
#[cfg(all(feature = "std", not(target_family = "wasm")))]
886-
fn wait_deadline(mut self, deadline: Instant) -> Option<T> {
887-
self.listener.as_mut().wait_internal(Some(deadline))
888-
}
889-
890-
fn discard(mut self) -> bool {
891-
self.listener.as_mut().discard()
892-
}
893-
911+
impl<T> EventListener<T> {
894912
#[inline]
895-
fn listens_to(&self, event: &Event<T>) -> bool {
896-
ptr::eq::<Inner<T>>(&*self.listener.event, event.inner.load(Ordering::Acquire))
913+
fn listener(&self) -> &InnerListener<T, Arc<Inner<T>>> {
914+
&self.listener
897915
}
898916

899917
#[inline]
900-
fn same_event(&self, other: &EventListener<T>) -> bool {
901-
ptr::eq::<Inner<T>>(&*self.listener.event, &*other.listener.event)
918+
fn listener_mut(&mut self) -> Pin<&mut InnerListener<T, Arc<Inner<T>>>> {
919+
self.listener.as_mut()
902920
}
903921
}
904922

923+
forward_impl_to_listener! { T => EventListener<T> }
924+
905925
impl<T> Future for EventListener<T> {
906926
type Output = T;
907927

@@ -910,6 +930,18 @@ impl<T> Future for EventListener<T> {
910930
}
911931
}
912932

933+
/// Create a stack-based event listener for an [`Event`].
934+
#[macro_export]
935+
macro_rules! listener {
936+
($event:expr => $listener:ident) => {
937+
let mut $listener = $crate::__private::StackSlot::new(&$event);
938+
// SAFETY: We shadow $listener so it can't be moved after.
939+
let mut $listener = unsafe { $crate::__private::Pin::new_unchecked(&mut $listener) };
940+
#[allow(unused_mut)]
941+
let mut $listener = $listener.listen();
942+
};
943+
}
944+
913945
pin_project_lite::pin_project! {
914946
#[project(!Unpin)]
915947
#[project = ListenerProject]
@@ -944,6 +976,13 @@ unsafe impl<T: Send, B: Borrow<Inner<T>> + Unpin + Send> Send for InnerListener<
944976
unsafe impl<T: Send, B: Borrow<Inner<T>> + Unpin + Sync> Sync for InnerListener<T, B> {}
945977

946978
impl<T, B: Borrow<Inner<T>> + Unpin> InnerListener<T, B> {
979+
/// Insert this listener into the linked list.
980+
#[inline]
981+
fn listen(self: Pin<&mut Self>) {
982+
let this = self.project();
983+
(*this.event).borrow().insert(this.listener);
984+
}
985+
947986
/// Wait until the provided deadline.
948987
#[cfg(all(feature = "std", not(target_family = "wasm")))]
949988
fn wait_internal(mut self: Pin<&mut Self>, deadline: Option<Instant>) -> Option<T> {
@@ -1251,9 +1290,99 @@ fn __test_send_and_sync() {
12511290
}
12521291

12531292
#[doc(hidden)]
1254-
mod __private {
1255-
use super::EventListener;
1293+
mod __sealed {
1294+
use super::{EventListener, __private::StackListener};
12561295

12571296
pub trait Sealed {}
12581297
impl<T> Sealed for EventListener<T> {}
1298+
impl<T> Sealed for StackListener<'_, '_, T> {}
1299+
}
1300+
1301+
/// Semver exempt module.
1302+
#[doc(hidden)]
1303+
pub mod __private {
1304+
pub use core::pin::Pin;
1305+
1306+
use super::{Event, Inner, InnerListener};
1307+
use core::fmt;
1308+
use core::future::Future;
1309+
use core::task::{Context, Poll};
1310+
1311+
pin_project_lite::pin_project! {
1312+
/// Space on the stack where a stack-based listener can be allocated.
1313+
#[doc(hidden)]
1314+
pub struct StackSlot<'ev, T> {
1315+
#[pin]
1316+
listener: InnerListener<T, &'ev Inner<T>>
1317+
}
1318+
}
1319+
1320+
impl<T> fmt::Debug for StackSlot<'_, T> {
1321+
#[inline]
1322+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1323+
f.debug_struct("StackSlot").finish_non_exhaustive()
1324+
}
1325+
}
1326+
1327+
impl<'ev, T> StackSlot<'ev, T> {
1328+
/// Create a new `StackSlot` on the stack.
1329+
#[inline]
1330+
#[doc(hidden)]
1331+
pub fn new(event: &'ev Event<T>) -> Self {
1332+
let inner = unsafe { &*event.inner() };
1333+
Self {
1334+
listener: InnerListener {
1335+
event: inner,
1336+
listener: None,
1337+
},
1338+
}
1339+
}
1340+
1341+
/// Start listening on this `StackSlot`.
1342+
#[inline]
1343+
#[doc(hidden)]
1344+
pub fn listen(mut self: Pin<&mut Self>) -> StackListener<'ev, '_, T> {
1345+
// Insert ourselves into the list.
1346+
self.as_mut().project().listener.listen();
1347+
1348+
// We are now listening.
1349+
StackListener { slot: self }
1350+
}
1351+
}
1352+
1353+
/// A stack-based `EventListener`.
1354+
#[doc(hidden)]
1355+
pub struct StackListener<'ev, 'stack, T> {
1356+
slot: Pin<&'stack mut StackSlot<'ev, T>>,
1357+
}
1358+
1359+
impl<T> fmt::Debug for StackListener<'_, '_, T> {
1360+
#[inline]
1361+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1362+
f.debug_struct("StackListener").finish_non_exhaustive()
1363+
}
1364+
}
1365+
1366+
impl<'ev, T> StackListener<'ev, '_, T> {
1367+
#[inline]
1368+
fn listener(&self) -> &InnerListener<T, &'ev Inner<T>> {
1369+
&self.slot.listener
1370+
}
1371+
1372+
#[inline]
1373+
fn listener_mut(&mut self) -> Pin<&mut InnerListener<T, &'ev Inner<T>>> {
1374+
self.slot.as_mut().project().listener
1375+
}
1376+
}
1377+
1378+
forward_impl_to_listener! { T => StackListener<'_, '_, T> }
1379+
1380+
impl<T> Future for StackListener<'_, '_, T> {
1381+
type Output = T;
1382+
1383+
#[inline]
1384+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1385+
self.listener_mut().poll_internal(cx)
1386+
}
1387+
}
12591388
}

0 commit comments

Comments
 (0)