Listener

Trait Listener 

Source
pub trait Listener<M>: Debug {
    // Required method
    fn receive(&self, messages: &[M]) -> bool;

    // Provided methods
    fn filter<MI, F>(self, function: F) -> Filter<F, Self, 1>
       where Self: Sized,
             F: for<'a> Fn(&'a MI) -> Option<M> { ... }
    fn gate(self) -> (Gate, GateListener<Self>)
       where Self: Sized { ... }
}
Expand description

A receiver of messages (typically from something implementing Listen) which can indicate when it is no longer interested in them (typically because the associated recipient has been dropped).

Listeners are typically used in trait object form, which may be created via the IntoListener trait in addition to the usual coercions; this is done automatically by Listen, but calling .into_listener() earlier may be useful to minimize the number of separately allocated clones of the listener when the same listener is to be registered with multiple message sources.

If you are implementing Listener, note the requirements set out in Listener::receive(). Instead of writing new implementations, consider the following alternatives when you need a listener:

  • Use an existing implementation such as FlagListener from Flag.
  • Implement Store instead, and use StoreLock instead. StoreLock provides the weak reference and mutex that are needed in the most common kind of use of Listener.
  • Implement StoreRef for an interior mutable data structure, then wrap it in Weak to make it a listener. (This works via via the built-in implementation impl<T: StoreRef<M>, M> Listener<M> for Weak<T>).

§Generic parameters

  • M is the type of message that can be received.

Required Methods§

Source

fn receive(&self, messages: &[M]) -> bool

Process and store the given series of messages.

Returns true if the listener is still interested in further messages (“alive”), and false if it should be dropped because these and all future messages would have no observable effect. A call of the form .receive(&[]) may be performed to query aliveness without delivering any messages.

§Requirements on implementors
  • Messages are provided in a batch for efficiency of dispatch. Each message in the provided slice should be processed exactly the same as if it were the only message provided. If the slice is empty, there should be no observable effect.

  • Do not panic under any possible incoming message stream, in order to ensure the sender’s other work is not interfered with. For example, if the listener accesses a poisoned mutex, it should do nothing or clear the poison, rather than panicking.

  • Do not acquire any locks except ones which are used only for the state of the listener itself.

  • Do not perform any blocking operation except for such locks.

  • Do not access thread-local state, since this may be called from whichever thread(s) the sender is using.

§Advice for implementors

Note that, since this method takes &Self, a Listener must use interior mutability of some variety to store the message. As a Listener may be called from various contexts, and in particular while the sender is still performing its work, that mutability should in general be limited to setting dirty flags or inserting into message queues — not attempting to directly perform further game state changes, and particularly not taking any locks that are not solely used by the Listener and its destination, as that could result in deadlock.

The typical pattern is for a listener to contain a Weak<Mutex<...>> or similar multiply-owned mutable structure to aggregate incoming messages, which will then be read and cleared by a later task; see StoreLock for assistance in implementing this pattern.

Note that a Notifier might call .receive(&[]) at any time, particularly when listeners are added. Be careful not to cause a deadlock in this case; it may be necessary to avoid locking in the case where there are no messages to be delivered.

Provided Methods§

Source

fn filter<MI, F>(self, function: F) -> Filter<F, Self, 1>
where Self: Sized, F: for<'a> Fn(&'a MI) -> Option<M>,

Wraps self so to apply a map/filter function (similar to Iterator::filter_map()) to incoming messages, to discard uninteresting messages and transform interesting ones.

Note: By default, this filter breaks up all message batching into batches of 1. In order to avoid this and have more efficient message delivery, use Filter::with_stack_buffer(). This is unnecessary if size_of::<M>() == 0; the buffer is automatically unbounded in that case.

§Example
use nosy::{unsync::Notifier, Flag, Listen as _, Listener as _};

let notifier = Notifier::new();
let flag = Flag::new(false);
notifier.listen(flag.listener().filter(|&msg: &i32| {
    if msg >= 0 {
        Some(())
    } else {
        None
    }
}));

// This message is filtered out.
notifier.notify(&-1);
assert_eq!(flag.get_and_clear(), false);

// This message is passed through:
notifier.notify(&2);
assert_eq!(flag.get_and_clear(), true);
Source

fn gate(self) -> (Gate, GateListener<Self>)
where Self: Sized,

Wraps self to pass messages only until the returned Gate, and any clones of it, are dropped.

This may be used to stop forwarding messages when a dependency no longer exists.

use nosy::{Listen as _, Listener as _};

let log = nosy::Log::new();
let (gate, gated) = log.listener().gate();
gated.receive(&["kept1"]);
assert_eq!(log.drain(), vec!["kept1"]);
gated.receive(&["kept2"]);
drop(gate);
gated.receive(&["discarded"]);
assert_eq!(log.drain(), vec!["kept2"]);

Implementations on Foreign Types§

Source§

impl<M, L1, L2> Listener<M> for (L1, L2)
where L1: Listener<M>, L2: Listener<M>,

Tuples of listeners may be used to distribute messages to multiple listeners with static dispatch.

Source§

fn receive(&self, messages: &[M]) -> bool

Source§

impl<T: ?Sized + StoreRef<M> + Debug, M> Listener<M> for Weak<T>

A weak reference to a StoreRef acts as a Listener.

Source§

fn receive(&self, messages: &[M]) -> bool

Source§

impl<T: ?Sized + StoreRef<M> + Debug, M> Listener<M> for Weak<T>

A weak reference to a StoreRef acts as a Listener.

Source§

fn receive(&self, messages: &[M]) -> bool

Implementors§

Source§

impl<M> Listener<M> for WakeFlagListener

Source§

impl<M> Listener<M> for FlagListener

Source§

impl<M> Listener<M> for NullListener

Source§

impl<M> Listener<M> for nosy::sync::DynListener<M>

Source§

impl<M> Listener<M> for nosy::unsync::DynListener<M>

Source§

impl<M, L> Listener<M> for GateListener<L>
where L: Listener<M>,

Source§

impl<M, L: Listener<M>> Listener<M> for NotifierForwarder<M, L>

Source§

impl<M, T: ?Sized + Store<M> + Send> Listener<M> for StoreLockListener<T>

Source§

impl<M: Clone + Send + Sync> Listener<M> for LogListener<M>

Source§

impl<MI, MO, F, T, const BATCH: usize> Listener<MI> for Filter<F, T, BATCH>
where F: Fn(&MI) -> Option<MO> + Send + Sync, T: Listener<MO>,