nosy/source.rs
1//! Containers for single values which notify when the value is changed.
2
3use core::fmt;
4use core::marker::PhantomData;
5
6use alloc::sync::Arc;
7
8#[cfg(doc)]
9use crate::Notifier;
10use crate::{FromListener, IntoListener, Listen, Listener};
11
12// -------------------------------------------------------------------------------------------------
13
14mod flatten;
15pub use flatten::Flatten;
16
17mod map;
18pub use map::Map;
19
20// -------------------------------------------------------------------------------------------------
21
22/// Access to a value that might change and notifications when it does.
23///
24/// The change notifications given are of type `()`; they do not allow access to the new value.
25/// This is an unfortunate necessity to allow sources to deliver notifications
26/// *after* the value has changed (i.e. while not holding any lock) without also needing a clone
27/// of, or reference-counted pointer to, the value.
28/// (Listeners are, as always, encouraged not to do significant work,
29/// so, while a listener could *try* calling [`Source::get()`] immediately,
30/// this is not the intended architecture and is not guaranteed to work.)
31///
32/// If a `Source` is known to be in a state such that its value will never change again,
33/// then it should drop all of its current and future listeners.
34/// This may typically be accomplished through [`Notifier::close()`].
35///
36/// The type aliases [`sync::DynSource`](crate::sync::DynSource)
37/// and [`unsync::DynSource`](crate::unsync::DynSource) are available for type-erased `Source`s
38/// with type-erased `Listener`s. If you want a value and don’t care about the type of the source
39/// it comes from, use them.
40///
41/// Additional traits sources may implement:
42///
43/// * They should, but are not required to, implement [`Clone`]; if they do, all clones
44/// should have identical future behavior (values returned and messages sent).
45/// * They should implement [`fmt::Debug`] in a way which identifies the source rather than only
46/// its current value, if this is possible possible without printing memory addresses or other
47/// non-deterministic information.
48/// * They should implement [`fmt::Pointer`] to print an address or other information which
49/// uniquely identifies the source, if possible.
50//---
51// Design note: All `Source`s must implement `Debug`;
52// ideally, only `DynSource` would have this requirement, but that is not possible since it would be
53// a trait object with two non-marker traits, unless we also introduced another public trait
54// dedicated to the purpose, which would be messy. As I see it, “everything must implement Debug”
55// is not too onerous a requirement and a much better choice than “you can get no debug info”.
56pub trait Source: Listen<Msg = ()> + fmt::Debug {
57 /// The type of value which can be obtained from this source.
58 ///
59 /// This type should usually be clonable (because in any case, arbitrary copies of it
60 /// can be obtained from [`Source::get()`]), but this is not required.
61 type Value;
62
63 /// Returns the most recent value.
64 ///
65 /// # Panics
66 ///
67 /// This method may, but is not required or expected to, panic if called from within
68 /// one of this source’s listeners.
69 #[must_use]
70 fn get(&self) -> Self::Value;
71
72 /// Takes a function and produces a [`Source`] which applies that function to the values of
73 /// `self`.
74 ///
75 /// # Caveats
76 ///
77 /// Note that the function is called *every* time [`get()`](Source::get) is called, and that
78 /// change notifications will be forwarded regardless of whether the mapped output changed;
79 /// there is no caching.
80 /// Therefore, it is important that the function should be cheap, and if it is likely that the
81 /// output value will change less often than the input value, then a different approach
82 /// should be used.
83 ///
84 // TODO: give example of such a different approach — like a dependent cell.
85 // Perhaps we should have a value-comparing adapter which filters notifications, too...
86 // but that requires scheduling `get()`s.
87 ///
88 /// # Example
89 ///
90 /// ```
91 /// use nosy::{unsync::Cell, Source as _};
92 ///
93 /// let cell: Cell<i32> = Cell::new(1);
94 /// let source = cell.as_source().map(|value| value * 100);
95 /// assert_eq!(source.get(), 100);
96 ///
97 /// cell.set(2);
98 /// assert_eq!(source.get(), 200);
99 /// ```
100 fn map<F, O>(self, function: F) -> Map<Self, F>
101 where
102 Self: Sized,
103 F: Fn(Self::Value) -> O,
104 {
105 Map {
106 source: self,
107 function,
108 }
109 }
110
111 /// Converts a source of sources of some value into a source of that value.
112 ///
113 /// # Caveats
114 ///
115 /// The current implementation of [`Flatten`] uses an internal mutex.
116 /// This mutex is locked while [`Flatten::get()`] is called, and while it is locked,
117 /// `<Self::Value as Clone>::clone()` may be called.
118 /// Therefore, if that `clone()` attempts to acquire a lock on something
119 /// locked by the caller of [`Flatten::get()`], a deadlock would occur.
120 /// This should generally not be a risk because cloning most [`Source`]s should be purely a
121 /// reference count update; you can enforce this by making sure that `Self::Value`
122 /// is some variety of [`Arc`], such as [`sync::DynSource`](crate::sync::DynSource).
123 ///
124 /// # Example
125 ///
126 /// ```
127 /// use std::sync::Arc;
128 /// use nosy::{unsync::{Cell, DynSource}, Source as _};
129 ///
130 /// let cell_inner_1: Cell<i32> = Cell::new(100);
131 /// let cell_inner_2: Cell<i32> = Cell::new(200);
132 /// let cell_outer: Cell<DynSource<i32>> = Cell::new(cell_inner_1.as_source());
133 ///
134 /// let flattened_source: DynSource<i32> = Arc::new(cell_outer.as_source().flatten());
135 /// assert_eq!(flattened_source.get(), 100);
136 ///
137 /// cell_inner_1.set(101);
138 /// assert_eq!(flattened_source.get(), 101);
139 ///
140 /// cell_outer.set(cell_inner_2.as_source());
141 /// assert_eq!(flattened_source.get(), 200);
142 ///
143 /// cell_inner_2.set(201);
144 /// assert_eq!(flattened_source.get(), 201);
145 /// ```
146 fn flatten(self) -> Flatten<Self>
147 where
148 Self: Sized,
149 Self::Value: Source + Clone,
150 Self::Listener: FromListener<flatten::OuterListener<Self>, ()>,
151 <Self::Value as Listen>::Listener: FromListener<flatten::InnerListener<Self>, ()>,
152 {
153 Flatten::new(self)
154 }
155}
156
157impl<T: ?Sized + Source> Source for &T {
158 type Value = T::Value;
159 fn get(&self) -> Self::Value {
160 T::get(*self)
161 }
162}
163impl<T: ?Sized + Source> Source for &mut T {
164 type Value = T::Value;
165 fn get(&self) -> Self::Value {
166 T::get(*self)
167 }
168}
169impl<T: ?Sized + Source> Source for alloc::boxed::Box<T> {
170 type Value = T::Value;
171 fn get(&self) -> Self::Value {
172 T::get(&**self)
173 }
174}
175impl<T: ?Sized + Source> Source for alloc::rc::Rc<T> {
176 type Value = T::Value;
177 fn get(&self) -> Self::Value {
178 T::get(&**self)
179 }
180}
181impl<T: ?Sized + Source> Source for alloc::sync::Arc<T> {
182 type Value = T::Value;
183 fn get(&self) -> Self::Value {
184 T::get(&**self)
185 }
186}
187
188// -------------------------------------------------------------------------------------------------
189
190/// A [`Source`] of a constant value; never sends a change notification.
191///
192/// # Generic parameters
193///
194/// * `T` is the type of the value.
195/// * `L` is the type of [`Listener`] this source accepts but never uses
196/// (necessary to implement [`Listen`]).
197///
198/// # Example
199///
200/// ```
201/// use nosy::{unsync::Constant, Source as _};
202///
203/// let constant: Constant<i32> = Constant::new(3);
204///
205/// assert_eq!(constant.map(|x| x * 10).get(), 30);
206/// ```
207// TODO: give a better example than this, that illustrates its usage better somehow
208pub struct Constant<T, L> {
209 value: T,
210 _phantom: PhantomData<fn(L)>,
211}
212
213impl<T, L> Constant<T, L> {
214 /// Constructs a [`Constant`] whose [`get()`](Source::get) always returns a clone of `value`.
215 pub const fn new(value: T) -> Self {
216 Self {
217 value,
218 _phantom: PhantomData,
219 }
220 }
221
222 /// Destroys this [`Constant`] and returns the value it contained.
223 pub fn into_inner(self) -> T {
224 self.value
225 }
226}
227
228impl<T, L: Listener<()>> Listen for Constant<T, L> {
229 type Msg = ();
230 type Listener = L;
231
232 fn listen<L2: IntoListener<L, ()>>(&self, _: L2) {
233 // do nothing, skipping the boxing that would happen if we only implemented listen_raw()
234 }
235 fn listen_raw(&self, _: Self::Listener) {}
236}
237
238// Design note: If it were possible, we would not have this `Debug` bound.
239// It is necessary because `Source` requires `Debug` (see its comments), and our own `Debug`
240// implementation prints the value (it would be useless otherwise).
241impl<T: Clone + fmt::Debug, L: Listener<()>> Source for Constant<T, L> {
242 type Value = T;
243 fn get(&self) -> Self::Value {
244 self.value.clone()
245 }
246}
247
248impl<T: fmt::Debug, L> core::fmt::Debug for Constant<T, L> {
249 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
250 f.debug_tuple("Constant").field(&self.value).finish()
251 }
252}
253
254impl<T: Copy, L> Copy for Constant<T, L> {}
255impl<T: Clone, L> Clone for Constant<T, L> {
256 fn clone(&self) -> Self {
257 Self {
258 value: self.value.clone(),
259 _phantom: PhantomData,
260 }
261 }
262}
263
264impl<T: Eq, L> Eq for Constant<T, L> {}
265impl<T: PartialEq, L> PartialEq for Constant<T, L> {
266 fn eq(&self, other: &Self) -> bool {
267 self.value == other.value
268 }
269}
270
271impl<T: core::hash::Hash, L> core::hash::Hash for Constant<T, L> {
272 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
273 self.value.hash(state);
274 }
275}
276
277impl<T: Ord, L> Ord for Constant<T, L> {
278 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
279 self.value.cmp(&other.value)
280 }
281}
282impl<T: PartialOrd, L> PartialOrd for Constant<T, L> {
283 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
284 self.value.partial_cmp(&other.value)
285 }
286}
287
288impl<T: Default, L> Default for Constant<T, L> {
289 fn default() -> Self {
290 Self {
291 value: Default::default(),
292 _phantom: PhantomData,
293 }
294 }
295}
296
297impl<T, L> AsRef<T> for Constant<T, L> {
298 fn as_ref(&self) -> &T {
299 &self.value
300 }
301}
302
303impl<T, L> core::borrow::Borrow<T> for Constant<T, L> {
304 fn borrow(&self) -> &T {
305 &self.value
306 }
307}
308
309impl<T, L> From<T> for Constant<T, L> {
310 fn from(value: T) -> Self {
311 Self::new(value)
312 }
313}
314
315// Convenience conversions directly to coerced trait object,
316// instead of `Arc::new()` followed by coercion.
317impl<T> From<Constant<T, crate::unsync::DynListener<()>>> for crate::unsync::DynSource<T>
318where
319 T: Clone + fmt::Debug + 'static,
320{
321 fn from(value: Constant<T, crate::unsync::DynListener<()>>) -> Self {
322 Arc::new(value)
323 }
324}
325impl<T> From<Constant<T, crate::sync::DynListener<()>>> for crate::sync::DynSource<T>
326where
327 T: Clone + fmt::Debug + Send + Sync + 'static,
328{
329 fn from(value: Constant<T, crate::sync::DynListener<()>>) -> Self {
330 Arc::new(value)
331 }
332}