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(internal:i);
116 }
117
118 fn count(&self, i: Internal) -> usize {
119 self.0.count(internal:i)
120 }
121
122 fn next_tag(&mut self, i: Internal) -> Self::Tag {
123 self.0.next_tag(internal: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(internal: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(internal:i)
155 }
156
157 fn next_tag(&mut self, i: Internal) -> Self::Tag {
158 self.0.next_tag(internal: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(internal:i)
192 }
193
194 fn fence(&self, i: Internal) {
195 self.inner.fence(internal:i);
196 }
197
198 fn count(&self, i: Internal) -> usize {
199 self.inner.count(internal: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(data:"..")
223 }
224 }
225
226 f&mut DebugStruct<'_, '_>.debug_struct("TagWith")
227 .field("tag", &Ellipses)
228 .field(name:"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(internal:i)
251 }
252
253 fn fence(&self, i: Internal) {
254 self.inner.fence(internal:i);
255 }
256
257 fn count(&self, i: Internal) -> usize {
258 self.inner.count(internal: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}
623