pub struct Event<T = ()> { /* private fields */ }
Expand description
A synchronization primitive for notifying async tasks and threads.
Listeners can be registered using Event::listen()
. There are two ways to notify listeners:
Event::notify()
notifies a number of listeners.Event::notify_additional()
notifies a number of previously unnotified listeners.
If there are no active listeners at the time a notification is sent, it simply gets lost.
There are two ways for a listener to wait for a notification:
- In an asynchronous manner using
.await
. - In a blocking manner by calling
EventListener::wait()
on it.
If a notified listener is dropped without receiving a notification, dropping will notify another active listener. Whether one additional listener will be notified depends on what kind of notification was delivered.
Listeners are registered and notified in the first-in first-out fashion, ensuring fairness.
Implementations§
source§impl<T> Event<T>
impl<T> Event<T>
sourcepub const fn with_tag() -> Self
pub const fn with_tag() -> Self
Creates a new Event
with a tag type.
Tagging cannot be implemented efficiently on no_std
, so this is only available when the
std
feature is enabled.
§Examples
use event_listener::Event;
let event = Event::<usize>::with_tag();
sourcepub fn is_notified(&self) -> bool
pub fn is_notified(&self) -> bool
Tell whether any listeners are currently notified.
§Examples
use event_listener::{Event, Listener};
let event = Event::new();
let listener = event.listen();
assert!(!event.is_notified());
event.notify(1);
assert!(event.is_notified());
sourcepub fn listen(&self) -> EventListener<T> ⓘ
pub fn listen(&self) -> EventListener<T> ⓘ
Returns a guard listening for a notification.
This method emits a SeqCst
fence after registering a listener. For now, this method
is an alias for calling [EventListener::new()
], pinning it to the heap, and then
inserting it into a list.
§Examples
use event_listener::Event;
let event = Event::new();
let listener = event.listen();
§Caveats
The above example is equivalent to this code:
use event_listener::{Event, EventListener};
let event = Event::new();
let mut listener = Box::pin(EventListener::new());
listener.listen(&event);
It creates a new listener, pins it to the heap, and inserts it into the linked list
of listeners. While this type of usage is simple, it may be desired to eliminate this
heap allocation. In this case, consider using the [EventListener::new
] constructor
directly, which allows for greater control over where the EventListener
is
allocated. However, users of this new
method must be careful to ensure that the
EventListener
is listen
ing before waiting on it; panics may occur otherwise.
sourcepub fn notify(&self, notify: impl IntoNotification<Tag = T>) -> usize
pub fn notify(&self, notify: impl IntoNotification<Tag = T>) -> usize
Notifies a number of active listeners.
The number is allowed to be zero or exceed the current number of listeners.
The Notification
trait is used to define what kind of notification is delivered.
The default implementation (implemented on usize
) is a notification that only notifies
at least the specified number of listeners.
In certain cases, this function emits a SeqCst
fence before notifying listeners.
This function returns the number of EventListener
s that were notified by this call.
§Caveats
If the std
feature is disabled, the notification will be delayed under high contention,
such as when another thread is taking a while to notify
the event. In this circumstance,
this function will return 0
instead of the number of listeners actually notified. Therefore
if the std
feature is disabled the return value of this function should not be relied upon
for soundness and should be used only as a hint.
If the std
feature is enabled, no spurious returns are possible, since the std
implementation uses system locking primitives to ensure there is no unavoidable
contention.
§Examples
Use the default notification strategy:
use event_listener::Event;
let event = Event::new();
// This notification gets lost because there are no listeners.
event.notify(1);
let listener1 = event.listen();
let listener2 = event.listen();
let listener3 = event.listen();
// Notifies two listeners.
//
// Listener queueing is fair, which means `listener1` and `listener2`
// get notified here since they start listening before `listener3`.
event.notify(2);
Notify without emitting a SeqCst
fence. This uses the relaxed
notification strategy.
This is equivalent to calling Event::notify_relaxed()
.
use event_listener::{IntoNotification, Event};
use std::sync::atomic::{self, Ordering};
let event = Event::new();
// This notification gets lost because there are no listeners.
event.notify(1.relaxed());
let listener1 = event.listen();
let listener2 = event.listen();
let listener3 = event.listen();
// We should emit a fence manually when using relaxed notifications.
atomic::fence(Ordering::SeqCst);
// Notifies two listeners.
//
// Listener queueing is fair, which means `listener1` and `listener2`
// get notified here since they start listening before `listener3`.
event.notify(2.relaxed());
Notify additional listeners. In contrast to Event::notify()
, this method will notify n
additional listeners that were previously unnotified. This uses the additional
notification strategy. This is equivalent to calling Event::notify_additional()
.
use event_listener::{IntoNotification, Event};
let event = Event::new();
// This notification gets lost because there are no listeners.
event.notify(1.additional());
let listener1 = event.listen();
let listener2 = event.listen();
let listener3 = event.listen();
// Notifies two listeners.
//
// Listener queueing is fair, which means `listener1` and `listener2`
// get notified here since they start listening before `listener3`.
event.notify(1.additional());
event.notify(1.additional());
Notifies with the additional
and relaxed
strategies at the same time. This is
equivalent to calling Event::notify_additional_relaxed()
.
use event_listener::{IntoNotification, Event};
use std::sync::atomic::{self, Ordering};
let event = Event::new();
// This notification gets lost because there are no listeners.
event.notify(1.additional().relaxed());
let listener1 = event.listen();
let listener2 = event.listen();
let listener3 = event.listen();
// We should emit a fence manually when using relaxed notifications.
atomic::fence(Ordering::SeqCst);
// Notifies two listeners.
//
// Listener queueing is fair, which means `listener1` and `listener2`
// get notified here since they start listening before `listener3`.
event.notify(1.additional().relaxed());
event.notify(1.additional().relaxed());
sourcepub fn total_listeners(&self) -> usize
pub fn total_listeners(&self) -> usize
Get the number of listeners currently listening to this Event
.
This call returns the number of EventListener
s that are currently listening to
this event. It does this by acquiring the internal event lock and reading the listener
count. Therefore it is only available for std
-enabled platforms.
§Caveats
This function returns just a snapshot of the number of listeners at this point in time. Due to the nature of multi-threaded CPUs, it is possible that this number will be inaccurate by the time that this function returns.
It is possible for the actual number to change at any point. Therefore, the number should only ever be used as a hint.
§Examples
use event_listener::Event;
let event = Event::new();
assert_eq!(event.total_listeners(), 0);
let listener1 = event.listen();
assert_eq!(event.total_listeners(), 1);
let listener2 = event.listen();
assert_eq!(event.total_listeners(), 2);
drop(listener1);
drop(listener2);
assert_eq!(event.total_listeners(), 0);
source§impl Event<()>
impl Event<()>
sourcepub fn notify_relaxed(&self, n: usize) -> usize
pub fn notify_relaxed(&self, n: usize) -> usize
Notifies a number of active listeners without emitting a SeqCst
fence.
The number is allowed to be zero or exceed the current number of listeners.
In contrast to Event::notify_additional()
, this method only makes sure at least n
listeners among the active ones are notified.
Unlike Event::notify()
, this method does not emit a SeqCst
fence.
This method only works for untagged events. In other cases, it is recommended to instead
use Event::notify()
like so:
use event_listener::{IntoNotification, Event};
let event = Event::new();
// Old way:
event.notify_relaxed(1);
// New way:
event.notify(1.relaxed());
§Examples
use event_listener::{Event, IntoNotification};
use std::sync::atomic::{self, Ordering};
let event = Event::new();
// This notification gets lost because there are no listeners.
event.notify_relaxed(1);
let listener1 = event.listen();
let listener2 = event.listen();
let listener3 = event.listen();
// We should emit a fence manually when using relaxed notifications.
atomic::fence(Ordering::SeqCst);
// Notifies two listeners.
//
// Listener queueing is fair, which means `listener1` and `listener2`
// get notified here since they start listening before `listener3`.
event.notify_relaxed(2);
sourcepub fn notify_additional(&self, n: usize) -> usize
pub fn notify_additional(&self, n: usize) -> usize
Notifies a number of active and still unnotified listeners.
The number is allowed to be zero or exceed the current number of listeners.
In contrast to Event::notify()
, this method will notify n
additional listeners that
were previously unnotified.
This method emits a SeqCst
fence before notifying listeners.
This method only works for untagged events. In other cases, it is recommended to instead
use Event::notify()
like so:
use event_listener::{IntoNotification, Event};
let event = Event::new();
// Old way:
event.notify_additional(1);
// New way:
event.notify(1.additional());
§Examples
use event_listener::Event;
let event = Event::new();
// This notification gets lost because there are no listeners.
event.notify_additional(1);
let listener1 = event.listen();
let listener2 = event.listen();
let listener3 = event.listen();
// Notifies two listeners.
//
// Listener queueing is fair, which means `listener1` and `listener2`
// get notified here since they start listening before `listener3`.
event.notify_additional(1);
event.notify_additional(1);
sourcepub fn notify_additional_relaxed(&self, n: usize) -> usize
pub fn notify_additional_relaxed(&self, n: usize) -> usize
Notifies a number of active and still unnotified listeners without emitting a SeqCst
fence.
The number is allowed to be zero or exceed the current number of listeners.
In contrast to Event::notify()
, this method will notify n
additional listeners that
were previously unnotified.
Unlike Event::notify_additional()
, this method does not emit a SeqCst
fence.
This method only works for untagged events. In other cases, it is recommended to instead
use Event::notify()
like so:
use event_listener::{IntoNotification, Event};
let event = Event::new();
// Old way:
event.notify_additional_relaxed(1);
// New way:
event.notify(1.additional().relaxed());
§Examples
use event_listener::Event;
use std::sync::atomic::{self, Ordering};
let event = Event::new();
// This notification gets lost because there are no listeners.
event.notify(1);
let listener1 = event.listen();
let listener2 = event.listen();
let listener3 = event.listen();
// We should emit a fence manually when using relaxed notifications.
atomic::fence(Ordering::SeqCst);
// Notifies two listeners.
//
// Listener queueing is fair, which means `listener1` and `listener2`
// get notified here since they start listening before `listener3`.
event.notify_additional_relaxed(1);
event.notify_additional_relaxed(1);