1 | //! The `Notification` trait for specifying notification. |
2 | |
3 | use crate::sync::atomic::{self, Ordering}; |
4 | #[cfg (feature = "std" )] |
5 | use core::fmt; |
6 | |
7 | pub(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)] |
15 | pub 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 |
59 | pub trait Notification: NotificationPrivate {} |
60 | impl<N: NotificationPrivate + ?Sized> Notification for N {} |
61 | |
62 | /// Notify a given number of unnotifed listeners. |
63 | #[derive (Debug, Clone)] |
64 | #[doc (hidden)] |
65 | pub struct Notify(usize); |
66 | |
67 | impl 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 | |
74 | impl 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)] |
95 | pub struct Additional<N: ?Sized>(N); |
96 | |
97 | impl<N> Additional<N> { |
98 | /// Create a new `Additional` with the given notification. |
99 | fn new(inner: N) -> Self { |
100 | Self(inner) |
101 | } |
102 | } |
103 | |
104 | impl<N> NotificationPrivate for Additional<N> |
105 | where |
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)] |
130 | pub struct Relaxed<N: ?Sized>(N); |
131 | |
132 | impl<N> Relaxed<N> { |
133 | /// Create a new `Relaxed` with the given notification. |
134 | fn new(inner: N) -> Self { |
135 | Self(inner) |
136 | } |
137 | } |
138 | |
139 | impl<N> NotificationPrivate for Relaxed<N> |
140 | where |
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)] |
166 | pub struct Tag<N: ?Sized, T> { |
167 | tag: T, |
168 | inner: N, |
169 | } |
170 | |
171 | #[cfg (feature = "std" )] |
172 | impl<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" )] |
183 | impl<N, T> NotificationPrivate for Tag<N, T> |
184 | where |
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)] |
210 | pub struct TagWith<N: ?Sized, F> { |
211 | tag: F, |
212 | inner: N, |
213 | } |
214 | |
215 | #[cfg (feature = "std" )] |
216 | impl<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" )] |
234 | impl<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" )] |
242 | impl<N, F, T> NotificationPrivate for TagWith<N, F> |
243 | where |
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)] |
268 | pub(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 | |
279 | impl<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 | |
289 | impl<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. |
310 | pub(crate) trait TagProducer { |
311 | type Tag; |
312 | |
313 | /// Get the next tag. |
314 | fn next_tag(&mut self) -> Self::Tag; |
315 | } |
316 | |
317 | impl<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`]. |
359 | pub 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 | |
544 | impl<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 | |
553 | macro_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 | |
573 | impl_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 ] |
577 | pub(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 | |
607 | mod __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 | |