silkenweb_signals_ext/
value.rs

1//! Abstract over the signal/value-ness of types.
2//!
3//! This allows you to write a single function that works for both signals and
4//! values.
5//!
6//! # Example
7//!
8//! ```
9//! # use futures_signals::signal::{Mutable, SignalExt};
10//! # use silkenweb_signals_ext::value::*;
11//! # use std::future::Future;
12//! #
13//! struct Exec;
14//!
15//! impl Executor for Exec {
16//!     fn spawn(&mut self, future: impl Future<Output = ()> + 'static) {
17//!         // This is a stub `Executor` for brevity. In real code, it should
18//!         // run the future.
19//!     }
20//! }
21//!
22//! fn increment_and_print(x: impl SignalOrValue<Item = i32>) {
23//!     x.map(|x| x + 1).select_spawn(
24//!         |_exec, x| println!("{x}"),
25//!         |exec, x| {
26//!             x.for_each(|x| {
27//!                 println!("{x}");
28//!                 async {}
29//!             })
30//!         },
31//!         &mut Exec,
32//!     );
33//! }
34//!
35//! let x_signal = Mutable::new(0);
36//! let x_value = 0;
37//!
38//! increment_and_print(x_value);
39//! increment_and_print(Sig(x_signal.signal()));
40//! ```
41use std::future::Future;
42
43use futures_signals::signal::{self, Always, Signal, SignalExt};
44
45/// Newtype wrapper to mark this type as a signal.
46///
47/// For use with [`SignalOrValue`] and [`RefSignalOrValue`]
48pub struct Sig<T>(pub T);
49
50/// Newtype wrapper to mark this type as a static value.
51///
52/// For use with [`SignalOrValue`] and [`RefSignalOrValue`] for when you can't
53/// implement [`Value`] for a type.
54pub struct Val<T>(pub T);
55
56/// Abstract over a type that can be a value or a signal of an underlying type.
57pub trait RefSignalOrValue<'a> {
58    /// The underlying type of the value or signal.
59    type Item: 'a;
60    /// The signal type. Use [`Always`] for value types.
61    type Signal: Signal<Item = Self::Item> + 'a;
62    /// The return type for [`Self::map`].
63    ///
64    /// `Map` needs a separate lifetime `'b` so that we can map from `Self` to
65    /// something with a longer lifetime. For example, mapping `&str` to
66    /// `String`.
67    type Map<'b, F, R>: RefSignalOrValue<'b, Item = R> + 'b
68    where
69        'b: 'a,
70        F: FnMut(Self::Item) -> R + 'b,
71        R: RefSignalOrValue<'b, Item = R> + 'b;
72
73    /// Map a function over this signal/value to produce a new signal/value.
74    fn map<'b: 'a, F, R>(self, callback: F) -> Self::Map<'b, F, R>
75    where
76        R: RefSignalOrValue<'b, Item = R> + 'b,
77        F: FnMut(Self::Item) -> R + 'b;
78
79    /// Select a function based on whether this is a signal or value.
80    ///
81    /// # Params
82    ///
83    /// - `fn_val`: The function to call if this is a value.
84    /// - `fn_sig`: The function to call if this is a signal.
85    /// - `data`: Some data for the function to consume. This is useful if
86    ///   either of the functions needs to consume some data.
87    fn select<FVal, FSig, Data, Out>(self, fn_val: FVal, fn_sig: FSig, data: Data) -> Out
88    where
89        FVal: FnOnce(Data, Self::Item) -> Out,
90        FSig: FnOnce(Data, Self::Signal) -> Out,
91        Self: Sized;
92
93    /// Select a function based on whether this is a signal or value.
94    ///
95    /// For signal types, this will spawn the task produced by `fn_sig` with
96    /// `exec`.
97    ///
98    /// # Params
99    ///
100    /// - `fn_val`: The function to call if this is a value.
101    /// - `fn_sig`: The function to call if this is a signal.
102    /// - `executor`: An [`Executor`] to spawn the task from `fn_sig`.
103    fn select_spawn<FVal, FSig, Task, Exec>(self, fn_val: FVal, fn_sig: FSig, executor: &mut Exec)
104    where
105        FVal: FnOnce(&mut Exec, Self::Item),
106        FSig: FnOnce(&mut Exec, Self::Signal) -> Task,
107        Task: Future<Output = ()> + 'a,
108        Exec: Executor;
109}
110
111/// Like [`RefSignalOrValue`], when you know the type is `'static`.
112pub trait SignalOrValue: RefSignalOrValue<'static> {}
113
114impl<T: RefSignalOrValue<'static>> SignalOrValue for T {}
115
116/// A type that can spawn futures.
117pub trait Executor {
118    fn spawn(&mut self, future: impl Future<Output = ()> + 'static);
119}
120
121/// Marker trait for values that can be used with [`RefSignalOrValue`].
122pub trait RefValue<'a> {}
123
124/// Marker trait for values that can be used with [`SignalOrValue`].
125pub trait Value: RefValue<'static> {}
126
127impl<T: Value> RefValue<'static> for T {}
128
129macro_rules! static_values{
130    ($($t:ty),*) => {
131        $(
132            impl Value for $t {}
133        )*
134    }
135}
136
137static_values!(i8, i16, i32, i64);
138static_values!(u8, u16, u32, u64);
139static_values!(f32, f64);
140static_values!(bool, String);
141
142impl<'a> RefValue<'a> for &'a str {}
143impl<'a> RefValue<'a> for &'a String {}
144impl<'a, T: 'a> RefValue<'a> for Option<T> {}
145impl<'a, T: 'a> RefValue<'a> for [T] {}
146impl<'a, T: 'a> RefValue<'a> for &'a [T] {}
147impl<'a, const COUNT: usize, T: 'a> RefValue<'a> for [T; COUNT] {}
148
149impl RefValue<'_> for () {}
150
151macro_rules! tuple_values {
152    ($t:ident $(,)?) => {};
153    ($t0:ident, $t1:ident $(, $tail:ident)* $(,)?) => {
154        impl<'a, $t0, $t1 $(, $tail)*> RefValue<'a> for ($t0, $t1 $(, $tail)*) {}
155
156        tuple_values!($t1, $($tail),*);
157    }
158}
159
160tuple_values!(A, B, C, D, E, F, G, H, I, J);
161
162impl<'a, T> RefSignalOrValue<'a> for T
163where
164    T: RefValue<'a> + 'a,
165{
166    type Item = Self;
167    type Map<'b, F, R>
168        = R
169    where
170        'b: 'a,
171        F: FnMut(Self::Item) -> R + 'b,
172        R: RefSignalOrValue<'b, Item = R> + 'b;
173    type Signal = Always<Self::Item>;
174
175    fn map<'b: 'a, F, R>(self, mut callback: F) -> Self::Map<'b, F, R>
176    where
177        R: RefSignalOrValue<'b, Item = R> + 'b,
178        F: FnMut(Self::Item) -> R + 'b,
179    {
180        callback(self)
181    }
182
183    fn select<FVal, FSig, Data, Out>(self, fn_val: FVal, _fn_sig: FSig, data: Data) -> Out
184    where
185        FVal: FnOnce(Data, Self::Item) -> Out,
186        FSig: FnOnce(Data, Self::Signal) -> Out,
187    {
188        fn_val(data, self)
189    }
190
191    fn select_spawn<FVal, FSig, Task, Exec>(self, fn_val: FVal, _fn_sig: FSig, executor: &mut Exec)
192    where
193        FVal: FnOnce(&mut Exec, Self::Item),
194        FSig: FnOnce(&mut Exec, Self::Signal) -> Task,
195        Task: Future<Output = ()> + 'a,
196        Exec: Executor,
197    {
198        fn_val(executor, self)
199    }
200}
201
202impl<'a, T> RefSignalOrValue<'a> for Val<T>
203where
204    T: 'static,
205{
206    type Item = T;
207    type Map<'b, F, R>
208        = R
209    where
210        'b: 'a,
211        F: FnMut(Self::Item) -> R + 'b,
212        R: RefSignalOrValue<'b, Item = R> + 'b;
213    type Signal = Always<Self::Item>;
214
215    fn map<'b: 'a, F, R>(self, mut callback: F) -> Self::Map<'b, F, R>
216    where
217        R: RefSignalOrValue<'b, Item = R> + 'b,
218        F: FnMut(Self::Item) -> R + 'b,
219    {
220        callback(self.0)
221    }
222
223    fn select<FVal, FSig, Data, Out>(self, fn_val: FVal, _fn_sig: FSig, data: Data) -> Out
224    where
225        FVal: FnOnce(Data, Self::Item) -> Out,
226        FSig: FnOnce(Data, Self::Signal) -> Out,
227    {
228        fn_val(data, self.0)
229    }
230
231    fn select_spawn<FVal, FSig, Task, Exec>(self, fn_val: FVal, _fn_sig: FSig, executor: &mut Exec)
232    where
233        FVal: FnOnce(&mut Exec, Self::Item),
234        FSig: FnOnce(&mut Exec, Self::Signal) -> Task,
235        Task: Future<Output = ()> + 'a,
236        Exec: Executor,
237    {
238        fn_val(executor, self.0)
239    }
240}
241
242impl<T, S> RefSignalOrValue<'static> for Sig<S>
243where
244    T: 'static,
245    S: Signal<Item = T> + 'static,
246{
247    type Item = T;
248    type Map<'b, F, R>
249        = Sig<signal::Map<S, F>>
250    where
251        'b: 'static,
252        F: FnMut(Self::Item) -> R + 'b,
253        R: RefSignalOrValue<'b, Item = R> + 'b;
254    type Signal = S;
255
256    fn map<'b, F, R>(self, callback: F) -> Self::Map<'b, F, R>
257    where
258        'b: 'static,
259        R: RefSignalOrValue<'b, Item = R> + 'b,
260        F: FnMut(Self::Item) -> R + 'b,
261    {
262        Sig(self.0.map(callback))
263    }
264
265    fn select<FVal, FSig, Data, Out>(self, _fn_val: FVal, fn_sig: FSig, data: Data) -> Out
266    where
267        FVal: FnOnce(Data, Self::Item) -> Out,
268        FSig: FnOnce(Data, Self::Signal) -> Out,
269    {
270        fn_sig(data, self.0)
271    }
272
273    fn select_spawn<FVal, FSig, Task, Exec>(self, _fn_val: FVal, fn_sig: FSig, executor: &mut Exec)
274    where
275        FVal: FnOnce(&mut Exec, Self::Item),
276        FSig: FnOnce(&mut Exec, Self::Signal) -> Task,
277        Task: Future<Output = ()> + 'static,
278        Exec: Executor,
279    {
280        let future = fn_sig(executor, self.0);
281        executor.spawn(future)
282    }
283}