Skip to main content

sequoia_async/
signal_ext.rs

1#![forbid(unsafe_code)]
2
3use futures_core::Future;
4
5use sequoia_reactive::Signal;
6
7pub trait SignalAsyncExt<T: Clone + PartialEq + Send + 'static> {
8    fn async_setter(&self) -> impl Fn(T) + Clone + 'static
9    where
10        Self: Clone;
11}
12
13impl<T: Clone + PartialEq + Send + 'static> SignalAsyncExt<T> for Signal<T> {
14    fn async_setter(&self) -> impl Fn(T) + Clone + 'static
15    where
16        Self: Clone,
17    {
18        let signal = self.clone();
19        move |value: T| signal.set(value)
20    }
21}
22
23pub fn pipe_to_signal<T>(signal: &Signal<T>) -> impl FnOnce(T) + 'static
24where
25    T: Clone + PartialEq + Send + 'static,
26{
27    let signal = signal.clone();
28    move |value: T| signal.set(value)
29}
30
31pub fn pipe_result_to_signal<T, E>(
32    signal: &Signal<T>,
33    on_error: impl FnOnce(E) + 'static,
34) -> impl FnOnce(Result<T, E>) + 'static
35where
36    T: Clone + PartialEq + Send + 'static,
37    E: Send + 'static,
38{
39    let signal = signal.clone();
40    move |result: Result<T, E>| match result {
41        Ok(v) => signal.set(v),
42        Err(e) => on_error(e),
43    }
44}
45
46#[allow(dead_code)]
47pub(crate) fn assert_ui_future<T: Send, F: Future<Output = T>>(_: &F) {}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn pipe_writes_to_signal() {
55        let s = Signal::new(0u32);
56        let apply = pipe_to_signal(&s);
57        apply(5);
58        assert_eq!(s.get_untracked(), 5);
59    }
60
61    #[test]
62    fn pipe_result_routes_ok_and_err() {
63        let s = Signal::new(0u32);
64        let apply = pipe_result_to_signal(&s, |e: String| assert_eq!(e, "boom"));
65        apply(Ok(3));
66        assert_eq!(s.get_untracked(), 3);
67        let s2 = Signal::new(0u32);
68        let apply2 = pipe_result_to_signal(&s2, |e: String| assert_eq!(e, "boom"));
69        apply2(Err("boom".to_string()));
70        assert_eq!(s2.get_untracked(), 0);
71    }
72}