event_listener

Struct Event

Source
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:

  1. Event::notify() notifies a number of listeners.
  2. 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:

  1. In an asynchronous manner using .await.
  2. 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>

Source

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();
Source

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());
Source

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 listening before waiting on it; panics may occur otherwise.

Source

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 EventListeners 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());
Source

pub fn total_listeners(&self) -> usize

Get the number of listeners currently listening to this Event.

This call returns the number of EventListeners 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<()>

Source

pub const fn new() -> Self

Creates a new Event.

§Examples
use event_listener::Event;

let event = Event::new();
Source

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);
Source

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);
Source

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);

Trait Implementations§

Source§

impl<T> Debug for Event<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Event

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<T> Drop for Event<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T> RefUnwindSafe for Event<T>

Source§

impl<T: Send> Send for Event<T>

Source§

impl<T: Send> Sync for Event<T>

Source§

impl<T> UnwindSafe for Event<T>

Auto Trait Implementations§

§

impl<T = ()> !Freeze for Event<T>

§

impl<T> Unpin for Event<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.