//! Types for storing and interacting with values in Widgets. use std::cell::{Ref, RefCell, RefMut}; use std::collections::HashMap; use std::fmt::{self, Debug, Display}; use std::future::Future; use std::hash::{BuildHasher, Hash}; use std::ops::{Add, AddAssign, Deref, DerefMut, Not}; use std::str::FromStr; use std::sync::{Arc, Weak}; use std::task::{Poll, Waker}; use std::thread::{self, ThreadId}; use std::time::{Duration, Instant}; use ahash::{AHashMap, AHashSet}; use alot::{LotId, Lots}; use intentional::Assert; use kempt::{Map, Sort}; use parking_lot::{Condvar, Mutex, MutexGuard}; use crate::animation::{AnimationHandle, DynamicTransition, IntoAnimate, LinearInterpolate, Spawn}; use crate::context::{self, Trackable, WidgetContext}; use crate::utils::WithClone; use crate::widget::{ MakeWidget, MakeWidgetWithTag, OnceCallback, WidgetId, WidgetInstance, WidgetList, }; use crate::widgets::{Label, Radio, Select, Space, Switcher}; use crate::window::WindowHandle; /// A source of one or more `T` values. pub trait Source { /// Maps the contents with read-only access, providing access to the value's /// [`Generation`]. fn try_map_generational( &self, map: impl FnOnce(DynamicGuard<'_, T, true>) -> R, ) -> Result; /// Maps the contents with read-only access, providing access to the value's /// [`Generation`]. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. fn map_generational(&self, map: impl FnOnce(DynamicGuard<'_, T, true>) -> R) -> R { self.try_map_generational(map).expect("deadlocked") } /// Returns the current generation of the value. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] fn generation(&self) -> Generation { self.map_generational(|g| g.generation()) } /// Maps the contents with read-only access. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. fn map_ref(&self, map: impl FnOnce(&T) -> R) -> R { self.map_generational(|gen| map(&*gen)) } /// Returns a clone of the currently contained value. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] fn get(&self) -> T where T: Clone, { self.map_ref(T::clone) } /// Maps the contents with read-only access. fn try_map_ref(&self, map: impl FnOnce(&T) -> R) -> Result { self.try_map_generational(|gen| map(&*gen)) } /// Returns a clone of the currently contained value. fn try_get(&self) -> Result where T: Clone, { self.try_map_generational(|gen| gen.clone()) } /// Returns a clone of the currently contained value. /// /// `context` will be invalidated when the value is updated. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] fn get_tracking_redraw(&self, context: &WidgetContext<'_>) -> T where T: Clone, Self: Trackable + Sized, { context.redraw_when_changed(self); self.get() } /// Returns a clone of the currently contained value. /// /// `context` will be invalidated when the value is updated. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] fn get_tracking_invalidate(&self, context: &WidgetContext<'_>) -> T where T: Clone, Self: Trackable + Sized, { context.invalidate_when_changed(self); self.get() } /// Attaches `for_each` to this value so that it is invoked each time the /// source's contents are updated. /// /// `for_each` will not be invoked with the currently stored value. /// /// Returning `Err(CallbackDisconnected)` will prevent the callback from /// being invoked again. fn for_each_subsequent_generational_try(&self, for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(DynamicGuard<'_, T, true>) -> Result<(), CallbackDisconnected> + Send + 'static; /// Attaches `for_each` to this value so that it is invoked each time the /// source's contents are updated. /// /// `for_each` will not be invoked with the currently stored value. fn for_each_subsequent_generational(&self, mut for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(DynamicGuard<'_, T, true>) + Send + 'static, { self.for_each_subsequent_generational_try(move |value| { for_each(value); Ok(()) }) } /// Attaches `for_each` to this value so that it is invoked each time the /// source's contents are updated. /// /// `for_each` will not be invoked with the currently stored value. /// /// Returning `Err(CallbackDisconnected)` will prevent the callback from /// being invoked again. fn for_each_subsequent_try(&self, mut for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(&'a T) -> Result<(), CallbackDisconnected> + Send + 'static, { self.for_each_subsequent_generational_try(move |gen| for_each(&*gen)) } /// Attaches `for_each` to this value so that it is invoked each time the /// source's contents are updated. /// /// `for_each` will not be invoked with the currently stored value. fn for_each_subsequent(&self, mut for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(&'a T) + Send + 'static, { self.for_each_subsequent_try(move |value| { for_each(value); Ok(()) }) } /// Invokes `for_each` with the current contents and each time this source's /// contents are updated. /// /// Returning `Err(CallbackDisconnected)` will prevent the callback from /// being invoked again. fn for_each_generational_try(&self, mut for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(DynamicGuard<'_, T, true>) -> Result<(), CallbackDisconnected> + Send + 'static, { self.map_generational(&mut for_each) .expect("initial for_each invocation failed"); self.for_each_subsequent_generational_try(for_each) } /// Invokes `for_each` with the current contents and each time this source's /// contents are updated. fn for_each_generational(&self, mut for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(DynamicGuard<'_, T, true>) + Send + 'static, { self.for_each_generational_try(move |value| { for_each(value); Ok(()) }) } /// Invokes `for_each` with the current contents and each time this source's /// contents are updated. /// /// Returning `Err(CallbackDisconnected)` will prevent the callback from /// being invoked again. fn for_each_try(&self, mut for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(&'a T) -> Result<(), CallbackDisconnected> + Send + 'static, { self.for_each_generational_try(move |gen| for_each(&*gen)) } /// Invokes `for_each` with the current contents and each time this source's /// contents are updated. fn for_each(&self, mut for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(&'a T) + Send + 'static, { self.for_each_try(move |value| { for_each(value); Ok(()) }) } /// Invokes `for_each` with the current contents and each time this source's /// contents are updated. /// /// Returning `Err(CallbackDisconnected)` will prevent the callback from /// being invoked again. fn for_each_generational_cloned_try(&self, for_each: F) -> CallbackHandle where T: Clone + Send + 'static, F: FnMut(GenerationalValue) -> Result<(), CallbackDisconnected> + Send + 'static; /// Invokes `for_each` with the current contents and each time this source's /// contents are updated. fn for_each_cloned_try(&self, mut for_each: F) -> CallbackHandle where T: Clone + Send + 'static, F: FnMut(T) -> Result<(), CallbackDisconnected> + Send + 'static, { self.for_each_generational_cloned_try(move |gen| for_each(gen.value)) } /// Invokes `for_each` with the current contents and each time this source's /// contents are updated. fn for_each_cloned(&self, mut for_each: F) -> CallbackHandle where T: Clone + Send + 'static, F: FnMut(T) + Send + 'static, { self.for_each_cloned_try(move |value| { for_each(value); Ok(()) }) } /// Returns a new dynamic that contains the updated contents of this dynamic /// at most once every `period`. #[must_use] fn debounced_every(&self, period: Duration) -> Dynamic where T: PartialEq + Clone + Send + Sync + 'static, { let debounced = Dynamic::new(self.get()); let mut debounce = Debounce::new(debounced.clone(), period); let callback = self.for_each_cloned(move |value| debounce.update(value)); debounced.set_source(callback); debounced } /// Returns a new dynamic that contains the updated contents of this dynamic /// delayed by `period`. Each time this value is updated, the delay is /// reset. #[must_use] fn debounced_with_delay(&self, period: Duration) -> Dynamic where T: PartialEq + Clone + Send + Sync + 'static, { let debounced = Dynamic::new(self.get()); let mut debounce = Debounce::new(debounced.clone(), period).extending(); let callback = self.for_each_cloned(move |value| debounce.update(value)); debounced.set_source(callback); debounced } /// Creates a new dynamic value that contains the result of invoking `map` /// each time this value is changed. fn map_each_generational(&self, mut map: F) -> Dynamic where T: Send + 'static, F: for<'a> FnMut(DynamicGuard<'a, T, true>) -> R + Send + 'static, R: PartialEq + Send + 'static, { let mapped = Dynamic::new(self.map_generational(&mut map)); let mapped_weak = mapped.downgrade(); mapped.set_source(self.for_each_generational_try(move |value| { let mapped = mapped_weak.upgrade().ok_or(CallbackDisconnected)?; mapped.set(map(value)); Ok(()) })); mapped } /// Creates a new dynamic value that contains the result of invoking `map` /// each time this value is changed. fn map_each(&self, mut map: F) -> Dynamic where T: Send + 'static, F: for<'a> FnMut(&'a T) -> R + Send + 'static, R: PartialEq + Send + 'static, { self.map_each_generational(move |gen| map(&*gen)) } /// Creates a new dynamic value that contains the result of invoking `map` /// each time this value is changed. fn map_each_cloned(&self, mut map: F) -> Dynamic where T: Clone + Send + 'static, F: FnMut(T) -> R + Send + 'static, R: PartialEq + Send + 'static, { let mapped = Dynamic::new(map(self.get())); let mapped_weak = mapped.downgrade(); mapped.set_source(self.for_each_cloned_try(move |value| { let mapped = mapped_weak.upgrade().ok_or(CallbackDisconnected)?; mapped.set(map(value)); Ok(()) })); mapped } /// Returns a new [`Dynamic`] that contains a clone of each value from /// `self`. /// /// The returned dynamic does not hold a strong reference to `self`, /// ensuring that `self` can be cleaned up even if the returned dynamic /// still exists. fn weak_clone(&self) -> Dynamic where T: Clone + Send + 'static, { let mapped = Dynamic::new(self.get()); let mapped_weak = mapped.downgrade(); mapped.set_source( self.for_each_cloned_try(move |value| { let mapped = mapped_weak.upgrade().ok_or(CallbackDisconnected)?; *mapped.lock() = value.clone(); Ok(()) }) .weak(), ); mapped } /// Returns a new dynamic that is updated using `U::from(T.clone())` each /// time `self` is updated. #[must_use] fn map_each_into(&self) -> Dynamic where U: PartialEq + From + Send + 'static, T: Clone + Send + 'static, { self.map_each(|value| U::from(value.clone())) } /// Returns a new dynamic that is updated using `U::from(&T)` each /// time `self` is updated. #[must_use] fn map_each_to(&self) -> Dynamic where U: PartialEq + for<'a> From<&'a T> + Send + 'static, T: Clone + Send + 'static, { self.map_each(|value| U::from(value)) } } /// A destination for values of type `T`. pub trait Destination { /// Maps the contents with exclusive access. Before returning from this /// function, all observers will be notified that the contents have been /// updated. fn try_map_mut(&self, map: impl FnOnce(Mutable<'_, T>) -> R) -> Result; /// Maps the contents with exclusive access. Before returning from this /// function, all observers will be notified that the contents have been /// updated. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. fn map_mut(&self, map: impl FnOnce(Mutable<'_, T>) -> R) -> R { self.try_map_mut(map).expect("deadlocked") } /// Replaces the contents with `new_value` if `new_value` is different than /// the currently stored value. If the value is updated, the previous /// contents are returned. /// /// /// Before returning from this function, all observers will be notified that /// the contents have been updated. /// /// # Errors /// /// - [`ReplaceError::NoChange`]: Returned when `new_value` is equal to the /// currently stored value. /// - [`ReplaceError::Deadlock`]: Returned when the current thread already /// has exclusive access to the contents of this dynamic. fn try_replace(&self, new_value: T) -> Result> where T: PartialEq, { match self.try_map_mut(|mut value| { if *value == new_value { Err(ReplaceError::NoChange(new_value)) } else { Ok(std::mem::replace(&mut *value, new_value)) } }) { Ok(old) => old, Err(DeadlockError) => Err(ReplaceError::Deadlock), } } /// Replaces the contents with `new_value`, returning the previous contents. /// Before returning from this function, all observers will be notified that /// the contents have been updated. /// /// If the calling thread has exclusive access to the contents of this /// dynamic, this call will return None and the value will not be updated. /// If detecting this is important, use [`Self::try_replace()`]. fn replace(&self, new_value: T) -> Option where T: PartialEq, { self.try_replace(new_value).ok() } /// Stores `new_value` in this dynamic. Before returning from this function, /// all observers will be notified that the contents have been updated. /// /// If the calling thread has exclusive access to the contents of this /// dynamic, this call will return None and the value will not be updated. /// If detecting this is important, use [`Self::try_replace()`]. fn set(&self, new_value: T) where T: PartialEq, { let _old = self.replace(new_value); } /// Replaces the current value with `new_value` if the current value is /// equal to `expected_current`. /// /// Returns `Ok` with the overwritten value upon success. /// /// # Errors /// /// - [`TryCompareSwapError::Deadlock`]: This operation would result in a /// thread deadlock. /// - [`TryCompareSwapError::CurrentValueMismatch`]: The current value did /// not match `expected_current`. The `T` returned is a clone of the /// currently stored value. fn try_compare_swap( &self, expected_current: &T, new_value: T, ) -> Result> where T: Clone + PartialEq, { match self.try_map_mut(|mut value| { if &*value == expected_current { Ok(std::mem::replace(&mut *value, new_value)) } else { Err(TryCompareSwapError::CurrentValueMismatch(value.clone())) } }) { Ok(old) => old, Err(_) => Err(TryCompareSwapError::Deadlock), } } /// Replaces the current value with `new_value` if the current value is /// equal to `expected_current`. /// /// Returns `Ok` with the overwritten value upon success. /// /// # Errors /// /// Returns `Err` with the currently stored value when `expected_current` /// does not match the currently stored value. fn compare_swap(&self, expected_current: &T, new_value: T) -> Result where T: Clone + PartialEq, { match self.try_compare_swap(expected_current, new_value) { Ok(old) => Ok(old), Err(TryCompareSwapError::Deadlock) => unreachable!("deadlocked"), Err(TryCompareSwapError::CurrentValueMismatch(value)) => Err(value), } } /// Updates the value to the result of invoking [`Not`] on the current /// value. This function returns the new value. #[allow(clippy::must_use_candidate)] fn toggle(&self) -> T where T: Not + Clone, { self.map_mut(|mut value| { *value = !value.clone(); value.clone() }) } /// Returns the currently stored value, replacing the current contents with /// `T::default()`. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. fn take(&self) -> T where Self: Source, T: Default, { self.map_mut(|mut value| std::mem::take(&mut *value)) } /// Checks if the currently stored value is different than `T::default()`, /// and if so, returns `Some(self.take())`. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] fn take_if_not_default(&self) -> Option where T: Default + PartialEq, { let default = T::default(); self.map_mut(|mut value| { if *value == default { None } else { Some(std::mem::replace(&mut *value, default)) } }) } } impl Source for Arc> { fn try_map_generational( &self, map: impl FnOnce(DynamicGuard<'_, T, true>) -> R, ) -> Result { let state = self.state()?; Ok(map(DynamicGuard { guard: DynamicOrOwnedGuard::Dynamic(state), accessed_mut: false, prevent_notifications: false, })) } fn for_each_subsequent_generational_try(&self, mut for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(DynamicGuard<'a, T, true>) -> Result<(), CallbackDisconnected> + Send + 'static, { let this = WeakDynamic(Arc::downgrade(self)); dynamic_for_each(self, move || { let this = this.upgrade().ok_or(CallbackDisconnected)?; this.map_generational(&mut for_each)?; Ok(()) }) } fn for_each_generational_cloned_try(&self, mut for_each: F) -> CallbackHandle where T: Clone + Send + 'static, F: FnMut(GenerationalValue) -> Result<(), CallbackDisconnected> + Send + 'static, { let this = WeakDynamic(Arc::downgrade(self)); dynamic_for_each(self, move || { let this = this.upgrade().ok_or(CallbackDisconnected)?; if let Ok(value) = this.try_map_generational(|g| g.guard.clone()) { for_each(value)?; } Ok(()) }) } } impl Source for Dynamic { fn try_map_generational( &self, map: impl FnOnce(DynamicGuard<'_, T, true>) -> R, ) -> Result { self.0.try_map_generational(map) } fn for_each_subsequent_generational_try(&self, for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(DynamicGuard<'_, T, true>) -> Result<(), CallbackDisconnected> + Send + 'static, { self.0.for_each_subsequent_generational_try(for_each) } fn for_each_generational_cloned_try(&self, for_each: F) -> CallbackHandle where T: Clone + Send + 'static, F: FnMut(GenerationalValue) -> Result<(), CallbackDisconnected> + Send + 'static, { self.0.for_each_generational_cloned_try(for_each) } } impl Source for DynamicReader { fn try_map_generational( &self, map: impl FnOnce(DynamicGuard<'_, T, true>) -> R, ) -> Result { self.source.try_map_generational(|generational| { *self.read_generation.lock() = generational.generation(); map(generational) }) } fn for_each_subsequent_generational_try(&self, for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(DynamicGuard<'_, T, true>) -> Result<(), CallbackDisconnected> + Send + 'static, { self.source.for_each_subsequent_generational_try(for_each) } fn for_each_generational_cloned_try(&self, for_each: F) -> CallbackHandle where T: Clone + Send + 'static, F: FnMut(GenerationalValue) -> Result<(), CallbackDisconnected> + Send + 'static, { self.source.for_each_generational_cloned_try(for_each) } } impl Destination for Dynamic { fn try_map_mut(&self, map: impl FnOnce(Mutable<'_, T>) -> R) -> Result { self.0.map_mut(map) } } /// A `mut` reference to `T` that tracks whether the contents have been accessed /// through `DerefMut`. #[derive(Debug)] pub struct Mutable<'a, T> { value: &'a mut T, mutated: Mutated<'a>, } #[derive(Debug)] enum Mutated<'a> { External(&'a mut bool), Ignored, } impl Mutated<'_> { fn set(&mut self, mutated: bool) { match self { Self::External(value) => **value = mutated, Self::Ignored => {} } } } impl Deref for Mutable<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { self.value } } impl DerefMut for Mutable<'_, T> { fn deref_mut(&mut self) -> &mut Self::Target { self.mutated.set(true); self.value } } impl<'a, T> Mutable<'a, T> { /// Creates a new wrapper that sets `mutated` to true when `DerefMut` is /// used to access `value`. #[must_use] pub fn new(value: &'a mut T, mutated: &'a mut bool) -> Self { *mutated = false; Self { value, mutated: Mutated::External(mutated), } } } impl<'a, T> From<&'a mut T> for Mutable<'a, T> { fn from(value: &'a mut T) -> Self { Self { value, mutated: Mutated::Ignored, } } } /// A unique, reactive value. /// /// This type is useful for situations where a value is owned by exactly one /// type but needs to have reactivity through [`Source`]/[`Destination`]. /// /// A [`Dynamic`] utilizes a [`Arc`] + [`Mutex`] to support updating its values /// from multiple threads. This type utilizes a [`RefCell`], preventing it from /// being shared between multiple threads. #[derive(Default)] pub struct Owned { wrapped: RefCell>, callbacks: Arc>, } impl Owned { /// Returns a new reactive value. pub fn new(value: T) -> Self { Self { wrapped: RefCell::new(GenerationalValue { value, generation: Generation::default(), }), callbacks: Arc::default(), } } /// Borrows the contents of this value with read-only access. pub fn borrow(&self) -> OwnedRef<'_, T> { OwnedRef(self.wrapped.borrow()) } /// Borrows the contents of this value with exclusive access. /// /// When the returned type is accessed through [`DerefMut`], all associated /// reactive callbacks will be invoked upon dropping the returned /// [`OwnedMut`]. pub fn borrow_mut(&mut self) -> OwnedMut<'_, T> { OwnedMut { borrowed: self.wrapped.borrow_mut(), accessed_mut: false, owned: self, } } /// Returns the contained value. pub fn into_inner(self) -> T { self.wrapped.into_inner().value } } impl Source for Owned { fn try_map_generational( &self, map: impl FnOnce(DynamicGuard<'_, T, true>) -> R, ) -> Result { Ok(map(DynamicGuard { guard: DynamicOrOwnedGuard::Owned(self.wrapped.borrow_mut()), accessed_mut: false, prevent_notifications: false, })) } fn for_each_subsequent_generational_try(&self, for_each: F) -> CallbackHandle where T: Send + 'static, F: for<'a> FnMut(DynamicGuard<'a, T, true>) -> Result<(), CallbackDisconnected> + Send + 'static, { let mut callbacks = self.callbacks.active.lock(); CallbackHandle(CallbackHandleInner::Single(CallbackHandleData { id: Some(callbacks.push(Box::new(for_each))), owner: None, callbacks: self.callbacks.clone(), })) } fn for_each_generational_cloned_try(&self, mut for_each: F) -> CallbackHandle where T: Clone + Send + 'static, F: FnMut(GenerationalValue) -> Result<(), CallbackDisconnected> + Send + 'static, { self.for_each_generational_try(move |gen| for_each(gen.guard.clone())) } } impl Destination for Owned where T: 'static, { fn try_map_mut(&self, map: impl FnOnce(Mutable<'_, T>) -> R) -> Result { let mut updated = false; let result = map(Mutable::new( &mut self.wrapped.borrow_mut().value, &mut updated, )); if updated { self.callbacks.invoke(&mut &self.wrapped, |wrapped| { DynamicOrOwnedGuard::Owned(wrapped.borrow_mut()) }); } Ok(result) } } #[cfg(feature = "serde")] impl serde::Serialize for Owned where T: serde::Serialize, { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { self.map_ref(|this| this.serialize(serializer)) } } #[cfg(feature = "serde")] impl<'de, T> serde::Deserialize<'de> for Owned where T: serde::Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { T::deserialize(deserializer).map(Self::new) } } /// A read-only reference to the value in an [`Owned`]. pub struct OwnedRef<'a, T>(Ref<'a, GenerationalValue>) where T: 'static; impl Deref for OwnedRef<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.0 } } /// An exclusive reference to the value contained in an [`Owned`]. /// /// This type tracks if the referenced value is accessed through [`DerefMut`]. /// If it is, reactive callbacks associated with the [`Owned`] value will be /// invoked. pub struct OwnedMut<'a, T> where T: 'static, { owned: &'a Owned, borrowed: RefMut<'a, GenerationalValue>, accessed_mut: bool, } impl Deref for OwnedMut<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.borrowed.value } } impl DerefMut for OwnedMut<'_, T> { fn deref_mut(&mut self) -> &mut Self::Target { self.accessed_mut = true; &mut self.borrowed.value } } impl Drop for OwnedMut<'_, T> where T: 'static, { fn drop(&mut self) { if self.accessed_mut { self.owned.callbacks.invoke(&mut self.borrowed, |borrowed| { DynamicOrOwnedGuard::OwnedRef(&mut *borrowed) }); } } } struct OwnedCallbacks { active: Mutex>>>, } impl Default for OwnedCallbacks { fn default() -> Self { Self { active: Mutex::default(), } } } impl OwnedCallbacks where T: 'static, { pub fn invoke<'a, U>( &self, user: &'a mut U, value: impl for<'b> Fn(&'b mut U) -> DynamicOrOwnedGuard<'b, T>, ) { let mut callbacks = self.active.lock(); callbacks.drain_filter(|callback| { callback .updated(DynamicGuard { guard: value(user), accessed_mut: false, prevent_notifications: false, }) .is_err() }); } } impl CallbackCollection for OwnedCallbacks where T: 'static, { fn remove(&self, id: LotId) { self.active.lock().remove(id); } } trait OwnedCallbackFn: Send + 'static { fn updated(&mut self, value: DynamicGuard<'_, T, true>) -> Result<(), CallbackDisconnected>; } impl OwnedCallbackFn for F where F: for<'a> FnMut(DynamicGuard<'a, T, true>) -> Result<(), CallbackDisconnected> + Send + 'static, { fn updated(&mut self, value: DynamicGuard<'_, T, true>) -> Result<(), CallbackDisconnected> { self(value) } } /// An instance of a value that provides APIs to observe and react to its /// contents. pub struct Dynamic(Arc>); impl Dynamic { /// Creates a new instance wrapping `value`. pub fn new(value: T) -> Self { Self(Arc::new(DynamicData { state: Mutex::new(State::new(value)), during_callback_state: Mutex::default(), sync: Condvar::default(), })) } pub(crate) fn as_ptr(&self) -> *const () { Arc::as_ptr(&self.0).cast() } /// Returns a weak reference to this dynamic. /// /// This is powered by [`Arc`]/[`Weak`] and follows the same semantics for /// reference counting. #[must_use] pub fn downgrade(&self) -> WeakDynamic { WeakDynamic::from(self) } /// Returns the number [`Dynamic`]s that point to this same value. /// /// The returned count includes `self`. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] pub fn instances(&self) -> usize { Arc::strong_count(&self.0) - self.readers() } /// Returns the number of [`DynamicReader`]s for this value. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] pub fn readers(&self) -> usize { self.state().expect("deadlocked").readers } /// Returns a new dynamic that has its contents linked with `self` by the /// pair of mapping functions provided. /// /// When the returned dynamic is updated, `r_into_t` will be invoked. This /// function accepts `&R` and can return `T`, or `Option`. If a value is /// produced, `self` will be updated with the new value. /// /// When `self` is updated, `t_into_r` will be invoked. This function /// accepts `&T` and can return `R` or `Option`. If a value is produced, /// the returned dynamic will be updated with the new value. /// /// # Panics /// /// This function panics if calling `t_into_r` with the current contents of /// the Dynamic produces a `None` value. This requirement is only for the /// first invocation, and it is guaranteed to occur before this function /// returns. pub fn linked( &self, mut t_into_r: TIntoR, mut r_into_t: RIntoT, ) -> Dynamic where T: PartialEq + Send + 'static, R: PartialEq + Send + 'static, TIntoRResult: Into> + Send + 'static, RIntoTResult: Into> + Send + 'static, TIntoR: FnMut(&T) -> TIntoRResult + Send + 'static, RIntoT: FnMut(&R) -> RIntoTResult + Send + 'static, { let r = Dynamic::new( self.map_ref(|v| t_into_r(v)) .into() .expect("t_into_r must succeed with the current value"), ); let r_weak = r.downgrade(); r.set_source(self.for_each_try(move |t| { let r = r_weak.upgrade().ok_or(CallbackDisconnected)?; if let Some(update) = t_into_r(t).into() { r.set(update); } Ok(()) })); // The linked dynamic holds a reference to the original, since it's // being created from the original. let t = self.clone(); self.set_source(r.for_each_try(move |r| { if let Some(update) = r_into_t(r).into() { let _result = t.replace(update); } Ok(()) })); r } /// Creates a [linked](Self::linked) dynamic containing a `String`. /// /// When `self` is updated, [`ToString::to_string()`] will be called to /// produce a new string value to store in the returned dynamic. /// /// When the returned dynamic is updated, [`str::parse`](std::str) is called /// to produce a new `T`. If an error is returned, `self` will not be /// updated. Otherwise, `self` will be updated with the produced value. #[must_use] pub fn linked_string(&self) -> Dynamic where T: ToString + FromStr + PartialEq + Send + 'static, { self.linked(ToString::to_string, |s: &String| s.parse().ok()) } /// Sets the current `source` for this dynamic with `source`. /// /// A dynamic can have multiple source callbacks. /// /// This ensures that `source` stays active as long as any clones of `self` /// are alive. pub fn set_source(&self, source: CallbackHandle) { self.state().assert("deadlocked").source_callback += source; } /// Attaches `for_each` to this value so that it is invoked each time the /// value's contents are updated. This function returns `self`. #[must_use] pub fn with_for_each(self, for_each: F) -> Self where T: Send + 'static, F: for<'a> FnMut(&'a T) + Send + 'static, { self.for_each(for_each).persist(); self } /// A helper function that invokes `with_clone` with a clone of self. This /// code may produce slightly more readable code. /// /// ```rust /// use cushy::value::{Dynamic, Source}; /// /// let value = Dynamic::new(1); /// /// // Using with_clone /// value.with_clone(|value| { /// std::thread::spawn(move || { /// println!("{}", value.get()); /// }) /// }); /// /// // Using an explicit clone /// std::thread::spawn({ /// let value = value.clone(); /// move || { /// println!("{}", value.get()); /// } /// }); /// /// println!("{}", value.get()); /// ```` pub fn with_clone(&self, with_clone: impl FnOnce(Self) -> R) -> R { with_clone(self.clone()) } /// Returns a new reference-based reader for this dynamic value. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] pub fn create_reader(&self) -> DynamicReader { self.state().expect("deadlocked").readers += 1; DynamicReader { source: self.0.clone(), read_generation: Mutex::new(self.0.state().expect("deadlocked").wrapped.generation), } } /// Converts this [`Dynamic`] into a reader. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] pub fn into_reader(self) -> DynamicReader { self.create_reader() } /// Returns an exclusive reference to the contents of this dynamic. /// /// This call will block until all other guards for this dynamic have been /// dropped. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] pub fn lock(&self) -> DynamicGuard<'_, T> { self.lock_inner() } /// Returns an exclusive reference to the contents of this dynamic. /// /// This call will block until all other guards for this dynamic have been /// dropped. /// /// # Errors /// /// Returns an error if the current thread already holds a lock to this /// dynamic. pub fn try_lock(&self) -> Result, DeadlockError> { Ok(DynamicGuard { guard: DynamicOrOwnedGuard::Dynamic(self.0.state()?), accessed_mut: false, prevent_notifications: false, }) } fn lock_inner(&self) -> DynamicGuard<'_, T, READONLY> { let mut guard = self.0.state().expect("deadlocked"); // Before allowing a lock, we need to ensure that the current change // callbacks aren't executing. Otherwise, during drop of this guard, if // we notify of changes from a second thread than one set is already // occuring on, both sets of invocations can end up waiting on each // other and deadlocking. By ensuring a single guard and change // callbacks cycle can exist at any one time, we prevent this deadlock. if !READONLY && guard.callbacks.currently_executing.lock().thread.is_some() { let callbacks = guard.callbacks.clone(); guard.unlocked(|| { let current_thread_id = std::thread::current().id(); let mut executing = callbacks.currently_executing.lock(); loop { match &executing.thread { Some(th) if th == ¤t_thread_id => break, None => break, Some(_) => callbacks.sync.wait(&mut executing), }; } }); } DynamicGuard { guard: DynamicOrOwnedGuard::Dynamic(guard), accessed_mut: false, prevent_notifications: false, } } fn state(&self) -> Result, DeadlockError> { self.0.state() } /// Returns a pending transition for this value to `new_value`. pub fn transition_to(&self, new_value: T) -> DynamicTransition where T: LinearInterpolate + Clone + Send + Sync, { DynamicTransition { dynamic: self.clone(), new_value, } } /// Returns a new [`Radio`] that updates this dynamic to `widget_value` when /// pressed. `label` is drawn next to the checkbox and is also clickable to /// select the radio. #[must_use] pub fn new_radio(&self, widget_value: T, label: impl MakeWidget) -> Radio where Self: Clone, // Technically this trait bound isn't necessary, but it prevents trying // to call new_radio on unsupported types. The MakeWidget/Widget // implementations require these bounds (and more). T: Clone + PartialEq, { Radio::new(widget_value, self.clone(), label) } /// Returns a new [`Select`] that updates this dynamic to `widget_value` /// when pressed. `label` is drawn next to the checkbox and is also /// clickable to select the widget. #[must_use] pub fn new_select(&self, widget_value: T, label: impl MakeWidget) -> Select where Self: Clone, // Technically this trait bound isn't necessary, but it prevents trying // to call new_select on unsupported types. The MakeWidget/Widget // implementations require these bounds (and more). T: Clone + PartialEq, { Select::new(widget_value, self.clone(), label) } /// Validates the contents of this dynamic using the `check` function, /// returning a dynamic that contains the validation status. #[must_use] pub fn validate_with(&self, mut check: Valid) -> Dynamic where T: Send + 'static, Valid: for<'a> FnMut(&'a T) -> Result<(), E> + Send + 'static, E: Display, { let validation = Dynamic::new(Validation::None); let callback = self.for_each({ let validation = validation.clone(); move |value| { validation.set(match check(value) { Ok(()) => Validation::Valid, Err(err) => Validation::Invalid(err.to_string()), }); } }); validation.set_source(callback); validation } } #[cfg(feature = "serde")] impl serde::Serialize for Dynamic where T: serde::Serialize, { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { self.map_ref(|this| this.serialize(serializer)) } } #[cfg(feature = "serde")] impl<'de, T> serde::Deserialize<'de> for Dynamic where T: serde::Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { T::deserialize(deserializer).map(Self::new) } } /// An error returned from [`Dynamic::try_compare_swap`]. #[derive(Debug, Clone, Eq, PartialEq)] pub enum TryCompareSwapError { /// The dynamic is already locked for exclusive access by the current /// thread. This operation would result in a deadlock. Deadlock, /// The current value did not match the expected value. This variant's value /// is the value at the time of comparison. CurrentValueMismatch(T), } impl Debug for Dynamic where T: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Debug::fmt(&DebugDynamicData(&self.0), f) } } impl Dynamic { /// Returns a new [`Switcher`] widget whose contents is the value of this /// dynamic. #[must_use] pub fn into_switcher(self) -> Switcher { self.into_reader().into_switcher() } /// Returns a new [`Switcher`] widget whose contents is the value of this /// dynamic. #[must_use] pub fn to_switcher(&self) -> Switcher { self.create_reader().into_switcher() } } impl DynamicReader { /// Returns a new [`Switcher`] widget whose contents is the value of this /// dynamic reader. #[must_use] pub fn into_switcher(self) -> Switcher { Switcher::new(self) } /// Returns a new [`Switcher`] widget whose contents is the value of this /// dynamic reader. #[must_use] pub fn to_switcher(&self) -> Switcher { Switcher::new(self.clone()) } } impl MakeWidgetWithTag for Dynamic { fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance { self.into_switcher().make_with_tag(id) } } impl MakeWidgetWithTag for Dynamic> { fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance { self.map_each(|widget| { widget .as_ref() .map_or_else(|| Space::clear().make_widget(), Clone::clone) }) .make_with_tag(id) } } impl context::sealed::Trackable for Dynamic { fn inner_redraw_when_changed(&self, handle: WindowHandle) { self.0.redraw_when_changed(handle); } fn inner_sync_when_changed(&self, handle: WindowHandle) { self.0.sync_when_changed(handle); } fn inner_invalidate_when_changed(&self, handle: WindowHandle, id: WidgetId) { self.0.invalidate_when_changed(handle, id); } } impl Eq for Dynamic {} impl PartialEq for Dynamic { fn eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.0, &other.0) } } impl Default for Dynamic where T: Default, { fn default() -> Self { Self::new(T::default()) } } impl Clone for Dynamic { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Drop for Dynamic { fn drop(&mut self) { // Ignoring deadlocks here allows complex flows to work properly, and // the only issue is that `on_disconnect` will not fire if during a map // callback on a `DynamicReader` the final reference to the source // `Dynamic`. if let Ok(mut state) = self.state() { if Arc::strong_count(&self.0) == state.readers + 1 { let cleanup = state.cleanup(); drop(state); drop(cleanup); self.0.sync.notify_all(); } } else { // In the event that this is the rare edge case and a reader is // blocking, we want to signal that we've dropped the final // reference. self.0.sync.notify_all(); } } } impl From> for DynamicReader { fn from(value: Dynamic) -> Self { value.create_reader() } } impl From<&str> for Dynamic { fn from(value: &str) -> Self { Dynamic::from(value.to_string()) } } impl From for Dynamic { fn from(value: String) -> Self { Dynamic::new(value) } } struct DynamicMutexGuard<'a, T> { dynamic: &'a DynamicData, guard: MutexGuard<'a, State>, } impl Debug for DynamicMutexGuard<'_, T> where T: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.guard.debug("DynamicMutexGuard", f) } } impl<'a, T> DynamicMutexGuard<'a, T> { fn unlocked(&mut self, while_unlocked: impl FnOnce()) { let previous_state = self.dynamic.during_callback_state.lock().take(); MutexGuard::unlocked(&mut self.guard, while_unlocked); *self.dynamic.during_callback_state.lock() = previous_state; } } impl<'a, T> Drop for DynamicMutexGuard<'a, T> { fn drop(&mut self) { let mut during_state = self.dynamic.during_callback_state.lock(); *during_state = None; drop(during_state); self.dynamic.sync.notify_all(); } } impl<'a, T> Deref for DynamicMutexGuard<'a, T> { type Target = State; fn deref(&self) -> &Self::Target { &self.guard } } impl<'a, T> DerefMut for DynamicMutexGuard<'a, T> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.guard } } #[derive(Debug)] struct LockState { locked_thread: ThreadId, } struct DynamicData { state: Mutex>, during_callback_state: Mutex>, sync: Condvar, } impl DynamicData { fn state(&self) -> Result, DeadlockError> { let mut during_sync = self.during_callback_state.lock(); let current_thread_id = std::thread::current().id(); let guard = loop { match self.state.try_lock() { Some(g) => break g, None => loop { match &*during_sync { Some(state) if state.locked_thread == current_thread_id => { return Err(DeadlockError) } Some(_) => { self.sync.wait(&mut during_sync); } None => break, } }, } }; *during_sync = Some(LockState { locked_thread: current_thread_id, }); Ok(DynamicMutexGuard { dynamic: self, guard, }) } pub fn redraw_when_changed(&self, window: WindowHandle) { let mut state = self.state().expect("deadlocked"); state.invalidation.windows.insert(window, true); } pub fn sync_when_changed(&self, window: WindowHandle) { let mut state = self.state().expect("deadlocked"); state.invalidation.windows.entry(window).or_insert(false); } pub fn invalidate_when_changed(&self, window: WindowHandle, widget: WidgetId) { let mut state = self.state().expect("deadlocked"); state.invalidation.widgets.insert((window, widget)); } pub fn map_mut(&self, map: impl FnOnce(Mutable) -> R) -> Result { let mut state = self.state()?; let (old, callbacks) = { let state = &mut *state; let mut changed = false; let result = map(Mutable::new(&mut state.wrapped.value, &mut changed)); let callbacks = changed.then(|| state.note_changed()); (result, callbacks) }; drop(state); drop(callbacks); self.sync.notify_all(); Ok(old) } } fn dynamic_for_each(this: &Arc>, map: F) -> CallbackHandle where F: for<'a> FnMut() -> Result<(), CallbackDisconnected> + Send + 'static, T: Send + 'static, { let state = this.state().expect("deadlocked"); let mut data = state.callbacks.callbacks.lock(); CallbackHandle(CallbackHandleInner::Single(CallbackHandleData { id: Some(data.callbacks.push(Box::new(map))), owner: Some(this.clone()), callbacks: state.callbacks.clone(), })) } /// A callback function is no longer connected to its source. #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub struct CallbackDisconnected; struct DebugDynamicData<'a, T>(&'a Arc>); impl Debug for DebugDynamicData<'_, T> where T: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0.state() { Ok(state) => state.debug("Dynamic", f), Err(_) => f.debug_tuple("Dynamic").field(&"").finish(), } } } /// An error occurred while updating a value in a [`Dynamic`]. pub enum ReplaceError { /// The value was already equal to the one set. NoChange(T), /// The current thread already has exclusive access to this dynamic. Deadlock, } /// A deadlock occurred accessing a [`Dynamic`]. /// /// Currently Cushy is only able to detect deadlocks where a single thread tries /// to lock the same [`Dynamic`] multiple times. #[derive(Debug)] pub struct DeadlockError; impl std::error::Error for DeadlockError {} impl Display for DeadlockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("a deadlock was detected") } } trait CallbackCollection: Send + Sync + 'static { fn remove(&self, id: LotId); } /// A handle to a callback installed on a [`Dynamic`]. When dropped, the /// callback will be uninstalled. /// /// To prevent the callback from ever being uninstalled, use /// [`Self::persist()`]. #[must_use = "Callbacks are disconnected once the associated CallbackHandle is dropped. Consider using `CallbackHandle::persist()` to prevent the callback from being disconnected."] pub struct CallbackHandle(CallbackHandleInner); impl Default for CallbackHandle { fn default() -> Self { Self(CallbackHandleInner::None) } } enum CallbackHandleInner { None, Single(CallbackHandleData), Multi(Vec), } trait ReferencedDynamic: Sync + Send + 'static {} impl ReferencedDynamic for T where T: Sync + Send + 'static {} struct CallbackHandleData { id: Option, owner: Option>, callbacks: Arc, } impl Debug for CallbackHandle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut tuple = f.debug_tuple("CallbackHandle"); match &self.0 { CallbackHandleInner::None => {} CallbackHandleInner::Single(handle) => { tuple.field(&handle.id); } CallbackHandleInner::Multi(handles) => { for handle in handles { tuple.field(&handle.id); } } } tuple.finish() } } impl CallbackHandle { /// Persists the callback so that it will always be invoked until the /// dynamic is freed. pub fn persist(self) { match self.0 { CallbackHandleInner::None => {} CallbackHandleInner::Single(mut handle) => { let _id = handle.id.take(); drop(handle); } CallbackHandleInner::Multi(handles) => { for handle in handles { handle.persist(); } } } } /// Drops any references to owning [`Dynamic`]s associated with this /// callback. /// /// This enables creating weak connections between callback graphs. pub fn forget_owners(&mut self) { match &mut self.0 { CallbackHandleInner::None => {} CallbackHandleInner::Single(handle) => { handle.owner = None; } CallbackHandleInner::Multi(handles) => { for handle in handles { handle.owner = None; } } } } /// Drops any references to owning [`Dynamic`]s associated with this /// callback, and returns self. /// /// This uses [`Self::forget_owners()`]. pub fn weak(mut self) -> Self { self.forget_owners(); self } } impl Eq for CallbackHandle {} impl PartialEq for CallbackHandle { fn eq(&self, other: &Self) -> bool { match (&self.0, &other.0) { (CallbackHandleInner::None, CallbackHandleInner::None) => true, (CallbackHandleInner::Single(this), CallbackHandleInner::Single(other)) => { this == other } (CallbackHandleInner::Multi(this), CallbackHandleInner::Multi(other)) => this == other, _ => false, } } } impl CallbackHandleData { fn persist(mut self) { let _id = self.id.take(); drop(self); } } impl Drop for CallbackHandleData { fn drop(&mut self) { if let Some(id) = self.id { self.callbacks.remove(id); } } } impl PartialEq for CallbackHandleData { fn eq(&self, other: &Self) -> bool { self.id == other.id && Arc::ptr_eq(&self.callbacks, &other.callbacks) } } impl Add for CallbackHandle { type Output = Self; fn add(mut self, rhs: Self) -> Self::Output { self += rhs; self } } impl AddAssign for CallbackHandle { fn add_assign(&mut self, rhs: Self) { match (&mut self.0, rhs.0) { (_, CallbackHandleInner::None) => {} (CallbackHandleInner::None, other) => { self.0 = other; } (CallbackHandleInner::Single(_), CallbackHandleInner::Single(other)) => { let CallbackHandleInner::Single(single) = std::mem::replace(&mut self.0, CallbackHandleInner::Multi(vec![other])) else { unreachable!("just matched") }; let CallbackHandleInner::Multi(multi) = &mut self.0 else { unreachable!("just replaced") }; multi.push(single); } (CallbackHandleInner::Single(_), CallbackHandleInner::Multi(multi)) => { let CallbackHandleInner::Single(single) = std::mem::replace(&mut self.0, CallbackHandleInner::Multi(multi)) else { unreachable!("just matched") }; let CallbackHandleInner::Multi(multi) = &mut self.0 else { unreachable!("just replaced") }; multi.push(single); } (CallbackHandleInner::Multi(this), CallbackHandleInner::Single(single)) => { this.push(single); } (CallbackHandleInner::Multi(this), CallbackHandleInner::Multi(mut other)) => { this.append(&mut other); } } } } #[derive(Default)] struct InvalidationState { windows: AHashMap, widgets: AHashSet<(WindowHandle, WidgetId)>, wakers: Vec, } impl InvalidationState { fn invoke(&mut self) { for (window, widget) in self.widgets.drain() { window.invalidate(widget); } for (window, redraw) in self.windows.drain() { if redraw { window.redraw(); } else { window.sync(); } } for waker in self.wakers.drain(..) { waker.wake(); } } fn extend(&mut self, other: &mut InvalidationState) { self.widgets.extend(other.widgets.drain()); self.windows.extend(other.windows.drain()); for waker in other.wakers.drain(..) { if !self .wakers .iter() .any(|existing| existing.will_wake(&waker)) { self.wakers.push(waker); } } } } struct State { wrapped: GenerationalValue, source_callback: CallbackHandle, callbacks: Arc, invalidation: InvalidationState, on_disconnect: Option>, readers: usize, } impl State { fn new(value: T) -> Self { Self { wrapped: GenerationalValue { value, generation: Generation::default(), }, callbacks: Arc::default(), invalidation: InvalidationState { windows: AHashMap::new(), wakers: Vec::new(), widgets: AHashSet::new(), }, readers: 0, on_disconnect: Some(Vec::new()), source_callback: CallbackHandle::default(), } } fn note_changed(&mut self) -> ChangeCallbacks { self.wrapped.generation = self.wrapped.generation.next(); if !InvalidationBatch::take_invalidations(&mut self.invalidation) { self.invalidation.invoke(); } ChangeCallbacks { data: self.callbacks.clone(), changed_at: Instant::now(), } } fn debug(&self, name: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result where T: Debug, { f.debug_struct(name) .field("value", &self.wrapped.value) .field("generation", &self.wrapped.generation.0) .finish() } #[must_use] fn cleanup(&mut self) -> StateCleanup { StateCleanup { on_disconnect: self.on_disconnect.take(), wakers: std::mem::take(&mut self.invalidation.wakers), } } } impl Drop for State { fn drop(&mut self) { // Ensure any disconnections that didn't fire due to deadlocking still // are invoked. drop(self.cleanup()); } } struct StateCleanup { on_disconnect: Option>, wakers: Vec, } impl Drop for StateCleanup { fn drop(&mut self) { for on_disconnect in self.on_disconnect.take().into_iter().flatten() { on_disconnect.invoke(()); } for waker in self.wakers.drain(..) { waker.wake(); } } } impl Debug for State where T: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("State") .field("wrapped", &self.wrapped) .field("readers", &self.readers) .finish_non_exhaustive() } } #[derive(Default)] struct ChangeCallbacksExecutor { thread: Option, callbacks_to_remove: Vec, } #[derive(Default)] struct ChangeCallbacksData { callbacks: Mutex, currently_executing: Mutex, sync: Condvar, } impl CallbackCollection for ChangeCallbacksData { fn remove(&self, id: LotId) { let mut currently_executing = self.currently_executing.lock(); if currently_executing.thread == Some(thread::current().id()) { currently_executing.callbacks_to_remove.push(id); } else { drop(currently_executing); let mut data = self.callbacks.lock(); data.callbacks.remove(id); } } } struct CallbacksList { callbacks: Lots>, invoked_at: Instant, } impl Default for CallbacksList { fn default() -> Self { Self { callbacks: Lots::new(), invoked_at: Instant::now(), } } } struct ChangeCallbacks { data: Arc, changed_at: Instant, } impl Drop for ChangeCallbacks { fn drop(&mut self) { let mut currently_executing = self.data.currently_executing.lock(); let current_thread = thread::current().id(); loop { match ¤tly_executing.thread { None => { // No other thread is executing these callbacks. Set this // thread as the current executor so that we can prevent // infinite cycles. currently_executing.thread = Some(current_thread); drop(currently_executing); // Invoke the callbacks let mut state = self.data.callbacks.lock(); // If the callbacks have already been invoked by another // thread such that the callbacks observed the value our // thread wrote, we can skip the callbacks. if state.invoked_at < self.changed_at { state.invoked_at = Instant::now(); // Invoke all callbacks, removing those that report an // error. state .callbacks .drain_filter(|callback| callback.changed().is_err()); } // Remove ourselves as the current executor, notifying any // other threads that are waiting. currently_executing = self.data.currently_executing.lock(); currently_executing.thread = None; for callback in currently_executing.callbacks_to_remove.drain(..) { state.callbacks.remove(callback); } drop(state); drop(currently_executing); self.data.sync.notify_all(); return; } Some(executing) if executing == ¤t_thread => { // The callbacks are already running, and they triggered // again. We ignore this rather than trying to continue to // propagate because this can only be caused by a cycle // happening during a callback already executing. return; } Some(_) => { self.data.sync.wait(&mut currently_executing); } } } } } trait ValueCallback: Send { fn changed(&mut self) -> Result<(), CallbackDisconnected>; } impl ValueCallback for F where F: for<'a> FnMut() -> Result<(), CallbackDisconnected> + Send + 'static, { fn changed(&mut self) -> Result<(), CallbackDisconnected> { self() } } /// A value stored in a [`Dynamic`] with its [`Generation`]. #[derive(Default, Clone, Debug, Eq, PartialEq)] pub struct GenerationalValue { /// The stored value. pub value: T, generation: Generation, } impl GenerationalValue { /// Returns the generation of this value. /// /// Each time a [`Dynamic`] is updated, the generation is also updated. This /// value can be used to track whether a particular value has been observed. pub const fn generation(&self) -> Generation { self.generation } /// Returns a new instance containing the result of invoking `map` with /// `self.value`. /// /// The returned instance will have the same generation as this instance. pub fn map(self, map: impl FnOnce(T) -> U) -> GenerationalValue { GenerationalValue { value: map(self.value), generation: self.generation, } } /// Returns a new instance containing the result of invoking `map` with /// `&self.value`. /// /// The returned instance will have the same generation as this instance. pub fn map_ref(&self, map: impl for<'a> FnOnce(&'a T) -> U) -> GenerationalValue { GenerationalValue { value: map(&self.value), generation: self.generation, } } } impl Deref for GenerationalValue { type Target = T; fn deref(&self) -> &Self::Target { &self.value } } impl DerefMut for GenerationalValue { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.value } } #[derive(Debug)] enum DynamicOrOwnedGuard<'a, T> { Dynamic(DynamicMutexGuard<'a, T>), Owned(RefMut<'a, GenerationalValue>), OwnedRef(&'a mut GenerationalValue), } impl<'a, T> DynamicOrOwnedGuard<'a, T> { fn note_changed(&mut self) -> Option { match self { Self::Dynamic(guard) => Some(guard.note_changed()), Self::Owned(_) | Self::OwnedRef(_) => None, } } fn unlocked(&mut self, while_unlocked: impl FnOnce()) { match self { Self::Dynamic(guard) => guard.unlocked(while_unlocked), Self::Owned(_) | Self::OwnedRef(_) => while_unlocked(), } } } impl<'a, T> Deref for DynamicOrOwnedGuard<'a, T> { type Target = GenerationalValue; fn deref(&self) -> &Self::Target { match self { Self::Dynamic(guard) => &guard.wrapped, Self::Owned(r) => r, Self::OwnedRef(r) => r, } } } impl<'a, T> DerefMut for DynamicOrOwnedGuard<'a, T> { fn deref_mut(&mut self) -> &mut Self::Target { match self { Self::Dynamic(guard) => &mut guard.wrapped, Self::Owned(r) => r, Self::OwnedRef(r) => r, } } } /// An exclusive reference to the contents of a [`Dynamic`]. /// /// If the contents are accessed through [`DerefMut`], all obververs will be /// notified of a change when this guard is dropped. #[derive(Debug)] pub struct DynamicGuard<'a, T, const READONLY: bool = false> { guard: DynamicOrOwnedGuard<'a, T>, accessed_mut: bool, prevent_notifications: bool, } impl DynamicGuard<'_, T, READONLY> { /// Returns the generation of the value at the time of locking the dynamic. /// /// Even if this guard accesses the data through [`DerefMut`], this value /// will remain unchanged while the guard is held. #[must_use] pub fn generation(&self) -> Generation { self.guard.generation } /// Prevent any access through [`DerefMut`] from triggering change /// notifications. pub fn prevent_notifications(&mut self) { self.prevent_notifications = true; } } impl<'a, T, const READONLY: bool> Deref for DynamicGuard<'a, T, READONLY> { type Target = T; fn deref(&self) -> &Self::Target { &self.guard.value } } impl<'a, T> DerefMut for DynamicGuard<'a, T, false> { fn deref_mut(&mut self) -> &mut Self::Target { self.accessed_mut = true; &mut self.guard.value } } impl Drop for DynamicGuard<'_, T, READONLY> { fn drop(&mut self) { if self.accessed_mut && !self.prevent_notifications { let callbacks = self.guard.note_changed(); self.guard.unlocked(|| drop(callbacks)); } } } /// A weak reference to a [`Dynamic`]. /// /// This is powered by [`Arc`]/[`Weak`] and follows the same semantics for /// reference counting. pub struct WeakDynamic(Weak>); impl WeakDynamic { /// Returns the [`Dynamic`] this weak reference points to, unless no /// remaining [`Dynamic`] instances exist for the underlying value. #[must_use] pub fn upgrade(&self) -> Option> { self.0.upgrade().map(Dynamic) } } impl Debug for WeakDynamic where T: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(strong) = self.upgrade() { Debug::fmt(&strong, f) } else { f.debug_tuple("WeakDynamic") .field(&"") .finish() } } } impl<'a, T> From<&'a Dynamic> for WeakDynamic { fn from(value: &'a Dynamic) -> Self { Self(Arc::downgrade(&value.0)) } } impl From> for WeakDynamic { fn from(value: Dynamic) -> Self { Self::from(&value) } } impl Clone for WeakDynamic { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Eq for WeakDynamic {} impl PartialEq for WeakDynamic { fn eq(&self, other: &Self) -> bool { Weak::ptr_eq(&self.0, &other.0) } } impl PartialEq> for WeakDynamic { fn eq(&self, other: &Dynamic) -> bool { Weak::as_ptr(&self.0) == Arc::as_ptr(&other.0) } } impl PartialEq> for Dynamic { fn eq(&self, other: &WeakDynamic) -> bool { Arc::as_ptr(&self.0) == Weak::as_ptr(&other.0) } } /// A reader of a [`Dynamic`] that tracks the last generation accessed. pub struct DynamicReader { source: Arc>, read_generation: Mutex, } impl DynamicReader { /// Returns an read-only, exclusive reference to the contents of this /// dynamic. /// /// This call will block until all other guards for this dynamic have been /// dropped. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] pub fn lock(&self) -> DynamicGuard<'_, T, true> { DynamicGuard { guard: DynamicOrOwnedGuard::Dynamic(self.source.state().expect("deadlocked")), accessed_mut: false, prevent_notifications: false, } } /// Returns the current generation that has been accessed through this /// reader. #[must_use] pub fn read_generation(&self) -> Generation { *self.read_generation.lock() } /// Returns true if the dynamic has been modified since the last time the /// value was accessed through this reader. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. #[must_use] pub fn has_updated(&self) -> bool { self.source.state().expect("deadlocked").wrapped.generation != self.read_generation() } /// Blocks the current thread until the contained value has been updated or /// there are no remaining writers for the value. /// /// Returns true if a newly updated value was discovered. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. pub fn block_until_updated(&self) -> bool { assert!( self.source .during_callback_state .lock() .as_ref() .map_or(true, |state| state.locked_thread != std::thread::current().id()), "deadlocked" ); let mut state = self.source.state.lock(); loop { if state.wrapped.generation != self.read_generation() { return true; } else if state.readers == Arc::strong_count(&self.source) || state.on_disconnect.is_none() { return false; } // Wait for a notification of a change, which is synch self.source.sync.wait(&mut state); } } /// Returns true if this reader still has any writers connected to it. #[must_use] pub fn connected(&self) -> bool { let state = self.source.state.lock(); state.readers < Arc::strong_count(&self.source) && state.on_disconnect.is_some() } /// Suspends the current async task until the contained value has been /// updated or there are no remaining writers for the value. /// /// Returns true if a newly updated value was discovered. pub fn wait_until_updated(&self) -> BlockUntilUpdatedFuture<'_, T> { BlockUntilUpdatedFuture(self) } /// Invokes `on_disconnect` when no instances of `Dynamic` exist. /// /// This callback will be invoked even if this `DynamicReader` has been /// dropped. /// /// # Panics /// /// This function panics if this value is already locked by the current /// thread. pub fn on_disconnect(&self, on_disconnect: OnDisconnect) where OnDisconnect: FnOnce() + Send + 'static, { let mut state = self.source.state().expect("deadlocked"); if let Some(callbacks) = &mut state.on_disconnect { callbacks.push(OnceCallback::new(|()| on_disconnect())); } } } impl context::sealed::Trackable for DynamicReader { fn inner_redraw_when_changed(&self, handle: WindowHandle) { self.source.redraw_when_changed(handle); } fn inner_sync_when_changed(&self, handle: WindowHandle) { self.source.sync_when_changed(handle); } fn inner_invalidate_when_changed(&self, handle: WindowHandle, id: WidgetId) { self.source.invalidate_when_changed(handle, id); } } impl Debug for DynamicReader where T: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DynamicReader") .field("source", &DebugDynamicData(&self.source)) .field("read_generation", &self.read_generation().0) .finish() } } impl Clone for DynamicReader { fn clone(&self) -> Self { self.source.state().expect("deadlocked").readers += 1; Self { source: self.source.clone(), read_generation: Mutex::new(self.read_generation()), } } } impl Drop for DynamicReader { fn drop(&mut self) { let mut state = self.source.state().expect("deadlocked"); state.readers -= 1; } } /// Suspends the current async task until the contained value has been /// updated or there are no remaining writers for the value. /// /// Yeilds true if a newly updated value was discovered. #[derive(Debug)] #[must_use = "futures must be .await'ed to be executed"] pub struct BlockUntilUpdatedFuture<'a, T>(&'a DynamicReader); impl<'a, T> Future for BlockUntilUpdatedFuture<'a, T> { type Output = bool; fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { let mut state = self.0.source.state().expect("deadlocked"); if state.wrapped.generation != self.0.read_generation() { return Poll::Ready(true); } else if state.readers == Arc::strong_count(&self.0.source) || state.on_disconnect.is_none() { return Poll::Ready(false); } state.invalidation.wakers.push(cx.waker().clone()); Poll::Pending } } #[test] fn disconnecting_reader_from_dynamic() { let value = Dynamic::new(1); let ref_reader = value.create_reader(); drop(value); assert!(!ref_reader.block_until_updated()); } #[test] fn disconnecting_reader_threaded() { let a = Dynamic::new(1); let a_reader = a.create_reader(); let b = Dynamic::new(1); let b_reader = b.create_reader(); let thread = std::thread::spawn(move || { b.set(2); assert!(a_reader.block_until_updated()); assert_eq!(a_reader.get(), 2); assert!(!a_reader.block_until_updated()); }); // Wait for the thread to set b to 2. assert!(b_reader.block_until_updated()); assert_eq!(b_reader.get(), 2); // Set a to 2 and drop the handle. a.set(2); drop(a); thread.join().unwrap(); } #[test] fn disconnecting_reader_async() { let a = Dynamic::new(1); let a_reader = a.create_reader(); let b = Dynamic::new(1); let b_reader = b.create_reader(); let async_thread = std::thread::spawn(move || { pollster::block_on(async move { // Set b to 2, allowing the thread to execute its code. b.set(2); assert!(a_reader.wait_until_updated().await); assert_eq!(a_reader.get(), 2); assert!(!a_reader.wait_until_updated().await); }); }); // Wait for the pollster thread to set b to 2. assert!(b_reader.block_until_updated()); assert_eq!(b_reader.get(), 2); // Set a to 2 and drop the handle. a.set(2); drop(a); async_thread.join().unwrap(); } /// A tag that represents an individual revision of a [`Dynamic`] value. #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] pub struct Generation(usize); impl Generation { /// Returns the next tag. #[must_use] pub fn next(self) -> Self { Self(self.0.wrapping_add(1)) } } /// A type that can convert into a `ReadOnly`. pub trait IntoReadOnly { /// Returns `self` as a `ReadOnly`. fn into_read_only(self) -> ReadOnly; } impl IntoReadOnly for T { fn into_read_only(self) -> ReadOnly { ReadOnly::Constant(self) } } impl IntoReadOnly for ReadOnly { fn into_read_only(self) -> ReadOnly { self } } impl IntoReadOnly for Value { fn into_read_only(self) -> ReadOnly { match self { Value::Constant(value) => ReadOnly::Constant(value), Value::Dynamic(dynamic) => ReadOnly::Reader(dynamic.into_reader()), } } } impl IntoReadOnly for Dynamic { fn into_read_only(self) -> ReadOnly { self.create_reader().into_read_only() } } impl IntoReadOnly for DynamicReader { fn into_read_only(self) -> ReadOnly { ReadOnly::Reader(self) } } impl IntoReadOnly for Owned { fn into_read_only(self) -> ReadOnly { ReadOnly::Constant(self.into_inner()) } } /// A type that can be converted into a [`DynamicReader`]. pub trait IntoReader { /// Returns this value as a reader. fn into_reader(self) -> DynamicReader; /// Returns `self` being `Display`ed in a [`Label`] widget. fn into_label(self) -> Label where Self: Sized, T: Debug + Display + Send + 'static, { Label::new(self.into_reader()) } /// Returns `self` being `Display`ed in a [`Label`] widget. fn to_label(&self) -> Label where Self: Clone, T: Debug + Display + Send + 'static, { self.clone().into_label() } } impl IntoReader for Dynamic { fn into_reader(self) -> DynamicReader { self.into_reader() } } impl IntoReader for DynamicReader { fn into_reader(self) -> DynamicReader { self } } /// A type that can convert into a `Dynamic`. pub trait IntoDynamic { /// Returns `self` as a dynamic. fn into_dynamic(self) -> Dynamic; } impl IntoDynamic for Dynamic { fn into_dynamic(self) -> Dynamic { self } } impl IntoDynamic for F where F: FnMut(&T) + Send + 'static, T: Default + Send + 'static, { /// Returns [`Dynamic::default()`] with `self` installed as a for-each /// callback. fn into_dynamic(self) -> Dynamic { Dynamic::default().with_for_each(self) } } /// A type that can be the source of a [`Switcher`] widget. pub trait Switchable: IntoDynamic + Sized { /// Returns a new [`Switcher`] whose contents is the result of invoking /// `map` each time `self` is updated. fn switcher(self, map: F) -> Switcher where F: FnMut(&T, &Dynamic) -> WidgetInstance + Send + 'static, T: Send + 'static, { Switcher::mapping(self, map) } /// Returns a new [`Switcher`] whose contents switches between the values /// contained in `map` using the value in `self` as the key. fn switch_between(self, map: Collection) -> Switcher where Collection: GetWidget + Send + 'static, T: Send + 'static, { Switcher::mapping(self, move |key, _| { map.get(key) .map_or_else(|| Space::clear().make_widget(), Clone::clone) }) } } /// A collection of widgets that can be queried by `Key`. pub trait GetWidget { /// Returns the widget associated with `key`, if found. fn get<'a>(&'a self, key: &Key) -> Option<&'a WidgetInstance>; } impl GetWidget for HashMap where Key: Hash + Eq, State: BuildHasher, { fn get<'a>(&'a self, key: &Key) -> Option<&'a WidgetInstance> { HashMap::get(self, key) } } impl GetWidget for Map where Key: Sort, { fn get<'a>(&'a self, key: &Key) -> Option<&'a WidgetInstance> { Map::get(self, key) } } impl GetWidget for WidgetList { fn get<'a>(&'a self, key: &usize) -> Option<&'a WidgetInstance> { (**self).get(*key) } } impl GetWidget for Vec { fn get<'a>(&'a self, key: &usize) -> Option<&'a WidgetInstance> { (**self).get(*key) } } impl Switchable for W where W: IntoDynamic {} /// A value that can only be read from. pub enum ReadOnly { /// A value that will not ever change externally. Constant(T), /// A value that is read from a dynamic. Reader(DynamicReader), } impl ReadOnly { /// Returns a clone of the currently stored value. #[must_use] pub fn get(&self) -> T where T: Clone, { match self { Self::Constant(value) => value.clone(), Self::Reader(value) => value.get(), } } /// Returns the current generation of the data stored, if the contained /// value is [`Dynamic`]. pub fn generation(&self) -> Option { match self { Self::Constant(_) => None, Self::Reader(value) => Some(value.generation()), } } /// Maps the current contents to `map` and returns the result. pub fn map(&self, map: impl FnOnce(&T) -> R) -> R { match self { Self::Constant(value) => map(value), Self::Reader(dynamic) => dynamic.map_ref(map), } } /// Returns a new value that is updated using `U::from(T.clone())` each time /// `self` is updated. #[must_use] pub fn map_each(&self, mut map: F) -> ReadOnly where T: Send + 'static, F: for<'a> FnMut(&'a T) -> R + Send + 'static, R: PartialEq + Send + 'static, { match self { Self::Constant(value) => ReadOnly::Constant(map(value)), Self::Reader(dynamic) => ReadOnly::Reader(dynamic.map_each(map).into_reader()), } } } impl From> for ReadOnly { fn from(value: DynamicReader) -> Self { Self::Reader(value) } } impl From> for ReadOnly { fn from(value: Dynamic) -> Self { Self::from(value.into_reader()) } } impl From> for ReadOnly { fn from(value: Owned) -> Self { Self::Constant(value.into_inner()) } } impl Debug for ReadOnly where T: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Constant(arg0) => Debug::fmt(arg0, f), Self::Reader(arg0) => Debug::fmt(arg0, f), } } } /// A value that may be either constant or dynamic. pub enum Value { /// A value that will not ever change externally. Constant(T), /// A value that may be updated externally. Dynamic(Dynamic), } impl Value { /// Returns a [`Value::Dynamic`] containing `value`. pub fn dynamic(value: T) -> Self { Self::Dynamic(Dynamic::new(value)) } /// Maps the current contents to `map` and returns the result. pub fn map(&self, map: impl FnOnce(&T) -> R) -> R { match self { Value::Constant(value) => map(value), Value::Dynamic(dynamic) => dynamic.map_ref(map), } } /// Maps the current contents to `map` and returns the result. /// /// If `self` is a dynamic, `context` will be invalidated when the value is /// updated. pub fn map_tracking_redraw( &self, context: &WidgetContext<'_>, map: impl FnOnce(&T) -> R, ) -> R { match self { Value::Constant(value) => map(value), Value::Dynamic(dynamic) => { context.redraw_when_changed(dynamic); dynamic.map_ref(map) } } } /// Maps the current contents to `map` and returns the result. /// /// If `self` is a dynamic, `context` will be invalidated when the value is /// updated. pub fn map_tracking_invalidate( &self, context: &WidgetContext<'_>, map: impl FnOnce(&T) -> R, ) -> R { match self { Value::Constant(value) => map(value), Value::Dynamic(dynamic) => { context.invalidate_when_changed(dynamic); dynamic.map_ref(map) } } } /// Maps the current contents with exclusive access and returns the result. pub fn map_mut(&mut self, map: impl FnOnce(Mutable<'_, T>) -> R) -> R { match self { Value::Constant(value) => map(Mutable::from(value)), Value::Dynamic(dynamic) => dynamic.map_mut(map), } } /// Returns a new value that is updated using `U::from(T.clone())` each time /// `self` is updated. #[must_use] pub fn map_each(&self, mut map: F) -> Value where T: Send + 'static, F: for<'a> FnMut(&'a T) -> R + Send + 'static, R: PartialEq + Send + 'static, { match self { Value::Constant(value) => Value::Constant(map(value)), Value::Dynamic(dynamic) => Value::Dynamic(dynamic.map_each(map)), } } /// Returns a clone of the currently stored value. pub fn get(&self) -> T where T: Clone, { self.map(Clone::clone) } /// Returns a clone of the currently stored value. /// /// If `self` is a dynamic, `context` will be refreshed when the value is /// updated. pub fn get_tracking_redraw(&self, context: &WidgetContext<'_>) -> T where T: Clone, { self.map_tracking_redraw(context, Clone::clone) } /// Returns a clone of the currently stored value. /// /// If `self` is a dynamic, `context` will be invalidated when the value is /// updated. pub fn get_tracking_invalidate(&self, context: &WidgetContext<'_>) -> T where T: Clone, { self.map_tracking_invalidate(context, Clone::clone) } /// Returns the current generation of the data stored, if the contained /// value is [`Dynamic`]. pub fn generation(&self) -> Option { match self { Value::Constant(_) => None, Value::Dynamic(value) => Some(value.generation()), } } } impl crate::context::sealed::Trackable for ReadOnly { fn inner_invalidate_when_changed(&self, handle: WindowHandle, id: WidgetId) { if let ReadOnly::Reader(dynamic) = self { dynamic.inner_invalidate_when_changed(handle, id); } } fn inner_sync_when_changed(&self, handle: WindowHandle) { if let ReadOnly::Reader(dynamic) = self { dynamic.inner_sync_when_changed(handle); } } fn inner_redraw_when_changed(&self, handle: WindowHandle) { if let ReadOnly::Reader(dynamic) = self { dynamic.inner_redraw_when_changed(handle); } } } impl crate::context::sealed::Trackable for Value { fn inner_invalidate_when_changed(&self, handle: WindowHandle, id: WidgetId) { if let Value::Dynamic(dynamic) = self { dynamic.inner_invalidate_when_changed(handle, id); } } fn inner_sync_when_changed(&self, handle: WindowHandle) { if let Value::Dynamic(dynamic) = self { dynamic.inner_sync_when_changed(handle); } } fn inner_redraw_when_changed(&self, handle: WindowHandle) { if let Value::Dynamic(dynamic) = self { dynamic.inner_redraw_when_changed(handle); } } } impl From> for Value { fn from(value: Dynamic) -> Self { Self::Dynamic(value) } } impl IntoDynamic for Value { fn into_dynamic(self) -> Dynamic { match self { Value::Constant(value) => Dynamic::new(value), Value::Dynamic(value) => value, } } } impl Debug for Value where T: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Constant(arg0) => Debug::fmt(arg0, f), Self::Dynamic(arg0) => Debug::fmt(arg0, f), } } } impl Clone for Value where T: Clone, { fn clone(&self) -> Self { match self { Self::Constant(arg0) => Self::Constant(arg0.clone()), Self::Dynamic(arg0) => Self::Dynamic(arg0.clone()), } } } impl Default for Value where T: Default, { fn default() -> Self { Self::Constant(T::default()) } } /// A type that can be converted into a [`Value`]. pub trait IntoValue { /// Returns this type as a [`Value`]. fn into_value(self) -> Value; } impl IntoValue for T { fn into_value(self) -> Value { Value::Constant(self) } } impl<'a> IntoValue for &'a str { fn into_value(self) -> Value { Value::Constant(self.to_owned()) } } impl<'a> IntoReadOnly for &'a str { fn into_read_only(self) -> ReadOnly { ReadOnly::Constant(self.to_string()) } } impl IntoValue for Dynamic { fn into_value(self) -> Value { Value::Dynamic(self) } } impl IntoValue for &'_ Dynamic { fn into_value(self) -> Value { Value::Dynamic(self.clone()) } } impl IntoValue for Value { fn into_value(self) -> Value { self } } impl IntoValue> for T { fn into_value(self) -> Value> { Value::Constant(Some(self)) } } /// A type that can have a `for_each` operation applied to it. pub trait ForEach { /// The borrowed representation of T to pass into the `for_each` function. type Ref<'a>; /// Invokes `for_each` with the current contents and each time this source's /// contents are updated. fn for_each(&self, for_each: F) -> CallbackHandle where F: for<'a> FnMut(Self::Ref<'a>) + Send + 'static; /// Attaches `for_each` to this value so that it is invoked each time the /// source's contents are updated. /// /// `for_each` will not be invoked with the currently stored value. fn for_each_subsequent(&self, for_each: F) -> CallbackHandle where F: for<'a> FnMut(Self::Ref<'a>) + Send + 'static; } macro_rules! impl_tuple_for_each { ($($type:ident $source:ident $field:tt $var:ident),+) => { impl<$($type,$source,)+> ForEach<($($type,)+)> for ($(&$source,)+) where $( $source: DynamicRead<$type> + Source<$type> + Clone + Send + 'static, $type: Send + 'static, )+ { type Ref<'a> = ($(&'a $type,)+); #[allow(unused_mut)] fn for_each(&self, mut for_each: F) -> CallbackHandle where F: for<'a> FnMut(Self::Ref<'a>) + Send + 'static, { { $(let $var = self.$field.read();)+ for_each(($(&$var,)+)); }; self.for_each_subsequent(for_each) } #[allow(unused_mut)] fn for_each_subsequent(&self, mut for_each: F) -> CallbackHandle where F: for<'a> FnMut(Self::Ref<'a>) + Send + 'static, { let mut handles = CallbackHandle::default(); impl_tuple_for_each!(self for_each handles [] [$($type $field $var),+]); handles } } }; ($self:ident $for_each:ident $handles:ident [] [$type:ident $field:tt $var:ident]) => { $handles += $self.$field.for_each(move |field| $for_each((field,))); }; ($self:ident $for_each:ident $handles:ident [] [$($type:ident $field:tt $var:ident),+]) => { let $for_each = Arc::new(Mutex::new($for_each)); $(let $var = $self.$field.clone();)* impl_tuple_for_each!(invoke $self $for_each $handles [] [$($type $field $var),+]); }; ( invoke // Identifiers used from the outer method $self:ident $for_each:ident $handles:ident // List of all tuple fields that have already been positioned as the focused call [$($ltype:ident $lfield:tt $lvar:ident),*] // [$type:ident $field:tt $var:ident, $($rtype:ident $rfield:tt $rvar:ident),+] ) => { impl_tuple_for_each!( invoke $self $for_each $handles $type $field $var [$($ltype $lfield $lvar,)* $type $field $var, $($rtype $rfield $rvar),+] [$($ltype $lfield $lvar,)* $($rtype $rfield $rvar),+] ); impl_tuple_for_each!( invoke $self $for_each $handles [$($ltype $lfield $lvar,)* $type $field $var] [$($rtype $rfield $rvar),+] ); }; ( invoke // Identifiers used from the outer method $self:ident $for_each:ident $handles:ident // List of all tuple fields that have already been positioned as the focused call [$($ltype:ident $lfield:tt $lvar:ident),+] // [$type:ident $field:tt $var:ident] ) => { impl_tuple_for_each!( invoke $self $for_each $handles $type $field $var [$($ltype $lfield $lvar,)+ $type $field $var] [$($ltype $lfield $lvar),+] ); }; ( invoke // Identifiers used from the outer method $self:ident $for_each:ident $handles:ident // Tuple field that for_each is being invoked on $type:ident $field:tt $var:ident // The list of all tuple fields in this invocation, in the correct order. [$($atype:ident $afield:tt $avar:ident),+] // The list of tuple fields excluding the one being invoked. [$($rtype:ident $rfield:tt $rvar:ident),+] ) => { $handles += $var.for_each_subsequent((&$for_each, $(&$rvar,)+).with_clone(|(for_each, $($rvar,)+)| { move |$var: &$type| { $(let $rvar = $rvar.read();)+ let mut for_each = for_each.lock(); (for_each)(($(&$avar,)+)); } })); }; } /// Read access to a value stored in a [`Dynamic`]. pub trait DynamicRead { /// Returns a guard that provides exclusive, read-only access to the value /// contained wihtin this dynamic. fn read(&self) -> DynamicGuard<'_, T, true>; } impl DynamicRead for Dynamic { fn read(&self) -> DynamicGuard<'_, T, true> { self.lock_inner() } } impl DynamicRead for DynamicReader { fn read(&self) -> DynamicGuard<'_, T, true> { self.lock() } } impl_all_tuples!(impl_tuple_for_each, 2); /// A type that can create a `Dynamic` from a `T` passed into a mapping /// function. pub trait MapEach { /// The borrowed representation of `T` passed into the mapping function. type Ref<'a> where T: 'a; /// Apply `map_each` to each value in `self`, storing the result in the /// returned dynamic. fn map_each(&self, map_each: F) -> Dynamic where F: for<'a> FnMut(Self::Ref<'a>) -> U + Send + 'static; } macro_rules! impl_tuple_map_each { ($($type:ident $source:ident $field:tt $var:ident),+) => { impl MapEach<($($type,)+), U> for ($(&$source,)+) where U: PartialEq + Send + 'static, $( $type: Send + 'static, $source: DynamicRead<$type> + Source<$type> + Clone + Send + 'static, )+ { type Ref<'a> = ($(&'a $type,)+); fn map_each(&self, mut map_each: F) -> Dynamic where F: for<'a> FnMut(Self::Ref<'a>) -> U + Send + 'static, { let dynamic = { $(let $var = self.$field.read();)+ Dynamic::new(map_each(($(&$var,)+))) }; dynamic.set_source(self.for_each({ let dynamic = dynamic.clone(); move |tuple| { dynamic.set(map_each(tuple)); } })); dynamic } } }; } impl_all_tuples!(impl_tuple_map_each, 2); /// A type that can have a `for_each` operation applied to it. pub trait ForEachCloned { /// Apply `for_each` to each value contained within `self`. fn for_each_cloned(&self, for_each: F) -> CallbackHandle where F: for<'a> FnMut(T) + Send + 'static; } macro_rules! impl_tuple_for_each_cloned { ($($type:ident $source:ident $field:tt $var:ident),+) => { impl<$($type,$source,)+> ForEachCloned<($($type,)+)> for ($(&$source,)+) where $( $type: Clone + Send + 'static, $source: Source<$type> + Clone + Send + 'static, )+ { #[allow(unused_mut)] fn for_each_cloned(&self, mut for_each: F) -> CallbackHandle where F: for<'a> FnMut(($($type,)+)) + Send + 'static, { let mut handles = CallbackHandle::default(); impl_tuple_for_each_cloned!(self for_each handles [] [$($type $field $var),+]); handles } } }; ($self:ident $for_each:ident $handles:ident [] [$type:ident $field:tt $var:ident]) => { $handles += $self.$field.for_each_cloned(move |field| $for_each((field,))); }; ($self:ident $for_each:ident $handles:ident [] [$($type:ident $field:tt $var:ident),+]) => { let $for_each = Arc::new(Mutex::new($for_each)); $(let $var = $self.$field.clone();)* impl_tuple_for_each_cloned!(invoke $self $for_each $handles [] [$($type $field $var),+]); }; ( invoke // Identifiers used from the outer method $self:ident $for_each:ident $handles:ident // List of all tuple fields that have already been positioned as the focused call [$($ltype:ident $lfield:tt $lvar:ident),*] // [$type:ident $field:tt $var:ident, $($rtype:ident $rfield:tt $rvar:ident),+] ) => { impl_tuple_for_each_cloned!( invoke $self $for_each $handles $type $field $var [$($ltype $lfield $lvar,)* $type $field $var, $($rtype $rfield $rvar),+] [$($ltype $lfield $lvar,)* $($rtype $rfield $rvar),+] ); impl_tuple_for_each_cloned!( invoke $self $for_each $handles [$($ltype $lfield $lvar,)* $type $field $var] [$($rtype $rfield $rvar),+] ); }; ( invoke // Identifiers used from the outer method $self:ident $for_each:ident $handles:ident // List of all tuple fields that have already been positioned as the focused call [$($ltype:ident $lfield:tt $lvar:ident),+] // [$type:ident $field:tt $var:ident] ) => { impl_tuple_for_each_cloned!( invoke $self $for_each $handles $type $field $var [$($ltype $lfield $lvar,)+ $type $field $var] [$($ltype $lfield $lvar),+] ); }; ( invoke // Identifiers used from the outer method $self:ident $for_each:ident $handles:ident // Tuple field that for_each is being invoked on $type:ident $field:tt $var:ident // The list of all tuple fields in this invocation, in the correct order. [$($atype:ident $afield:tt $avar:ident),+] // The list of tuple fields excluding the one being invoked. [$($rtype:ident $rfield:tt $rvar:ident),+] ) => { $handles += $var.for_each_cloned((&$for_each, $(&$rvar,)+).with_clone(|(for_each, $($rvar,)+)| { move |$var: $type| { $(let $rvar = $rvar.get();)+ if let Some(mut for_each) = for_each.try_lock() { (for_each)(($($avar,)+)); } } })); }; } impl_all_tuples!(impl_tuple_for_each_cloned, 2); /// A type that can create a `Dynamic` from a `T` passed into a mapping /// function. pub trait MapEachCloned { /// Apply `map_each` to each value in `self`, storing the result in the /// returned dynamic. fn map_each_cloned(&self, map_each: F) -> Dynamic where F: for<'a> FnMut(T) -> U + Send + 'static; } macro_rules! impl_tuple_map_each_cloned { ($($type:ident $source:ident $field:tt $var:ident),+) => { impl MapEachCloned<($($type,)+), U> for ($(&$source,)+) where U: PartialEq + Send + 'static, $( $type: Clone + Send + 'static, $source: Source<$type> + Clone + Send + 'static, )+ { fn map_each_cloned(&self, mut map_each: F) -> Dynamic where F: for<'a> FnMut(($($type,)+)) -> U + Send + 'static, { let dynamic = { $(let $var = self.$field.get();)+ Dynamic::new(map_each(($($var,)+))) }; dynamic.set_source(self.for_each_cloned({ let dynamic = dynamic.clone(); move |tuple| { dynamic.set(map_each(tuple)); } })); dynamic } } }; } impl_all_tuples!(impl_tuple_map_each_cloned, 2); /// The status of validating data. #[derive(Debug, Default, Clone, Eq, PartialEq)] pub enum Validation { /// No validation has been performed yet. /// /// This status represents that the data is still in its initial state, so /// errors should be delayed until it is changed. #[default] None, /// The data is valid. Valid, /// The data is invalid. The string contains a human-readable message. Invalid(String), } impl Validation { /// Returns the effective text to display along side the field. /// /// When there is a validation error, it is returned, otherwise the hint is /// returned. #[must_use] pub fn message<'a>(&'a self, hint: &'a str) -> &'a str { match self { Validation::None | Validation::Valid => hint, Validation::Invalid(err) => err, } } /// Returns true if there is a validation error. #[must_use] pub const fn is_error(&self) -> bool { matches!(self, Self::Invalid(_)) } /// Returns the result of merging both validations. #[must_use] pub fn and(&self, other: &Self) -> Self { match (self, other) { (Validation::Valid, Validation::Valid) => Validation::Valid, (Validation::Invalid(error), _) | (_, Validation::Invalid(error)) => { Validation::Invalid(error.clone()) } (Validation::None, _) | (_, Validation::None) => Validation::None, } } } impl IntoDynamic for Dynamic> where T: Send + 'static, E: Display + Send + 'static, { fn into_dynamic(self) -> Dynamic { self.map_each(|result| match result { Ok(_) => Validation::Valid, Err(err) => Validation::Invalid(err.to_string()), }) } } /// A grouping of validations that can be checked simultaneously. #[derive(Debug, Default, Clone)] pub struct Validations { state: Dynamic, invalid: Dynamic, } #[derive(Default, Debug, Eq, PartialEq, Clone)] enum ValidationsState { #[default] Initial, Resetting, Checked, Disabled, } impl Validations { /// Validates `dynamic`'s contents using `check`, returning a dynamic /// containing the validation status. /// /// The validation is linked with `self` such that checking `self`'s /// validation status will include this validation. #[must_use] pub fn validate( &self, dynamic: &Dynamic, mut check: Valid, ) -> Dynamic where T: Send + 'static, Valid: for<'a> FnMut(&'a T) -> Result<(), E> + Send + 'static, E: Display, { let validation = Dynamic::new(Validation::None); let mut message_mapping = Self::map_to_message(move |value| check(value)); let error_message = dynamic.map_each_generational(move |gen| message_mapping(&gen.guard)); validation.set_source((&self.state, &error_message).for_each_cloned({ let mut f = self.generate_validation(dynamic); let validation = validation.clone(); move |(current_state, message)| { validation.set(f(current_state, message)); } })); validation } /// Returns a dynamic validation status that is created by transforming the /// `Err` variant of `result` using [`Display`]. /// /// The validation is linked with `self` such that checking `self`'s /// validation status will include this validation. #[must_use] pub fn validate_result( &self, result: impl IntoDynamic>, ) -> Dynamic where T: Send + 'static, E: Display + Send + 'static, { let result = result.into_dynamic(); let error_message = result.map_each(move |value| match value { Ok(_) => None, Err(err) => Some(err.to_string()), }); self.validate(&error_message, |error_message| match error_message { None => Ok(()), Some(message) => Err(message.clone()), }) } fn map_to_message( mut check: Valid, ) -> impl for<'a> FnMut(&'a GenerationalValue) -> GenerationalValue> + Send + 'static where T: Send + 'static, Valid: for<'a> FnMut(&'a T) -> Result<(), E> + Send + 'static, E: Display, { move |value| { value.map_ref(|value| match check(value) { Ok(()) => None, Err(err) => Some(err.to_string()), }) } } fn generate_validation( &self, dynamic: &Dynamic, ) -> impl FnMut(ValidationsState, GenerationalValue>) -> Validation where T: Send + 'static, { self.invalid.map_mut(|mut invalid| *invalid += 1); let invalid_count = self.invalid.clone(); let dynamic = dynamic.clone(); let mut initial_generation = dynamic.generation(); let mut invalid = true; move |current_state, generational| { let new_invalid = match (¤t_state, &generational.value) { (ValidationsState::Disabled, _) | (_, None) => false, (_, Some(_)) => true, }; if invalid != new_invalid { if new_invalid { invalid_count.map_mut(|mut invalid| *invalid += 1); } else { invalid_count.map_mut(|mut invalid| *invalid -= 1); } invalid = new_invalid; } let new_status = if let Some(err) = generational.value { Validation::Invalid(err.to_string()) } else { Validation::Valid }; match current_state { ValidationsState::Resetting => { initial_generation = dynamic.generation(); Validation::None } ValidationsState::Initial if initial_generation == dynamic.generation() => { Validation::None } _ => new_status, } } } /// Returns a builder that can be used to create validations that only run /// when `condition` is true. pub fn when(&self, condition: impl IntoDynamic) -> WhenValidation<'_> { WhenValidation { validations: self, condition: condition.into_dynamic(), not: false, } } /// Returns a builder that can be used to create validations that only run /// when `condition` is false. pub fn when_not(&self, condition: impl IntoDynamic) -> WhenValidation<'_> { WhenValidation { validations: self, condition: condition.into_dynamic(), not: true, } } /// Returns true if this set of validations are all valid. #[must_use] pub fn is_valid(&self) -> bool { self.invoke_callback((), &mut |()| true) } fn invoke_callback(&self, t: T, handler: &mut F) -> R where F: FnMut(T) -> R + Send + 'static, R: Default, { let _result = self .state .compare_swap(&ValidationsState::Initial, ValidationsState::Checked); if self.invalid.get() == 0 { handler(t) } else { R::default() } } /// Returns a function that invokes `handler` only when all tracked /// validations are valid. /// /// The returned function can be use in a /// [`Callback`](crate::widget::Callback). /// /// When the contents are invalid, `R::default()` is returned. pub fn when_valid(self, mut handler: F) -> impl FnMut(T) -> R + Send + 'static where F: FnMut(T) -> R + Send + 'static, R: Default, { move |t: T| self.invoke_callback(t, &mut handler) } /// Resets the validation status for all related validations. pub fn reset(&self) { self.state.set(ValidationsState::Resetting); self.state.set(ValidationsState::Initial); } } /// A builder for validations that only run when a precondition is met. pub struct WhenValidation<'a> { validations: &'a Validations, condition: Dynamic, not: bool, } impl WhenValidation<'_> { /// Validates `dynamic`'s contents using `check`, returning a dynamic /// containing the validation status. /// /// The validation is linked with `self` such that checking `self`'s /// validation status will include this validation. /// /// Each change to `dynamic` is validated, but the result of the validation /// will be ignored if the required prerequisite isn't met. #[must_use] pub fn validate( &self, dynamic: &Dynamic, mut check: Valid, ) -> Dynamic where T: Send + 'static, Valid: for<'a> FnMut(&'a T) -> Result<(), E> + Send + 'static, E: Display, { let validation = Dynamic::new(Validation::None); let mut map_to_message = Validations::map_to_message(move |value| check(value)); let error_message = dynamic.map_each_generational(move |generational| map_to_message(&generational.guard)); let mut f = self.validations.generate_validation(dynamic); let not = self.not; (&self.condition, &self.validations.state, &error_message).map_each_cloned({ let validation = validation.clone(); move |(condition, state, message)| { let enabled = if not { !condition } else { condition }; let state = if enabled { state } else { ValidationsState::Disabled }; let result = f(state, message); if enabled { validation.set(result); } else { validation.set(Validation::None); } } }); validation } /// Returns a dynamic validation status that is created by transforming the /// `Err` variant of `result` using [`Display`]. /// /// The validation is linked with `self` such that checking `self`'s /// validation status will include this validation. #[must_use] pub fn validate_result( &self, result: impl IntoDynamic>, ) -> Dynamic where T: Send + 'static, E: Display + Send + 'static, { let result = result.into_dynamic(); let error_message = result.map_each(move |value| match value { Ok(_) => None, Err(err) => Some(err.to_string()), }); self.validate(&error_message, |error_message| match error_message { None => Ok(()), Some(message) => Err(message.clone()), }) } } struct Debounce { destination: Dynamic, period: Duration, delay: Option, buffer: Dynamic, extend: bool, _callback: Option, } impl Debounce where T: Clone + PartialEq + Send + Sync + 'static, { pub fn new(destination: Dynamic, period: Duration) -> Self { Self { buffer: Dynamic::new(destination.get()), destination, period, delay: None, extend: false, _callback: None, } } pub fn extending(mut self) -> Self { self.extend = true; self } pub fn update(&mut self, value: T) { if self.buffer.replace(value).is_some() { let create_delay = if self.extend { true } else { self.delay .as_ref() .map_or(true, AnimationHandle::is_complete) }; if create_delay { let destination = self.destination.clone(); let buffer = self.buffer.clone(); self.delay = Some( self.period .on_complete(move || { destination.set(buffer.get()); }) .spawn(), ); } } } } /// A batch of invalidations across one or more windows. /// /// This type helps background tasks synchronize when to invalidate or redraw a /// widget. Without this type, if a tracked dynamic is changed, the window is /// immediately sent a request to redraw itself. These requests are batched to /// ensure efficiency, but if a background task is updating several dynamics /// independent of one another, it may desire that those updates only trigger /// one redraw per "step". /// /// The closure invoked by [`InvalidationBatch::batch`] will gather all /// invalidations into a single batch that can be executed by the handle /// provided or automatically when the closure returns. pub struct InvalidationBatch<'a>(&'a RefCell); #[derive(Default)] struct InvalidationBatchGuard { nesting: usize, state: InvalidationState, } thread_local! { static GUARD: RefCell = RefCell::default(); } impl InvalidationBatch<'_> { /// Executes `batched` gathering all tracked invalidations into a shared /// batch. /// /// The closure accepts an `&InvalidationBatch<'_>` parameter which can be /// used to [`invoke()`](Self::invoke) the batch on-demand while during /// `batched`. /// /// This function supports nested invocation. When nested, only the /// outermost batch can manually invoke. When the outermost batch's callback /// ends, any pending invalidations are invoked automatically. pub fn batch(batched: impl FnOnce(&InvalidationBatch<'_>)) { GUARD.with(|guard| { let mut batch = guard.borrow_mut(); batch.nesting += 1; drop(batch); batched(&InvalidationBatch(guard)); let mut batch = guard.borrow_mut(); batch.nesting -= 1; if batch.nesting == 0 { batch.state.invoke(); } }); } /// Invokes all pending invalidations. /// /// This function is a no-op if `self` is a nested batch. Only the root /// batch of each thread can trigger invalidations manually. pub fn invoke(&self) { let mut batch = self.0.borrow_mut(); if batch.nesting == 1 { batch.state.invoke(); } } #[must_use] fn take_invalidations(state: &mut InvalidationState) -> bool { GUARD.with(|guard| { let mut batch = guard.borrow_mut(); if batch.nesting > 0 { // A batch is active on this thread batch.state.extend(state); true } else { false } }) } } /// Watches one or more [`Source`]s and invokes associated callbacks when /// changed. /// /// This type is useful when needing to ensure logic is executed or a value is /// regenerated each time one of many sources are changed. #[derive(Debug, Clone, Default)] pub struct Watcher(Dynamic); impl Watcher { /// Ensures all callbacks attached to this watcher are invoked when `other` /// is changed. pub fn watch(&self, other: &impl Source) where T: Send + 'static, { let counter = self.0.clone(); self.0 .set_source(other.for_each_subsequent_generational(move |guard| { // We want to drop our guard before changing the counter to // ensure all callbacks associated with our counter are executed // without this type holding any source locks. drop(guard); let mut counter = counter.lock(); *counter = counter.wrapping_add(1); })); } /// Returns a new dynamic populated by invoking `when_changed` each time any /// watched source is updated. pub fn map_changed(&self, mut when_changed: F) -> Dynamic where F: FnMut() -> T + Send + 'static, T: PartialEq + Send + 'static, { self.0.map_each(move |_| when_changed()) } /// Invokes `when_changed` each time any watched source is updated. pub fn when_changed(&self, mut when_changed: F) -> CallbackHandle where F: FnMut() + Send + 'static, { self.0.for_each(move |_| when_changed()) } } /// A value that has its read and updated states tracked. pub struct Tracked where Source: TrackedSource, { current: Source::Value, source: Source, current_generation: Generation, unread: bool, } impl Tracked where Source: TrackedSource, { /// Returns a new tracked instance. pub fn new(source: Source) -> Self { let (current, current_generation) = source.read(); Self { current, current_generation, source, unread: true, } } /// Marks the initial value as read and returns self. #[must_use] pub fn ignoring_first(mut self) -> Self { self.unread = false; self } /// Updates this tracked instance's cached value from the source. /// /// Returns true if a value hasn't been read yet. pub fn update(&mut self) -> bool { if let Some((updated, updated_generation)) = self.source.read_if_needed(self.current_generation) { self.current = updated; self.current_generation = updated_generation; self.unread = true; true } else { self.unread } } /// Returns the current value from the source, if it hasn't been read /// before. pub fn updated(&mut self) -> Option<&Source::Value> { if self.update() { self.unread = false; Some(&self.current) } else { None } } /// Returns true if the currently cached value hasn't been read. pub const fn unread(&self) -> bool { self.unread } /// Reads the current value from the source. pub fn read(&mut self) -> &Source::Value { self.update(); self.read_cached() } /// Reads the current cached value. /// /// This function does not check if an updated value exists in the source. pub fn read_cached(&mut self) -> &Source::Value { self.unread = false; self.peek() } /// Returns the current cached value without changing the unread state. pub const fn peek(&self) -> &Source::Value { &self.current } /// Returns the source being tracked. pub const fn source(&self) -> &Source { &self.source } /// Marks the current value in the source as being read. pub fn mark_read(&mut self) { self.unread = false; self.current_generation = self.source.generation(); } /// Updates the value stored in the source, and marks it as being read. pub fn set_and_read(&mut self, new_value: Source::Value) where Source::Value: PartialEq + Clone, { self.current = new_value; self.unread = false; if self.source.set(self.current.clone()) { self.current_generation = self.source.generation(); } } } /// A [`Source`] that can be used in a [`Tracked`] instance. pub trait TrackedSource: sealed::TrackedSource {} mod sealed { use super::Generation; pub trait TrackedSource { type Value; fn read(&self) -> (Self::Value, Generation); fn read_if_needed(&self, read_generation: Generation) -> Option<(Self::Value, Generation)>; fn generation(&self) -> Generation; fn set(&self, new_value: Self::Value) -> bool; } } impl TrackedSource for Dynamic where T: Clone + PartialEq {} impl sealed::TrackedSource for Dynamic where T: Clone + PartialEq, { type Value = T; fn read(&self) -> (Self::Value, Generation) { self.map_generational(|g| (g.clone(), g.generation())) } fn read_if_needed(&self, read_generation: Generation) -> Option<(Self::Value, Generation)> { self.map_generational(|g| { if g.generation() == read_generation { None } else { Some((g.clone(), g.generation())) } }) } fn generation(&self) -> Generation { Source::generation(self) } fn set(&self, new_value: Self::Value) -> bool { let mut value = self.lock(); if *value == new_value { false } else { *value = new_value; true } } } impl TrackedSource for Value where T: Clone + PartialEq {} impl sealed::TrackedSource for Value where T: Clone + PartialEq, { type Value = T; fn read(&self) -> (Self::Value, Generation) { match self { Value::Constant(value) => (value.clone(), Generation::default()), Value::Dynamic(value) => sealed::TrackedSource::read(value), } } fn read_if_needed(&self, read_generation: Generation) -> Option<(Self::Value, Generation)> { match self { Value::Constant(_) => None, Value::Dynamic(value) => sealed::TrackedSource::read_if_needed(value, read_generation), } } fn generation(&self) -> Generation { match self { Value::Constant(_) => Generation::default(), Value::Dynamic(value) => Source::generation(value), } } fn set(&self, new_value: Self::Value) -> bool { match self { Value::Constant(_) => false, Value::Dynamic(value) => sealed::TrackedSource::set(value, new_value), } } } impl Destination for Tracked where S: TrackedSource + Destination, { fn try_map_mut( &self, map: impl FnOnce(Mutable<'_, S::Value>) -> R, ) -> Result { self.source.try_map_mut(map) } } impl From> for Tracked> where T: Clone + PartialEq, { fn from(source: Dynamic) -> Self { Self::new(source) } } impl From> for Tracked> where T: Clone + PartialEq, { fn from(source: Value) -> Self { Self::new(source) } } impl context::sealed::Trackable for Tracked where Source: Trackable + TrackedSource, { fn inner_invalidate_when_changed(&self, handle: WindowHandle, id: WidgetId) { self.source.inner_invalidate_when_changed(handle, id); } fn inner_sync_when_changed(&self, handle: WindowHandle) { self.source.inner_sync_when_changed(handle); } fn inner_redraw_when_changed(&self, handle: WindowHandle) { self.source.inner_redraw_when_changed(handle); } } #[test] fn map_cycle_is_finite() { crate::initialize_tracing(); let a = Dynamic::new(0_usize); // This callback updates a each time a is updated with a + 1, causing an // infinite cycle if not broken by Cushy. a.for_each_cloned({ let a = a.clone(); move |current| { a.set(current + 1); } }) .persist(); // Cushy will invoke the callback for the first set call, but the set call // within the callback will not cause the callback to be invoked again. // Thus, we expect setting the value to 1 to result in `a` containing 2. a.set(1); assert_eq!(a.get(), 2); } #[test] fn compare_swap() { let dynamic = Dynamic::new(1); assert_eq!(dynamic.compare_swap(&1, 2), Ok(1)); assert_eq!(dynamic.compare_swap(&1, 0), Err(2)); assert_eq!(dynamic.compare_swap(&2, 0), Ok(2)); assert_eq!(dynamic.get(), 0); } #[test] fn ref_counts() { let dynamic = Dynamic::new(1); assert_eq!(dynamic.instances(), 1); let second = dynamic.clone(); assert_eq!(dynamic.instances(), 2); assert_eq!(dynamic.readers(), 0); let reader = second.into_reader(); assert_eq!(dynamic.instances(), 1); assert_eq!(dynamic.readers(), 1); // Test that once the last instance is dropped that the reader is no longer // connected and that on_disconnect gets invoked. assert!(reader.connected()); let invoked = Dynamic::new(false); reader.on_disconnect({ let invoked = invoked.clone(); move || { invoked.set(true); } }); drop(dynamic); assert!(invoked.get()); assert!(!reader.connected()); } #[test] fn linked_short_circuit() { let usize = Dynamic::new(0_usize); let string = usize.linked_string(); string.map_ref(|s| assert_eq!(s, "0")); string.set(String::from("1")); assert_eq!(usize.get(), 1); usize.set(2); string.map_ref(|s| assert_eq!(s, "2")); } #[test] fn graph_shortcircuit() { let a = Dynamic::new(0_usize); let doubled = a.map_each_cloned(|a| a * 2); let quadrupled = doubled.map_each_cloned(|a| a * 2); a.set_source(quadrupled.for_each_cloned({ let a = a.clone(); move |quad| a.set(quad / 4) })); assert_eq!(a.get(), 0); assert_eq!(quadrupled.get(), 0); a.set(1); assert_eq!(quadrupled.get(), 4); quadrupled.set(16); assert_eq!(a.get(), 4); assert_eq!(doubled.get(), 8); }