Crate flo_binding[−][src]
Bindings
This library provides a mechansim for designing applications with a data-driven control flow. This is essentially the paradigm found in spreadsheets, where a formula will update automatically if its dependencies update. This is a convenient way to express how a user interface updates, as it eliminates the need to describe and manage events.
A simple binding can be created using let binding = bind(X)
. This creates
a simple mutable binding that can be updated using binding.set(Y)
or
retrieved using binding.get()
.
This value can be monitored using when_changed
, as in
let lifetime = binding.when_changed(notify(|| println!("Changed!")))
.
The lifetime value returned can be used to stop the notifications from firing.
Unless lifetime.keep_alive()
is called, it will also stop the notifications
once it goes out of scope.
So far, this is very similar to traditional observables. What makes bindings different is the idea that they can be computed as well. Here's an example:
let mut number = bind(1); let number_clone = number.clone(); let plusone = computed(move || number_clone.get() + 1); let mut lifetime = plusone.when_changed(notify(|| println!("Changed!"))); println!("{}", plusone.get()); // 2 number.set(2); // 'Changed!' println!("{}", plusone.get()); // 3 lifetime.done(); number.set(3); // Lifetime is done, so no notification println!("{}", plusone.get()); // 4
Computed values can be as complicated as necessary, and will notify the specified function whenever their value changes.
Cloning a binding creates a new binding that references the same location.
This makes it easier to pass bindings into closures (though still a
little awkward as Rust doesn't really have a shorthand way of doing this
for philosophical reasons). They're similar in behaviour to an
Arc<Mutex<X>>
object in this respect (and never really immutable given
that cloning them creates a mutable object)
Computed bindings as demonstrated above are 'lazy'. They don't know their own value until they have been evaluated after a change (and start in this 'uncertain' state), so they will not notify of value changes until they have been read at least once and will not notify again until they have been read again. Reading the value from within the notification is possible but in general the idea is to queue up an update for later: being lazy in this way prevents repeated computations of intermediate values when many values are being updated. Knock-on effects are all accounted for, so if a future update is queued, it won't trigger further notifications.
Modules
binding_context |
Structs
BindRef |
A |
Binding |
Represents a thread-safe, sharable binding |
ComputedBinding |
Represents a binding to a value that is computed by a function |
FollowStream |
Stream that follows the values of a binding |
StreamBinding |
Binding that represents the result of |
Traits
Bound |
Trait implemented by something that is bound to a value |
Changeable |
Trait implemented by items that can notify something when they're changed |
MutableBound |
Trait implemented by something that is bound to a value that can be changed |
Notifiable |
Trait implemented by items with dependencies that need to be notified when they have changed |
Releasable |
Trait implemented by an object that can be released: for example to stop performing an action when it's no longer required. |
Functions
bind |
Creates a simple bound value with the specified initial value |
bind_stream |
Uses a stream to update a binding |
computed |
Creates a computed value that tracks bindings accessed during the function call and marks itself as changed when any of these dependencies also change |
follow |
Creates a stream from a binding |
notify |
Creates a notifiable reference from a function |