1use std::{
2 any::Any, cell::RefCell, collections::HashSet, fmt, marker::PhantomData, rc::Rc, sync::Arc,
3};
4
5use parking_lot::Mutex;
6
7use crate::{
8 create_effect, create_updater,
9 id::Id,
10 memo::{create_memo, Memo},
11 runtime::{Runtime, RUNTIME},
12 signal::{ReadSignal, RwSignal, SignalState, SignalValue, WriteSignal},
13 storage::{SyncStorage, UnsyncStorage},
14 trigger::{create_trigger, Trigger},
15};
16
17#[derive(Clone, Copy)]
23pub struct Scope(pub(crate) Id, pub(crate) PhantomData<()>);
24
25impl Default for Scope {
26 fn default() -> Self {
27 Self::new()
28 }
29}
30
31impl fmt::Debug for Scope {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 let mut s = f.debug_struct("Scope");
34 s.field("id", &self.0);
35 s.finish()
36 }
37}
38
39impl Scope {
40 pub fn new() -> Self {
42 Self(Id::next(), PhantomData)
43 }
44
45 pub fn current() -> Scope {
48 RUNTIME.with(|runtime| Scope(*runtime.current_scope.borrow(), PhantomData))
49 }
50
51 pub fn create_child(&self) -> Scope {
53 let child = Id::next();
54 RUNTIME.with(|runtime| {
55 runtime
56 .children
57 .borrow_mut()
58 .entry(self.0)
59 .or_default()
60 .insert(child);
61 runtime.parents.borrow_mut().insert(child, self.0);
62 });
63 Scope(child, PhantomData)
64 }
65
66 #[cfg_attr(debug_assertions, track_caller)]
68 pub fn create_signal<T>(self, value: T) -> (ReadSignal<T>, WriteSignal<T>)
69 where
70 T: Any + 'static,
71 {
72 self.enter(|| RwSignal::new_split(value))
73 }
74
75 #[cfg_attr(debug_assertions, track_caller)]
77 pub fn create_rw_signal<T>(self, value: T) -> RwSignal<T>
78 where
79 T: Any + 'static,
80 {
81 self.enter(|| RwSignal::new(value))
82 }
83
84 #[cfg_attr(debug_assertions, track_caller)]
86 pub fn create_sync_signal<T>(
87 self,
88 value: T,
89 ) -> (ReadSignal<T, SyncStorage>, WriteSignal<T, SyncStorage>)
90 where
91 T: Any + Send + Sync + 'static,
92 {
93 self.enter(|| RwSignal::<T, SyncStorage>::new_sync_split(value))
94 }
95
96 #[cfg_attr(debug_assertions, track_caller)]
98 pub fn create_sync_rw_signal<T>(self, value: T) -> RwSignal<T, SyncStorage>
99 where
100 T: Any + Send + Sync + 'static,
101 {
102 self.enter(|| RwSignal::<T, SyncStorage>::new_sync(value))
103 }
104
105 #[cfg_attr(debug_assertions, track_caller)]
107 pub fn create_local_signal<T>(
108 self,
109 value: T,
110 ) -> (ReadSignal<T, UnsyncStorage>, WriteSignal<T, UnsyncStorage>)
111 where
112 T: Any + 'static,
113 {
114 self.enter(|| RwSignal::new_split(value))
115 }
116
117 #[cfg_attr(debug_assertions, track_caller)]
119 pub fn create_local_rw_signal<T>(self, value: T) -> RwSignal<T, UnsyncStorage>
120 where
121 T: Any + 'static,
122 {
123 self.enter(|| RwSignal::new(value))
124 }
125
126 #[cfg_attr(debug_assertions, track_caller)]
128 pub fn create_memo<T>(self, f: impl Fn(Option<&T>) -> T + 'static) -> Memo<T>
129 where
130 T: PartialEq + 'static,
131 {
132 self.enter(|| create_memo(f))
133 }
134
135 #[cfg_attr(debug_assertions, track_caller)]
137 pub fn create_trigger(self) -> Trigger {
138 self.enter(create_trigger)
139 }
140
141 #[cfg_attr(debug_assertions, track_caller)]
143 pub fn create_effect<T>(self, f: impl Fn(Option<T>) -> T + 'static)
144 where
145 T: Any + 'static,
146 {
147 self.enter(|| create_effect(f))
148 }
149
150 #[cfg_attr(debug_assertions, track_caller)]
152 pub fn create_updater<R>(
153 self,
154 compute: impl Fn() -> R + 'static,
155 on_change: impl Fn(R) + 'static,
156 ) -> R
157 where
158 R: 'static,
159 {
160 self.enter(|| create_updater(compute, on_change))
161 }
162
163 pub fn provide_context<T>(&self, value: T)
182 where
183 T: Clone + 'static,
184 {
185 self.enter(|| crate::context::Context::provide(value))
186 }
187
188 pub fn get_context<T>(&self) -> Option<T>
209 where
210 T: Clone + 'static,
211 {
212 self.enter(crate::context::Context::get::<T>)
213 }
214
215 #[cfg_attr(debug_assertions, track_caller)]
217 pub fn enter<T>(&self, f: impl FnOnce() -> T) -> T
218 where
219 T: 'static,
220 {
221 Runtime::assert_ui_thread();
222 let prev_scope = RUNTIME.with(|runtime| {
223 let mut current_scope = runtime.current_scope.borrow_mut();
224 let prev_scope = *current_scope;
225 *current_scope = self.0;
226 prev_scope
227 });
228
229 let result = f();
230
231 RUNTIME.with(|runtime| {
232 *runtime.current_scope.borrow_mut() = prev_scope;
233 });
234
235 result
236 }
237
238 #[cfg_attr(debug_assertions, track_caller)]
240 pub fn enter_child<T, U>(&self, f: impl Fn(T) -> U + 'static) -> impl Fn(T) -> (U, Scope)
241 where
242 T: 'static,
243 {
244 Runtime::assert_ui_thread();
245 let parent = *self;
246 move |t| {
247 let scope = parent.create_child();
248 let prev_scope = RUNTIME.with(|runtime| {
249 let mut current_scope = runtime.current_scope.borrow_mut();
250 let prev_scope = *current_scope;
251 *current_scope = scope.0;
252 prev_scope
253 });
254
255 let result = f(t);
256
257 RUNTIME.with(|runtime| {
258 *runtime.current_scope.borrow_mut() = prev_scope;
259 });
260
261 (result, scope)
262 }
263 }
264
265 #[cfg_attr(debug_assertions, track_caller)]
268 pub fn track(&self) {
269 Runtime::assert_ui_thread();
270 let signal = if let Some(signal) = self.0.signal() {
271 signal
272 } else {
273 let signal = SignalState {
274 id: self.0,
275 subscribers: Arc::new(Mutex::new(HashSet::new())),
276 value: SignalValue::Local(Rc::new(RefCell::new(()))),
277 };
278 self.0.add_signal(signal.clone());
279 signal
280 };
281 signal.subscribe();
282 }
283
284 pub fn dispose(&self) {
287 self.0.dispose();
288 }
289}
290
291#[deprecated(
292 since = "0.2.0",
293 note = "Use Scope::enter instead; this will be removed in a future release"
294)]
295pub fn with_scope<T>(scope: Scope, f: impl FnOnce() -> T) -> T
297where
298 T: 'static,
299{
300 scope.enter(f)
301}
302
303#[deprecated(
306 since = "0.2.0",
307 note = "Use Scope::current().enter_child instead; this will be removed in a future release"
308)]
309pub fn as_child_of_current_scope<T, U>(f: impl Fn(T) -> U + 'static) -> impl Fn(T) -> (U, Scope)
310where
311 T: 'static,
312{
313 Scope::current().enter_child(f)
314}