pub trait FromListener<L: Listener<M>, M>: Listener<M> {
// Required method
fn from_listener(listener: L) -> Self;
}Expand description
Conversion from a specific listener type to a more general listener type, such as a trait object.
This trait is typically used via calling Listen::listen(), or an IntoListener bound
on a function’s parameter, to convert listeners of the provided type into a more common type
that can be stored in a Notifier’s listener set.
§Generic parameters
Selfis the listener type being converted to.Lis the listener type being converted from.Mis the type of message accepted by the listener.
§When to implement FromListener
There are two kinds of implementations of FromListener:
-
Conversion to trait objects, like
sync::DynListenerandunsync::DynListener, or enums. You would write such an implementation if you are using a custom type for your type-erased listeners (e.g. to add more required traits to allow more inspection of the listeners). -
Reflexive implementations, allowing the use of a
Notifierthat accepts only one type of listener and does no dynamic dispatch. You may write such an implementation,impl FromListener<MyListener, MyMsg> for MyListener, whenever you implementListener.Unfortunately, we cannot provide a blanket implementation of this type,
impl<L: Listener<M>, M> FromListener<L, M> for L, because it would conflict with the other kind of implementation.
§Example implementation
Suppose that you want to use only Flag and
WakeFlag listeners,
perhaps because they use atomic operations and no custom code or locks.
A custom implementation of FromListener can offer this restriction, and
potential performance improvement by avoiding indirection and allocation:
use nosy::Listen as _;
/// A non-boxing type for all `Flag` listeners and no other kinds of listener.
#[derive(Debug)]
enum AnyFlag {
NoWake(nosy::FlagListener),
Wake(nosy::future::WakeFlagListener),
}
// Dispatches to the listeners in each variant.
impl<M> nosy::Listener<M> for AnyFlag {
fn receive(&self, messages: &[M]) -> bool {
match self {
Self::NoWake(l) => l.receive(messages),
Self::Wake(l) => l.receive(messages),
}
}
}
// Whenever possible, provide a reflexive, idempotent implementation,
// so that an already-converted listener can still be passed to `listen()` methods.
impl<M> nosy::FromListener<AnyFlag, M> for AnyFlag {
fn from_listener(listener: AnyFlag) -> AnyFlag {
listener
}
}
// The actual work of conversion.
impl<M> nosy::FromListener<nosy::FlagListener, M> for AnyFlag {
fn from_listener(listener: nosy::FlagListener) -> AnyFlag {
AnyFlag::NoWake(listener)
}
}
impl<M> nosy::FromListener<nosy::future::WakeFlagListener, M> for AnyFlag {
fn from_listener(listener: nosy::future::WakeFlagListener) -> AnyFlag {
AnyFlag::Wake(listener)
}
}
fn example_usage(notifier: &nosy::Notifier<(), AnyFlag>) {
notifier.listen(nosy::Flag::new(false).listener());
}§Why not From?
The reason we define this trait instead of using the standard From trait is that coherence
would prohibit providing the needed blanket implementations — we cannot write
impl<L, M> From<L> for nosy::unsync::DynListener<M>
where
L: nosy::Listener<M>,because L is an uncovered type parameter and DynListener
is not a local type, and
even if that were not the case, this implementation would conflict with
the blanket implementation impl<T> From<T> for T.
Required Methods§
Sourcefn from_listener(listener: L) -> Self
fn from_listener(listener: L) -> Self
Convert the given Listener into Self.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.