floem_reactive/
read.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
use std::{
    cell::{Ref, RefCell},
    rc::Rc,
};

use crate::id::Id;

#[derive(Clone)]
pub struct ReadSignalValue<T> {
    pub(crate) value: Rc<RefCell<T>>,
}

impl<T> ReadSignalValue<T> {
    /// Borrows the current value stored in the Signal
    pub fn borrow(&self) -> Ref<'_, T> {
        self.value.borrow()
    }
}

pub trait SignalGet<T: Clone> {
    /// get the Signal Id
    fn id(&self) -> Id;

    /// Clones and returns the current value stored in the Signal, but it doesn't subscribe
    /// to the current running effect.
    fn get_untracked(&self) -> T
    where
        T: 'static,
    {
        self.try_get_untracked().unwrap()
    }

    /// Clones and returns the current value stored in the Signal, and subscribes
    /// to the current running effect to this Signal.
    fn get(&self) -> T
    where
        T: 'static,
    {
        self.try_get().unwrap()
    }

    /// Try to clone and return the current value stored in the Signal, and returns None
    /// if it's already disposed. It subscribes to the current running effect.
    fn try_get(&self) -> Option<T>
    where
        T: 'static,
    {
        self.id().signal().map(|signal| signal.get())
    }

    /// Try to clone and return the current value stored in the Signal, and returns None
    /// if it's already disposed. It doesn't subscribe to the current running effect.
    fn try_get_untracked(&self) -> Option<T>
    where
        T: 'static,
    {
        self.id().signal().map(|signal| signal.get_untracked())
    }
}

pub trait SignalTrack<T> {
    fn id(&self) -> Id;
    /// Only subscribes to the current running effect to this Signal.
    ///
    fn track(&self) {
        self.id().signal().unwrap().subscribe();
    }

    /// If the signal isn't disposed,
    // subscribes to the current running effect to this Signal.
    fn try_track(&self) {
        if let Some(signal) = self.id().signal() {
            signal.subscribe();
        }
    }
}

pub trait SignalWith<T> {
    /// get the Signal Id
    fn id(&self) -> Id;

    /// Applies a closure to the current value stored in the Signal, and subscribes
    /// to the current running effect to this Memo.
    fn with<O>(&self, f: impl FnOnce(&T) -> O) -> O
    where
        T: 'static,
    {
        self.id().signal().unwrap().with(f)
    }

    /// Applies a closure to the current value stored in the Signal, but it doesn't subscribe
    /// to the current running effect.
    fn with_untracked<O>(&self, f: impl FnOnce(&T) -> O) -> O
    where
        T: 'static,
    {
        self.id().signal().unwrap().with_untracked(f)
    }

    /// If the signal isn't disposed, applies a closure to the current value stored in the Signal.
    /// It subscribes to the current running effect.
    fn try_with<O>(&self, f: impl FnOnce(Option<&T>) -> O) -> O
    where
        T: 'static,
    {
        if let Some(signal) = self.id().signal() {
            signal.with(|v| f(Some(v)))
        } else {
            f(None)
        }
    }

    /// If the signal isn't disposed, applies a closure to the current value stored in the Signal,
    /// but it doesn't subscribe to the current running effect.
    fn try_with_untracked<O>(&self, f: impl FnOnce(Option<&T>) -> O) -> O
    where
        T: 'static,
    {
        if let Some(signal) = self.id().signal() {
            signal.with_untracked(|v| f(Some(v)))
        } else {
            f(None)
        }
    }
}

pub trait SignalRead<T> {
    /// get the Signal Id
    fn id(&self) -> Id;

    /// Reads the data stored in the Signal to a RefCell, so that you can `borrow()`
    /// and access the data.
    /// It subscribes to the current running effect.
    fn read(&self) -> ReadSignalValue<T>
    where
        T: 'static,
    {
        self.try_read().unwrap()
    }

    /// Reads the data stored in the Signal to a RefCell, so that you can `borrow()`
    /// and access the data.
    /// It doesn't subscribe to the current running effect.
    fn read_untracked(&self) -> ReadSignalValue<T>
    where
        T: 'static,
    {
        self.try_read_untracked().unwrap()
    }

    /// If the signal isn't disposed,
    /// reads the data stored in the Signal to a RefCell, so that you can `borrow()`
    /// and access the data.
    /// It subscribes to the current running effect.
    fn try_read(&self) -> Option<ReadSignalValue<T>>
    where
        T: 'static,
    {
        if let Some(signal) = self.id().signal() {
            signal.subscribe();
            Some(ReadSignalValue {
                value: signal
                    .value
                    .clone()
                    .downcast::<RefCell<T>>()
                    .expect("to downcast signal type"),
            })
        } else {
            None
        }
    }

    /// If the signal isn't disposed,
    /// reads the data stored in the Signal to a RefCell, so that you can `borrow()`
    /// and access the data.
    /// It doesn't subscribe to the current running effect.
    fn try_read_untracked(&self) -> Option<ReadSignalValue<T>>
    where
        T: 'static,
    {
        if let Some(signal) = self.id().signal() {
            Some(ReadSignalValue {
                value: signal
                    .value
                    .clone()
                    .downcast::<RefCell<T>>()
                    .expect("to downcast signal type"),
            })
        } else {
            None
        }
    }
}