pub trait Source: Listen<Msg = ()> + Debug {
type Value;
// Required method
fn get(&self) -> Self::Value;
// Provided methods
fn map<F, O>(self, function: F) -> Map<Self, F>
where Self: Sized,
F: Fn(Self::Value) -> O { ... }
fn flatten(self) -> Flatten<Self>
where Self: Sized,
Self::Value: Source + Clone,
Self::Listener: FromListener<OuterListener<Self>, ()>,
<Self::Value as Listen>::Listener: FromListener<InnerListener<Self>, ()> { ... }
}Expand description
Access to a value that might change and notifications when it does.
The change notifications given are of type (); they do not allow access to the new value.
This is an unfortunate necessity to allow sources to deliver notifications
after the value has changed (i.e. while not holding any lock) without also needing a clone
of, or reference-counted pointer to, the value.
(Listeners are, as always, encouraged not to do significant work,
so, while a listener could try calling Source::get() immediately,
this is not the intended architecture and is not guaranteed to work.)
If a Source is known to be in a state such that its value will never change again,
then it should drop all of its current and future listeners.
This may typically be accomplished through Notifier::close().
The type aliases sync::DynSource
and unsync::DynSource are available for type-erased Sources
with type-erased Listeners. If you want a value and don’t care about the type of the source
it comes from, use them.
Additional traits sources may implement:
- They should, but are not required to, implement
Clone; if they do, all clones should have identical future behavior (values returned and messages sent). - They should implement
fmt::Debugin a way which identifies the source rather than only its current value, if this is possible possible without printing memory addresses or other non-deterministic information. - They should implement
fmt::Pointerto print an address or other information which uniquely identifies the source, if possible.
Required Associated Types§
Sourcetype Value
type Value
The type of value which can be obtained from this source.
This type should usually be clonable (because in any case, arbitrary copies of it
can be obtained from Source::get()), but this is not required.
Required Methods§
Provided Methods§
Sourcefn map<F, O>(self, function: F) -> Map<Self, F>
fn map<F, O>(self, function: F) -> Map<Self, F>
Takes a function and produces a Source which applies that function to the values of
self.
§Caveats
Note that the function is called every time get() is called, and that
change notifications will be forwarded regardless of whether the mapped output changed;
there is no caching.
Therefore, it is important that the function should be cheap, and if it is likely that the
output value will change less often than the input value, then a different approach
should be used.
§Example
use nosy::{unsync::Cell, Source as _};
let cell: Cell<i32> = Cell::new(1);
let source = cell.as_source().map(|value| value * 100);
assert_eq!(source.get(), 100);
cell.set(2);
assert_eq!(source.get(), 200);Sourcefn flatten(self) -> Flatten<Self>
fn flatten(self) -> Flatten<Self>
Converts a source of sources of some value into a source of that value.
§Caveats
The current implementation of Flatten uses an internal mutex.
This mutex is locked while Flatten::get() is called, and while it is locked,
<Self::Value as Clone>::clone() may be called.
Therefore, if that clone() attempts to acquire a lock on something
locked by the caller of Flatten::get(), a deadlock would occur.
This should generally not be a risk because cloning most Sources should be purely a
reference count update; you can enforce this by making sure that Self::Value
is some variety of Arc, such as sync::DynSource.
§Example
use std::sync::Arc;
use nosy::{unsync::{Cell, DynSource}, Source as _};
let cell_inner_1: Cell<i32> = Cell::new(100);
let cell_inner_2: Cell<i32> = Cell::new(200);
let cell_outer: Cell<DynSource<i32>> = Cell::new(cell_inner_1.as_source());
let flattened_source: DynSource<i32> = Arc::new(cell_outer.as_source().flatten());
assert_eq!(flattened_source.get(), 100);
cell_inner_1.set(101);
assert_eq!(flattened_source.get(), 101);
cell_outer.set(cell_inner_2.as_source());
assert_eq!(flattened_source.get(), 200);
cell_inner_2.set(201);
assert_eq!(flattened_source.get(), 201);