//! Types for storing and interacting with values in Widgets. use std::fmt::Debug; use std::future::Future; 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}; /// 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)) } /// 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)); } /// 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 } /// 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: Eq, { 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() } 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.wrapped.generation = state.wrapped.generation.next(); for callback in &mut state.callbacks { callback.update(&state.wrapped); } for window in state.windows.drain(..) { window.redraw(); } for waker in state.wakers.drain(..) { waker.wake(); } } 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 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, } /// 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 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 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 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 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)) } }