//! Types for storing and interacting with values in Widgets. use std::fmt::Debug; use std::future::Future; use std::ops::{Deref, DerefMut}; use std::panic::AssertUnwindSafe; use std::sync::{Arc, Condvar, Mutex, MutexGuard, PoisonError}; use std::task::{Poll, Waker}; use crate::animation::{DynamicTransition, LinearInterpolate}; use crate::context::{WidgetContext, WindowHandle}; use crate::utils::WithClone; /// An instance of a value that provides APIs to observe and react to its /// contents. #[derive(Debug)] 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 { wrapped: GenerationalValue { value, generation: Generation::default(), }, callbacks: Vec::new(), windows: Vec::new(), readers: 0, wakers: Vec::new(), }), sync: AssertUnwindSafe(Condvar::new()), })) } /// Maps the contents with read-only access. pub fn map_ref(&self, map: impl FnOnce(&T) -> R) -> R { let state = self.state(); map(&state.wrapped.value) } /// Maps the contents with exclusive access. Before returning from this /// function, all observers will be notified that the contents have been /// updated. pub fn map_mut(&self, map: impl FnOnce(&mut T) -> R) -> R { self.0.map_mut(|value, _| map(value)) } /// Returns a new dynamic that is updated using `U::from(T.clone())` each /// time `self` is updated. #[must_use] pub fn map_each_into(&self) -> Dynamic where U: From + Send + 'static, T: Clone, { 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] pub fn map_each_to(&self) -> Dynamic where U: for<'a> From<&'a T> + Send + 'static, T: Clone, { self.map_each(|value| U::from(value)) } /// Attaches `for_each` to this value so that it is invoked each time the /// value's contents are updated. pub fn for_each(&self, mut for_each: F) where F: for<'a> FnMut(&'a T) + Send + 'static, { self.0.for_each(move |gen| for_each(&gen.value)); } /// 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, mut for_each: F) -> Self where F: for<'a> FnMut(&'a T) + Send + 'static, { self.0.for_each(move |gen| for_each(&gen.value)); self } /// Creates a new dynamic value that contains the result of invoking `map` /// each time this value is changed. pub fn map_each(&self, mut map: F) -> Dynamic where F: for<'a> FnMut(&'a T) -> R + Send + 'static, R: Send + 'static, { self.0.map_each(move |gen| map(&gen.value)) } /// A helper function that invokes `with_clone` with a clone of self. This /// code may produce slightly more readable code. /// /// ```rust /// let value = gooey::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()) } pub(crate) fn redraw_when_changed(&self, window: WindowHandle) { self.0.redraw_when_changed(window); } /// Returns a clone of the currently contained value. #[must_use] pub fn get(&self) -> T where T: Clone, { self.0.get().value } /// Returns a clone of the currently contained value. /// /// `context` will be invalidated when the value is updated. #[must_use] pub fn get_tracked(&self, context: &WidgetContext<'_, '_>) -> T where T: Clone, { context.redraw_when_changed(self); self.get() } /// Returns the currently stored value, replacing the current contents with /// `T::default()`. #[must_use] pub fn take(&self) -> T where T: Default, { std::mem::take(&mut self.lock()) } /// Checks if the currently stored value is different than `T::default()`, /// and if so, returns `Some(self.take())`. #[must_use] pub fn take_if_not_default(&self) -> Option where T: Default + PartialEq, { let default = T::default(); let mut guard = self.lock(); if *guard == default { None } else { Some(std::mem::replace(&mut guard, default)) } } /// 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. #[must_use] pub fn replace(&self, new_value: T) -> T { self.0 .map_mut(|value, _| std::mem::replace(value, new_value)) } /// Stores `new_value` in this dynamic. Before returning from this function, /// all observers will be notified that the contents have been updated. pub fn set(&self, new_value: T) { let _old = self.replace(new_value); } /// Updates this dynamic with `new_value`, but only if `new_value` is not /// equal to the currently stored value. pub fn update(&self, new_value: T) where T: PartialEq, { self.0.map_mut(|value, changed| { if *value == new_value { *changed = false; } else { *value = new_value; } }); } /// Returns a new reference-based reader for this dynamic value. #[must_use] pub fn create_reader(&self) -> DynamicReader { self.state().readers += 1; DynamicReader { source: self.0.clone(), read_generation: self.0.state().wrapped.generation, } } /// Converts this [`Dynamic`] into a reader. #[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. #[must_use] pub fn lock(&self) -> DynamicGuard<'_, T> { DynamicGuard { guard: self.0.state(), accessed_mut: false, } } fn state(&self) -> MutexGuard<'_, State> { self.0.state() } /// Returns the current generation of the value. #[must_use] pub fn generation(&self) -> Generation { self.state().wrapped.generation } /// 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, } } } 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) { let state = self.state(); if state.readers == 0 { drop(state); self.0.sync.notify_all(); } } } impl From> for DynamicReader { fn from(value: Dynamic) -> Self { value.create_reader() } } #[derive(Debug)] struct DynamicData { state: Mutex>, // The AssertUnwindSafe is only needed on Mac. For some reason on // Mac OS, Condvar isn't RefUnwindSafe. sync: AssertUnwindSafe, } impl DynamicData { fn state(&self) -> MutexGuard<'_, State> { self.state .lock() .map_or_else(PoisonError::into_inner, |g| g) } pub fn redraw_when_changed(&self, window: WindowHandle) { let mut state = self.state(); state.windows.push(window); } #[must_use] pub fn get(&self) -> GenerationalValue where T: Clone, { self.state().wrapped.clone() } pub fn map_mut(&self, map: impl FnOnce(&mut T, &mut bool) -> R) -> R { let mut state = self.state(); let old = { let state = &mut *state; let mut changed = true; let result = map(&mut state.wrapped.value, &mut changed); if changed { state.note_changed(); } result }; drop(state); self.sync.notify_all(); old } pub fn for_each(&self, map: F) where F: for<'a> FnMut(&'a GenerationalValue) + Send + 'static, { let mut state = self.state(); state.callbacks.push(Box::new(map)); } pub fn map_each(&self, mut map: F) -> Dynamic where F: for<'a> FnMut(&'a GenerationalValue) -> R + Send + 'static, R: Send + 'static, { let mut state = self.state(); let initial_value = map(&state.wrapped); let mapped_value = Dynamic::new(initial_value); let returned = mapped_value.clone(); state .callbacks .push(Box::new(move |updated: &GenerationalValue| { mapped_value.set(map(updated)); })); returned } } struct State { wrapped: GenerationalValue, callbacks: Vec>>, windows: Vec, wakers: Vec, readers: usize, } impl State { fn note_changed(&mut self) { self.wrapped.generation = self.wrapped.generation.next(); for callback in &mut self.callbacks { callback.update(&self.wrapped); } for window in self.windows.drain(..) { window.redraw(); } for waker in self.wakers.drain(..) { waker.wake(); } } } impl Debug for State where T: Debug, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("State") .field("wrapped", &self.wrapped) .field("readers", &self.readers) .finish_non_exhaustive() } } trait ValueCallback: Send { fn update(&mut self, value: &GenerationalValue); } impl ValueCallback for F where F: for<'a> FnMut(&'a GenerationalValue) + Send + 'static, { fn update(&mut self, value: &GenerationalValue) { self(value); } } #[derive(Clone, Debug, Eq, PartialEq)] struct GenerationalValue { pub value: T, pub generation: Generation, } /// 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> { guard: MutexGuard<'a, State>, accessed_mut: bool, } impl<'a, T> Deref for DynamicGuard<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.guard.wrapped.value } } impl<'a, T> DerefMut for DynamicGuard<'a, T> { fn deref_mut(&mut self) -> &mut Self::Target { self.accessed_mut = true; &mut self.guard.wrapped.value } } impl Drop for DynamicGuard<'_, T> { fn drop(&mut self) { if self.accessed_mut { self.guard.note_changed(); } } } /// A reader that tracks the last generation accessed through this reader. #[derive(Debug)] pub struct DynamicReader { source: Arc>, read_generation: Generation, } impl DynamicReader { /// Maps the contents of the dynamic value and returns the result. /// /// This function marks the currently stored value as being read. pub fn map_ref(&mut self, map: impl FnOnce(&T) -> R) -> R { let state = self.source.state(); self.read_generation = state.wrapped.generation; map(&state.wrapped.value) } /// Returns true if the dynamic has been modified since the last time the /// value was accessed through this reader. #[must_use] pub fn has_updated(&self) -> bool { self.source.state().wrapped.generation != self.read_generation } /// Returns a clone of the currently contained value. /// /// This function marks the currently stored value as being read. #[must_use] pub fn get(&mut self) -> T where T: Clone, { let GenerationalValue { value, generation } = self.source.get(); self.read_generation = generation; value } /// 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. pub fn block_until_updated(&mut self) -> bool { let mut state = self.source.state(); loop { if state.wrapped.generation != self.read_generation { return true; } else if state.readers == Arc::strong_count(&self.source) { return false; } state = self .source .sync .wait(state) .map_or_else(PoisonError::into_inner, |g| g); } } /// 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(&mut self) -> BlockUntilUpdatedFuture<'_, T> { BlockUntilUpdatedFuture(self) } } impl Clone for DynamicReader { fn clone(&self) -> Self { self.source.state().readers += 1; Self { source: self.source.clone(), read_generation: self.read_generation, } } } impl Drop for DynamicReader { fn drop(&mut self) { let mut state = self.source.state(); 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 mut 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(); if state.wrapped.generation != self.0.read_generation { return Poll::Ready(true); } else if state.readers == Arc::strong_count(&self.0.source) { return Poll::Ready(false); } state.wakers.push(cx.waker().clone()); Poll::Pending } } #[test] fn disconnecting_reader_from_dynamic() { let value = Dynamic::new(1); let mut ref_reader = value.create_reader(); drop(value); assert!(!ref_reader.block_until_updated()); } #[test] fn disconnecting_reader_threaded() { let a = Dynamic::new(1); let mut a_reader = a.create_reader(); let b = Dynamic::new(1); let mut 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 mut a_reader = a.create_reader(); let b = Dynamic::new(1); let mut 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 `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, { /// Returns [`Dynamic::default()`] with `self` installed as a for-each /// callback. fn into_dynamic(self) -> Dynamic { Dynamic::default().with_for_each(self) } } /// A value that may be either constant or dynamic. #[derive(Debug)] 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_tracked(&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 with exclusive access and returns the result. pub fn map_mut(&mut self, map: impl FnOnce(&mut T) -> R) -> R { match self { Value::Constant(value) => map(value), Value::Dynamic(dynamic) => dynamic.map_mut(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 invalidated when the value is /// updated. pub fn get_tracked(&self, context: &WidgetContext<'_, '_>) -> T where T: Clone, { self.map_tracked(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()), } } /// Marks the widget for redraw when this value is updated. /// /// This function has no effect if the value is constant. pub fn redraw_when_changed(&self, context: &WidgetContext<'_, '_>) { if let Value::Dynamic(dynamic) = self { context.redraw_when_changed(dynamic); } } } 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 IntoValue for Dynamic { fn into_value(self) -> Value { Value::Dynamic(self) } } 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>; /// Apply `for_each` to each value contained within `self`. fn for_each(&self, for_each: F) where F: for<'a> FnMut(Self::Ref<'a>) + Send + 'static; } macro_rules! impl_tuple_for_each { ($($type:ident $field:tt $var:ident),+) => { impl<$($type,)+> ForEach<($($type,)+)> for ($(&Dynamic<$type>,)+) where $($type: Send + 'static,)+ { type Ref<'a> = ($(&'a $type,)+); #[allow(unused_mut)] fn for_each(&self, mut for_each: F) where F: for<'a> FnMut(Self::Ref<'a>) + Send + 'static, { impl_tuple_for_each!(self for_each [] [$($type $field $var),+]); } } }; ($self:ident $for_each:ident [] [$type:ident $field:tt $var:ident]) => { $self.$field.for_each(move |field: &$type| $for_each((field,))); }; ($self:ident $for_each: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 [] [$($type $field $var),+]); }; ( invoke // Identifiers used from the outer method $self:ident $for_each: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 $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 [$($ltype $lfield $lvar,)* $type $field $var] [$($rtype $rfield $rvar),+] ); }; ( invoke // Identifiers used from the outer method $self:ident $for_each: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 $type $field $var [$($ltype $lfield $lvar,)+ $type $field $var] [$($ltype $lfield $lvar),+] ); }; ( invoke // Identifiers used from the outer method $self:ident $for_each: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),+] ) => { $var.for_each((&$for_each, $(&$rvar,)+).with_clone(|(for_each, $($rvar,)+)| { move |$var: &$type| { $(let $rvar = $rvar.lock();)+ let mut for_each = for_each.lock().map_or_else(PoisonError::into_inner, |g| g); (for_each)(($(&$avar,)+)); } })); }; } impl_all_tuples!(impl_tuple_for_each); /// 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>; /// 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 $field:tt $var:ident),+) => { impl MapEach<($($type,)+), U> for ($(&Dynamic<$type>,)+) where U: Send + 'static, $($type: 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.lock();)+ Dynamic::new(map_each(($(&$var,)+))) }; self.for_each({ let dynamic = dynamic.clone(); move |tuple| { dynamic.set(map_each(tuple)); } }); dynamic } } }; } impl_all_tuples!(impl_tuple_map_each);