Skip to main content

guise/reactive/
signal.rs

1//! `Signal` — an observable state cell backed by a gpui entity.
2
3use gpui::{App, AppContext, Entity};
4
5/// A clonable handle to a piece of reactive state. React's `useState` value:
6/// reading is cheap, writing notifies every observer (see [`super::watch`]).
7///
8/// All clones share one backing entity, so passing a `Signal` around — or
9/// providing it as context — gives every holder the same live value.
10pub struct Signal<T> {
11    entity: Entity<T>,
12}
13
14impl<T: 'static> Signal<T> {
15    /// Create a new signal holding `value`.
16    pub fn new(cx: &mut App, value: T) -> Self {
17        Signal {
18            entity: cx.new(|_cx| value),
19        }
20    }
21
22    /// The backing entity — pass to `cx.observe(...)` or [`super::watch`].
23    pub fn entity(&self) -> &Entity<T> {
24        &self.entity
25    }
26
27    /// Borrow the current value.
28    pub fn read<'a>(&self, cx: &'a App) -> &'a T {
29        self.entity.read(cx)
30    }
31
32    /// Clone out the current value.
33    pub fn get(&self, cx: &App) -> T
34    where
35        T: Clone,
36    {
37        self.entity.read(cx).clone()
38    }
39
40    /// Replace the value and notify observers.
41    pub fn set(&self, cx: &mut App, value: T) {
42        self.entity.update(cx, |slot, cx| {
43            *slot = value;
44            cx.notify();
45        });
46    }
47
48    /// Mutate the value in place and notify observers.
49    pub fn update(&self, cx: &mut App, f: impl FnOnce(&mut T)) {
50        self.entity.update(cx, |slot, cx| {
51            f(slot);
52            cx.notify();
53        });
54    }
55}
56
57impl<T> Clone for Signal<T> {
58    fn clone(&self) -> Self {
59        Signal {
60            entity: self.entity.clone(),
61        }
62    }
63}