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
/// The `signal!` macro is used to create signals of all types. It automatically detects
/// the type of the provided data or function and if it implements [PartialEq] or [Hash](std::hash::Hash)
///
/// Arguments:
/// - `scope`: mandatory. The [Scope](crate::Scope) to use when creating the [Signal](crate::Signal)
/// - `clone:`: optional. A space-separated list of data to clone and provide to the function.
/// - `server` | `client`: optional. Whether the signal should run only on the server or the client.
/// - `inner`: the data or function the signal handles.
///
/// Examples:
///
/// - [reactive data signals](Self#Example_of_reactive_data_signals)
/// - [functional reactive signals](Self#Example_of_functional_reactive_signals)
/// - [async functional reactive signals](Self#Example_of_async_functional_reactive_signals)
///
/// # Example of reactive data signals
///
/// ```rust
/// # use reactive_signals::types::*;
/// use reactive_signals::{Scope, Signal, signal, runtimes::ClientRuntime};
///
/// let sc = ClientRuntime::new_root_scope();
///
/// // Create a string signal. Since string implements PartialEq the
/// // signal will only notify it's subscribers if it's value change.
/// let string_sig = signal!(sc, "hi".to_string());
///
/// struct MyNoEqData;
/// // Create a signal from data that doesn't implement equality.
/// // it will always notify the subscribers when it changes.
/// let no_eq_sig = signal!(sc, MyNoEqData);
/// ```
///
/// # Example of functional reactive signals
///
/// ```rust
/// # use reactive_signals::types::*;
/// # use std::cell::RefCell;
/// # use std::rc::Rc;
/// #
/// use reactive_signals::{Scope, Signal, signal, runtimes::ClientRuntime};
///
/// let sc = ClientRuntime::new_root_scope();
///
/// struct MyNoEqData;
///
/// let count_sig = signal!(sc, 4);
///
/// // create a simple functional signal
/// let func_sig = signal!(sc, move || count_sig.get() + 1);
///
/// ///////////// the clone argument /////////////
///
/// let counter = Rc::new(RefCell::new(0));
///
/// // using the clone argument you can provide a space-separated
/// // list of data to clone and provide to the function.
/// let counter_upd = signal!(sc, clone: counter, move || *counter.borrow_mut() += 1);
///
/// // the above is equivalent to:
/// let counter_upd = {
/// let counter = counter.clone();
/// signal!(sc, move || *counter.borrow_mut() += 1)
/// };
///
/// ///////////// client and server only signals /////////////
///
/// // create a signal that only runs on the server
/// let server_func = signal!(sc, server, move || count_sig.get() + 1);
///
/// // create a signal that only runs on the client
/// let client_func = signal!(sc, client, move || count_sig.get() + 1);
/// ```
///
/// # Example of async functional reactive signals
///
/// Note that this has not yet been implemented and the exact details of the API
/// has not been ironed out.
///
/// ```rust ignore
/// // creating an async closure/function is basically the same as normal one
/// let remote_count = signal!(sc, move async || {
/// // some async stuff
/// fetch_usize_count().await
/// });
///
/// // an async signal works just like any other signal, it just waits until
/// // the async closure finishes before notifiying subscribers.
/// signal!(sc, move || println!("Remote count is now: {}", remote_count.get()));
///
/// let async_timer = signal!(sc, 500 ms, move async |&mut interval| {
/// // runs after 500 ms
/// // you can change the interval or stop it by:
/// *interval = None;
/// });
/// ```