event_listener/
notify.rs

1//! The `Notification` trait for specifying notification.
2
3use crate::sync::atomic::{self, Ordering};
4#[cfg(feature = "std")]
5use core::fmt;
6
7pub(crate) use __private::Internal;
8
9/// The type of notification to use with an [`Event`].
10///
11/// This is hidden and sealed to prevent changes to this trait from being breaking.
12///
13/// [`Event`]: crate::Event
14#[doc(hidden)]
15pub trait NotificationPrivate {
16    /// The tag data associated with a notification.
17    type Tag;
18
19    /// Emit a fence to ensure that the notification is visible to the listeners.
20    fn fence(&self, internal: Internal);
21
22    /// Whether or not the number of currently waiting listeners should be subtracted from `count()`.
23    fn is_additional(&self, internal: Internal) -> bool;
24
25    /// Get the number of listeners to wake.
26    fn count(&self, internal: Internal) -> usize;
27
28    /// Get a tag to be associated with a notification.
29    ///
30    /// This method is expected to be called `count()` times.
31    fn next_tag(&mut self, internal: Internal) -> Self::Tag;
32}
33
34/// A notification that can be used to notify an [`Event`].
35///
36/// This type is used by the [`Event::notify()`] function to determine how many listeners to wake up, whether
37/// or not to subtract additional listeners, and other properties. The actual internal data is hidden in a
38/// private trait and is intentionally not exposed. This means that users cannot manually implement the
39/// [`Notification`] trait. However, it also means that changing the underlying trait is not a semver breaking
40/// change.
41///
42/// Users can create types that implement notifications using the combinators on the [`IntoNotification`] type.
43/// Typical construction of a [`Notification`] starts with a numeric literal (like `3usize`) and then optionally
44/// adding combinators.
45///
46/// # Example
47///
48/// ```
49/// use event_listener::{Event, IntoNotification, Notification};
50///
51/// fn notify(ev: &Event, notify: impl Notification<Tag = ()>) {
52///     ev.notify(notify);
53/// }
54///
55/// notify(&Event::new(), 1.additional());
56/// ```
57///
58/// [`Event`]: crate::Event
59pub trait Notification: NotificationPrivate {}
60impl<N: NotificationPrivate + ?Sized> Notification for N {}
61
62/// Notify a given number of unnotifed listeners.
63#[derive(Debug, Clone)]
64#[doc(hidden)]
65pub struct Notify(usize);
66
67impl Notify {
68    /// Create a new `Notify` with the given number of listeners to notify.
69    fn new(count: usize) -> Self {
70        Self(count)
71    }
72}
73
74impl NotificationPrivate for Notify {
75    type Tag = ();
76
77    fn is_additional(&self, _: Internal) -> bool {
78        false
79    }
80
81    fn fence(&self, _: Internal) {
82        full_fence();
83    }
84
85    fn count(&self, _: Internal) -> usize {
86        self.0
87    }
88
89    fn next_tag(&mut self, _: Internal) -> Self::Tag {}
90}
91
92/// Make the underlying notification additional.
93#[derive(Debug, Clone)]
94#[doc(hidden)]
95pub struct Additional<N: ?Sized>(N);
96
97impl<N> Additional<N> {
98    /// Create a new `Additional` with the given notification.
99    fn new(inner: N) -> Self {
100        Self(inner)
101    }
102}
103
104impl<N> NotificationPrivate for Additional<N>
105where
106    N: Notification + ?Sized,
107{
108    type Tag = N::Tag;
109
110    fn is_additional(&self, _: Internal) -> bool {
111        true
112    }
113
114    fn fence(&self, i: Internal) {
115        self.0.fence(i);
116    }
117
118    fn count(&self, i: Internal) -> usize {
119        self.0.count(i)
120    }
121
122    fn next_tag(&mut self, i: Internal) -> Self::Tag {
123        self.0.next_tag(i)
124    }
125}
126
127/// Don't emit a fence for this notification.
128#[derive(Debug, Clone)]
129#[doc(hidden)]
130pub struct Relaxed<N: ?Sized>(N);
131
132impl<N> Relaxed<N> {
133    /// Create a new `Relaxed` with the given notification.
134    fn new(inner: N) -> Self {
135        Self(inner)
136    }
137}
138
139impl<N> NotificationPrivate for Relaxed<N>
140where
141    N: Notification + ?Sized,
142{
143    type Tag = N::Tag;
144
145    fn is_additional(&self, i: Internal) -> bool {
146        self.0.is_additional(i)
147    }
148
149    fn fence(&self, _: Internal) {
150        // Don't emit a fence.
151    }
152
153    fn count(&self, i: Internal) -> usize {
154        self.0.count(i)
155    }
156
157    fn next_tag(&mut self, i: Internal) -> Self::Tag {
158        self.0.next_tag(i)
159    }
160}
161
162/// Use a tag to notify listeners.
163#[cfg(feature = "std")]
164#[derive(Debug, Clone)]
165#[doc(hidden)]
166pub struct Tag<N: ?Sized, T> {
167    tag: T,
168    inner: N,
169}
170
171#[cfg(feature = "std")]
172impl<N: ?Sized, T> Tag<N, T> {
173    /// Create a new `Tag` with the given tag and notification.
174    fn new(tag: T, inner: N) -> Self
175    where
176        N: Sized,
177    {
178        Self { tag, inner }
179    }
180}
181
182#[cfg(feature = "std")]
183impl<N, T> NotificationPrivate for Tag<N, T>
184where
185    N: Notification + ?Sized,
186    T: Clone,
187{
188    type Tag = T;
189
190    fn is_additional(&self, i: Internal) -> bool {
191        self.inner.is_additional(i)
192    }
193
194    fn fence(&self, i: Internal) {
195        self.inner.fence(i);
196    }
197
198    fn count(&self, i: Internal) -> usize {
199        self.inner.count(i)
200    }
201
202    fn next_tag(&mut self, _: Internal) -> Self::Tag {
203        self.tag.clone()
204    }
205}
206
207/// Use a function to generate a tag to notify listeners.
208#[cfg(feature = "std")]
209#[doc(hidden)]
210pub struct TagWith<N: ?Sized, F> {
211    tag: F,
212    inner: N,
213}
214
215#[cfg(feature = "std")]
216impl<N: fmt::Debug, F> fmt::Debug for TagWith<N, F> {
217    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218        struct Ellipses;
219
220        impl fmt::Debug for Ellipses {
221            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222                f.write_str("..")
223            }
224        }
225
226        f.debug_struct("TagWith")
227            .field("tag", &Ellipses)
228            .field("inner", &self.inner)
229            .finish()
230    }
231}
232
233#[cfg(feature = "std")]
234impl<N, F> TagWith<N, F> {
235    /// Create a new `TagFn` with the given tag function and notification.
236    fn new(tag: F, inner: N) -> Self {
237        Self { tag, inner }
238    }
239}
240
241#[cfg(feature = "std")]
242impl<N, F, T> NotificationPrivate for TagWith<N, F>
243where
244    N: Notification + ?Sized,
245    F: FnMut() -> T,
246{
247    type Tag = T;
248
249    fn is_additional(&self, i: Internal) -> bool {
250        self.inner.is_additional(i)
251    }
252
253    fn fence(&self, i: Internal) {
254        self.inner.fence(i);
255    }
256
257    fn count(&self, i: Internal) -> usize {
258        self.inner.count(i)
259    }
260
261    fn next_tag(&mut self, _: Internal) -> Self::Tag {
262        (self.tag)()
263    }
264}
265
266/// A generic notification.
267#[derive(Debug)]
268pub(crate) struct GenericNotify<F> {
269    /// Number of listeners to notify.
270    count: usize,
271
272    /// Whether this notification is additional.
273    additional: bool,
274
275    /// Generate tags.
276    tags: F,
277}
278
279impl<T, F: TagProducer<Tag = T>> GenericNotify<F> {
280    pub(crate) fn new(count: usize, additional: bool, tags: F) -> Self {
281        Self {
282            count,
283            additional,
284            tags,
285        }
286    }
287}
288
289impl<T, F: TagProducer<Tag = T>> NotificationPrivate for GenericNotify<F> {
290    type Tag = T;
291
292    fn is_additional(&self, _: Internal) -> bool {
293        self.additional
294    }
295
296    fn fence(&self, _: Internal) {
297        // Don't emit a fence.
298    }
299
300    fn count(&self, _: Internal) -> usize {
301        self.count
302    }
303
304    fn next_tag(&mut self, _: Internal) -> Self::Tag {
305        self.tags.next_tag()
306    }
307}
308
309/// The producer for a generic notification.
310pub(crate) trait TagProducer {
311    type Tag;
312
313    /// Get the next tag.
314    fn next_tag(&mut self) -> Self::Tag;
315}
316
317impl<T, F: FnMut() -> T> TagProducer for F {
318    type Tag = T;
319
320    fn next_tag(&mut self) -> T {
321        (self)()
322    }
323}
324
325/// A value that can be converted into a [`Notification`].
326///
327/// This trait adds onto the [`Notification`] trait by providing combinators that can be applied to all
328/// notification types as well as numeric literals. This transforms what would normally be:
329///
330/// ```
331/// use event_listener::Event;
332///
333/// let event = Event::new();
334///
335/// // Note that each use case needs its own function, leading to bloat.
336/// event.notify(1);
337/// event.notify_additional(3);
338/// event.notify_relaxed(5);
339/// event.notify_additional_relaxed(2);
340/// ```
341///
342/// into this:
343///
344/// ```
345/// use event_listener::{Event, IntoNotification, Listener};
346///
347/// let event = Event::new();
348///
349/// event.notify(1);
350/// event.notify(3.additional());
351/// event.notify(5.relaxed());
352/// event.notify(2.additional().relaxed());
353/// ```
354///
355/// This trait is implemented for all types that implement [`Notification`], as well as for non-floating-point
356/// numeric literals (`usize`, `i32`, etc).
357///
358/// This function can be thought of as being analogous to [`std::iter::IntoIterator`], but for [`Notification`].
359pub trait IntoNotification: __private::Sealed {
360    /// The tag data associated with a notification.
361    ///
362    /// By default, most [`Event`]s will use the unit type, `()`. However, this can be used to pass data along to
363    /// the listener.
364    type Tag;
365
366    /// The notification type.
367    ///
368    /// Tells what kind of underlying type that the [`Notification`] is. You probably don't need to worry about
369    /// this.
370    type Notify: Notification<Tag = Self::Tag>;
371
372    /// Convert this value into a notification.
373    ///
374    /// This allows the user to convert an [`IntoNotification`] into a [`Notification`].
375    ///
376    /// # Panics
377    ///
378    /// This function panics if the value represents a negative number of notifications.
379    ///
380    /// # Examples
381    ///
382    /// ```
383    /// use event_listener::IntoNotification;
384    ///
385    /// let _ = 3.into_notification();
386    /// ```
387    fn into_notification(self) -> Self::Notify;
388
389    /// Convert this value into an additional notification.
390    ///
391    /// By default, notifications ignore listeners that are already notified. Generally, this happens when there
392    /// is an [`EventListener`] that has been woken up, but hasn't been polled to completion or waited on yet.
393    /// For instance, if you have three notified listeners and you call `event.notify(5)`, only two listeners
394    /// will be woken up.
395    ///
396    /// This default behavior is generally desired. For instance, if you are writing a `Mutex` implementation
397    /// powered by an [`Event`], you usually only want one consumer to be notified at a time. If you notified
398    /// a listener when another listener is already notified, you would have unnecessary contention for your
399    /// lock, as both listeners fight over the lock. Therefore, you would call `event.notify(1)` to make sure
400    /// *at least* one listener is awake.
401    ///
402    /// Sometimes, this behavior is not desired. For instance, if you are writing an MPMC channel, it is desirable
403    /// for multiple listeners to be reading from the underlying queue at once. In this case, you would instead
404    /// call `event.notify(1.additional())`.
405    ///
406    /// # Examples
407    ///
408    /// ```
409    /// use event_listener::{Event, IntoNotification, Listener};
410    ///
411    /// let event = Event::new();
412    ///
413    /// let mut l1 = event.listen();
414    /// let mut l2 = event.listen();
415    ///
416    /// // This will only wake up the first listener, as the second call observes that there is already a
417    /// // notified listener.
418    /// event.notify(1);
419    /// event.notify(1);
420    ///
421    /// // This call wakes up the other listener.
422    /// event.notify(1.additional());
423    /// ```
424    fn additional(self) -> Additional<Self::Notify>
425    where
426        Self: Sized,
427    {
428        Additional::new(self.into_notification())
429    }
430
431    /// Don't emit a fence for this notification.
432    ///
433    /// Usually, notifications emit a `SeqCst` atomic fence before any listeners are woken up. This ensures
434    /// that notification state isn't inconsistent before any wakers are woken up. However, it may be
435    /// desirable to omit this fence in certain cases.
436    ///
437    /// - You are running the [`Event`] on a single thread, where no synchronization needs to occur.
438    /// - You are emitting the `SeqCst` fence yourself.
439    ///
440    /// In these cases, `relaxed()` can be used to avoid emitting the `SeqCst` fence.
441    ///
442    /// # Examples
443    ///
444    /// ```
445    /// use event_listener::{Event, IntoNotification, Listener};
446    /// use std::sync::atomic::{self, Ordering};
447    ///
448    /// let event = Event::new();
449    ///
450    /// let listener1 = event.listen();
451    /// let listener2 = event.listen();
452    /// let listener3 = event.listen();
453    ///
454    /// // We should emit a fence manually when using relaxed notifications.
455    /// atomic::fence(Ordering::SeqCst);
456    ///
457    /// // Notifies two listeners.
458    /// //
459    /// // Listener queueing is fair, which means `listener1` and `listener2`
460    /// // get notified here since they start listening before `listener3`.
461    /// event.notify(1.relaxed());
462    /// event.notify(1.relaxed());
463    /// ```
464    fn relaxed(self) -> Relaxed<Self::Notify>
465    where
466        Self: Sized,
467    {
468        Relaxed::new(self.into_notification())
469    }
470
471    /// Use a tag with this notification.
472    ///
473    /// In many cases, it is desired to send additional information to the listener of the [`Event`]. For instance,
474    /// it is possible to optimize a `Mutex` implementation by locking directly on the next listener, without
475    /// needing to ever unlock the mutex at all.
476    ///
477    /// The tag provided is cloned to provide the tag for all listeners. In cases where this is not flexible
478    /// enough, use [`IntoNotification::with_tag()`] instead.
479    ///
480    /// Tagging functions cannot be implemented efficiently for `no_std`, so this is only available
481    /// when the `std` feature is enabled.
482    ///
483    /// # Examples
484    ///
485    /// ```
486    /// use event_listener::{IntoNotification, Listener, Event};
487    ///
488    /// let event = Event::<bool>::with_tag();
489    ///
490    /// let mut listener1 = event.listen();
491    /// let mut listener2 = event.listen();
492    ///
493    /// // Notify with `true` then `false`.
494    /// event.notify(1.additional().tag(true));
495    /// event.notify(1.additional().tag(false));
496    ///
497    /// assert_eq!(listener1.wait(), true);
498    /// assert_eq!(listener2.wait(), false);
499    /// ```
500    #[cfg(feature = "std")]
501    fn tag<T: Clone>(self, tag: T) -> Tag<Self::Notify, T>
502    where
503        Self: Sized + IntoNotification<Tag = ()>,
504    {
505        Tag::new(tag, self.into_notification())
506    }
507
508    /// Use a function to generate a tag with this notification.
509    ///
510    /// In many cases, it is desired to send additional information to the listener of the [`Event`]. For instance,
511    /// it is possible to optimize a `Mutex` implementation by locking directly on the next listener, without
512    /// needing to ever unlock the mutex at all.
513    ///
514    /// Tagging functions cannot be implemented efficiently for `no_std`, so this is only available
515    /// when the `std` feature is enabled.
516    ///
517    /// # Examples
518    ///
519    /// ```
520    /// use event_listener::{IntoNotification, Listener, Event};
521    ///
522    /// let event = Event::<bool>::with_tag();
523    ///
524    /// let mut listener1 = event.listen();
525    /// let mut listener2 = event.listen();
526    ///
527    /// // Notify with `true` then `false`.
528    /// event.notify(1.additional().tag_with(|| true));
529    /// event.notify(1.additional().tag_with(|| false));
530    ///
531    /// assert_eq!(listener1.wait(), true);
532    /// assert_eq!(listener2.wait(), false);
533    /// ```
534    #[cfg(feature = "std")]
535    fn tag_with<T, F>(self, tag: F) -> TagWith<Self::Notify, F>
536    where
537        Self: Sized + IntoNotification<Tag = ()>,
538        F: FnMut() -> T,
539    {
540        TagWith::new(tag, self.into_notification())
541    }
542}
543
544impl<N: Notification> IntoNotification for N {
545    type Tag = N::Tag;
546    type Notify = N;
547
548    fn into_notification(self) -> Self::Notify {
549        self
550    }
551}
552
553macro_rules! impl_for_numeric_types {
554    ($($ty:ty)*) => {$(
555        impl IntoNotification for $ty {
556            type Tag = ();
557            type Notify = Notify;
558
559            #[allow(unused_comparisons)]
560            fn into_notification(self) -> Self::Notify {
561                if self < 0 {
562                    panic!("negative notification count");
563                }
564
565                Notify::new(self.try_into().expect("overflow"))
566            }
567        }
568
569        impl __private::Sealed for $ty {}
570    )*};
571}
572
573impl_for_numeric_types! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
574
575/// Equivalent to `atomic::fence(Ordering::SeqCst)`, but in some cases faster.
576#[inline]
577pub(super) fn full_fence() {
578    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), not(miri), not(loom)))]
579    {
580        use core::{arch::asm, cell::UnsafeCell};
581        // HACK(stjepang): On x86 architectures there are two different ways of executing
582        // a `SeqCst` fence.
583        //
584        // 1. `atomic::fence(SeqCst)`, which compiles into a `mfence` instruction.
585        // 2. A `lock <op>` instruction.
586        //
587        // Both instructions have the effect of a full barrier, but empirical benchmarks have shown
588        // that the second one is sometimes a bit faster.
589        let a = UnsafeCell::new(0_usize);
590        // It is common to use `lock or` here, but when using a local variable, `lock not`, which
591        // does not change the flag, should be slightly more efficient.
592        // Refs: https://www.felixcloutier.com/x86/not
593        unsafe {
594            #[cfg(target_pointer_width = "64")]
595            asm!("lock not qword ptr [{0}]", in(reg) a.get(), options(nostack, preserves_flags));
596            #[cfg(target_pointer_width = "32")]
597            asm!("lock not dword ptr [{0:e}]", in(reg) a.get(), options(nostack, preserves_flags));
598        }
599        return;
600    }
601    #[allow(unreachable_code)]
602    {
603        atomic::fence(Ordering::SeqCst);
604    }
605}
606
607mod __private {
608    /// Make sure the NotificationPrivate trait can't be implemented outside of this crate.
609    #[doc(hidden)]
610    #[derive(Debug)]
611    pub struct Internal(());
612
613    impl Internal {
614        pub(crate) fn new() -> Self {
615            Self(())
616        }
617    }
618
619    #[doc(hidden)]
620    pub trait Sealed {}
621    impl<N: super::NotificationPrivate + ?Sized> Sealed for N {}
622}