Skip to main content

dinamika_core/signal/
computed.rs

1//! A read-only derived (computed) signal ([`Computed`]).
2
3use std::rc::Rc;
4
5/// A derived (computed) signal — read-only.
6///
7/// The value is recomputed on each [`Computed::get`] from the captured signals,
8/// so it is always up to date:
9///
10/// ```
11/// use dinamika_core::*;
12///
13/// let a = Signal::new(2.0_f32);
14/// let b = Signal::new(3.0_f32);
15/// let sum = {
16///     let (a, b) = (a.clone(), b.clone());
17///     Computed::new(move || a.get() + b.get())
18/// };
19/// assert_eq!(sum.get(), 5.0);
20/// a.set(10.0);
21/// assert_eq!(sum.get(), 13.0);
22/// ```
23pub struct Computed<T> {
24    f: Rc<dyn Fn() -> T>,
25}
26
27impl<T> Clone for Computed<T> {
28    fn clone(&self) -> Self {
29        Computed { f: Rc::clone(&self.f) }
30    }
31}
32
33impl<T> Computed<T> {
34    /// Creates a computed signal from a closure.
35    pub fn new(f: impl Fn() -> T + 'static) -> Self {
36        Computed { f: Rc::new(f) }
37    }
38
39    /// Recomputes and returns the current value.
40    pub fn get(&self) -> T {
41        (self.f)()
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use crate::signal::Signal;
49
50    #[test]
51    fn computed_tracks_sources() {
52        let x = Signal::new(4.0_f32);
53        let doubled = {
54            let x = x.clone();
55            Computed::new(move || x.get() * 2.0)
56        };
57        assert_eq!(doubled.get(), 8.0);
58        x.set(5.0);
59        assert_eq!(doubled.get(), 10.0);
60    }
61}