nami/
distinct.rs

1//! # Distinct Signal Implementation
2//!
3//! This module provides a distinct signal that only notifies on value changes.
4//! This is useful for creating signals that only notify when the value has changed,
5//! rather than on every change.
6
7use core::cell::RefCell;
8
9use alloc::rc::Rc;
10use nami_core::watcher::Context;
11
12use crate::signal::Signal;
13
14/// A distinct signal that only notifies on value changes.
15#[derive(Debug, Clone)]
16pub struct Distinct<S: Signal>
17where
18    S::Output: PartialEq,
19{
20    signal: S,
21    last_value: Rc<RefCell<Option<S::Output>>>,
22}
23
24impl<S: Signal> Distinct<S>
25where
26    S::Output: PartialEq,
27{
28    /// Creates a new distinct signal from the given signal.
29    pub fn new(signal: S) -> Self {
30        Self {
31            signal,
32            last_value: Rc::new(RefCell::new(None)),
33        }
34    }
35}
36
37impl<S: Signal> Signal for Distinct<S>
38where
39    S::Output: PartialEq + Clone,
40{
41    type Output = S::Output;
42    type Guard = S::Guard;
43
44    fn get(&self) -> Self::Output {
45        self.signal.get()
46    }
47
48    fn watch(&self, watcher: impl Fn(Context<Self::Output>) + 'static) -> Self::Guard {
49        let last_value_store = self.last_value.clone();
50        self.signal.watch(move |ctx: Context<S::Output>| {
51            let last_value = last_value_store.borrow();
52            if let Some(last_value) = &*last_value {
53                if last_value != ctx.value() {
54                    *last_value_store.borrow_mut() = Some(ctx.value().clone());
55                    watcher(ctx);
56                }
57            } else {
58                // First time watching, set the last value
59                *last_value_store.borrow_mut() = Some(ctx.value().clone());
60                watcher(ctx);
61            }
62        })
63    }
64}