/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Data binding types are used to implement dynamic behaviors in UIs. [`Event`] is the primitive //! type underlying most others. [Properties](Property) are what should usually be used in UI //! models, since they have `From` impls allowing different binding behaviors to be set.
use std::cell::RefCell; use std::rc::Rc;
/// An event which can have multiple subscribers. /// /// The type parameter is the payload of the event. pubstruct Event<T> {
subscribers: Rc<RefCell<Vec<Box<dynFn(&T)>>>>,
}
impl<T> Event<T> { /// Add a callback for when the event is fired. pubfn subscribe<F>(&self, f: F) where
F: Fn(&T) + 'static,
{ self.subscribers.borrow_mut().push(Box::new(f));
}
/// Fire the event with the given payload. pubfn fire(&self, payload: &T) { for f inself.subscribers.borrow().iter() {
f(payload);
}
}
}
/// A synchronized runtime value. /// /// Consumers can subscribe to change events on the value. Change events are fired when /// `borrow_mut()` references are dropped. #[derive(Default)] pubstruct Synchronized<T> {
inner: Rc<SynchronizedInner<T>>,
}
/// Mutably borrow a value's data. /// /// When the mutable reference is dropped, a change event is fired. pubfn borrow_mut(&self) -> ValueRefMut<'_, T> {
ValueRefMut {
value: std::mem::ManuallyDrop::new(self.inner.current.borrow_mut()),
inner: &self.inner,
}
}
/// Subscribe to change events in the value. pubfn on_change<F: Fn(&T) + 'static>(&self, f: F) { self.inner.change.subscribe(f);
}
/// Update another synchronized value when this one changes. pubfn update_on_change<U: 'static, F: Fn(&T) -> U + 'static>(
&self,
other: &Synchronized<U>,
f: F,
) { let other = other.clone(); self.on_change(move |val| {
*other.borrow_mut() = f(val);
});
}
/// Immediately call the closure on the current value and call it whenever the value changes. pubfn map_with<F: Fn(&T) + 'static>(&self, f: F) { // Hold the borrow to guarantee the value doesn't change until we are subscribed (just as a // measure of extra sanity; this should never occur). let borrow = self.borrow();
f(&*borrow); self.on_change(f);
}
/// Create a new synchronized value which will update when this one changes. pubfn mapped<U: 'static, F: Fn(&T) -> U + 'static>(&self, f: F) -> Synchronized<U> { let s = Synchronized::new(f(&*self.borrow())); self.update_on_change(&s, f);
s
}
pubfn join<A: 'static, B: 'static, F: Fn(&A, &B) -> T + Clone + 'static>(
a: &Synchronized<A>,
b: &Synchronized<B>,
f: F,
) -> Self where
T: 'static,
{ let s = Synchronized::new(f(&*a.borrow(), &*b.borrow())); let update = cc! { (a,b,s) move || {
*s.borrow_mut() = f(&*a.borrow(), &*b.borrow());
}};
a.on_change(cc! { (update) move |_| update()});
b.on_change(move |_| update());
s
}
}
/// A runtime value that can be fetched on-demand (read-only). /// /// Consumers call [`read`] or [`get`] to retrieve the value, while producers call [`register`] to /// set the function which is called to retrieve the value. This is of most use for things like /// editable text strings, where it would be unnecessarily expensive to e.g. update a /// `Synchronized` property as the text string is changed (debouncing could be used, but if change /// notification isn't needed then it's still unnecessary). pubstruct OnDemand<T> {
get: Rc<RefCell<Option<Box<dynFn(&mut T) + 'static>>>>,
}
impl<T> OnDemand<T> { /// Reads the current value. pubfn read(&self, value: &mut T) { match &*self.get.borrow() {
None => { // The test UI doesn't always register OnDemand getters (only on a per-test basis), // so don't panic otherwise the tests will fail unnecessarily. #[cfg(not(test))]
panic!("OnDemand not registered by renderer")
}
Some(f) => f(value),
}
}
/// Get a copy of the current value. pubfn get(&self) -> T where
T: Default,
{ letmut r = T::default(); self.read(&mut r);
r
}
/// Register the function to use when getting the value. pubfn register(&self, f: implFn(&mut T) + 'static) {
*self.get.borrow_mut() = Some(Box::new(f));
}
}
/// A UI element property. /// /// Properties support static and dynamic value bindings. /// * `T` can be converted to static bindings. /// * `Synchronized<T>` can be converted to dynamic bindings which will be updated /// bidirectionally. /// * `OnDemand<T>` can be converted to dynamic bindings which can be queried on an as-needed /// basis. #[derive(Clone, Debug)] pubenum Property<T> { Static(T),
Binding(Synchronized<T>),
ReadOnly(OnDemand<T>),
}
/// A mutable Value reference. /// /// When dropped, the Value's change event will fire (_after_ demoting the RefMut to a Ref). pubstruct ValueRefMut<'a, T> {
value: std::mem::ManuallyDrop<std::cell::RefMut<'a, T>>,
inner: &'a SynchronizedInner<T>,
}
impl<T> std::ops::Deref for ValueRefMut<'_, T> { type Target = T;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.