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::{Memo, create_memo},
11 runtime::{RUNTIME, Runtime},
12 signal::{ReadSignal, RwSignal, SignalState, SignalValue, WriteSignal},
13 storage::{SyncStorage, UnsyncStorage},
14 trigger::{Trigger, create_trigger},
15};
16
17#[derive(Clone, Copy, PartialEq, Eq)]
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 pub fn set_parent(&self, new_parent: Scope) {
82 RUNTIME.with(|runtime| {
83 if let Some(old_parent) = runtime.parents.borrow_mut().remove(&self.0)
85 && let Some(children) = runtime.children.borrow_mut().get_mut(&old_parent)
86 {
87 children.remove(&self.0);
88 }
89
90 runtime
92 .children
93 .borrow_mut()
94 .entry(new_parent.0)
95 .or_default()
96 .insert(self.0);
97
98 runtime.parents.borrow_mut().insert(self.0, new_parent.0);
100 });
101 }
102
103 pub fn parent(&self) -> Option<Scope> {
105 RUNTIME.with(|runtime| {
106 runtime
107 .parents
108 .borrow()
109 .get(&self.0)
110 .map(|id| Scope(*id, PhantomData))
111 })
112 }
113
114 #[cfg_attr(debug_assertions, track_caller)]
116 pub fn create_signal<T>(self, value: T) -> (ReadSignal<T>, WriteSignal<T>)
117 where
118 T: Any + 'static,
119 {
120 self.enter(|| RwSignal::new_split(value))
121 }
122
123 #[cfg_attr(debug_assertions, track_caller)]
125 pub fn create_rw_signal<T>(self, value: T) -> RwSignal<T>
126 where
127 T: Any + 'static,
128 {
129 self.enter(|| RwSignal::new(value))
130 }
131
132 #[cfg_attr(debug_assertions, track_caller)]
134 pub fn create_sync_signal<T>(
135 self,
136 value: T,
137 ) -> (ReadSignal<T, SyncStorage>, WriteSignal<T, SyncStorage>)
138 where
139 T: Any + Send + Sync + 'static,
140 {
141 self.enter(|| RwSignal::<T, SyncStorage>::new_sync_split(value))
142 }
143
144 #[cfg_attr(debug_assertions, track_caller)]
146 pub fn create_sync_rw_signal<T>(self, value: T) -> RwSignal<T, SyncStorage>
147 where
148 T: Any + Send + Sync + 'static,
149 {
150 self.enter(|| RwSignal::<T, SyncStorage>::new_sync(value))
151 }
152
153 #[cfg_attr(debug_assertions, track_caller)]
155 pub fn create_local_signal<T>(
156 self,
157 value: T,
158 ) -> (ReadSignal<T, UnsyncStorage>, WriteSignal<T, UnsyncStorage>)
159 where
160 T: Any + 'static,
161 {
162 self.enter(|| RwSignal::new_split(value))
163 }
164
165 #[cfg_attr(debug_assertions, track_caller)]
167 pub fn create_local_rw_signal<T>(self, value: T) -> RwSignal<T, UnsyncStorage>
168 where
169 T: Any + 'static,
170 {
171 self.enter(|| RwSignal::new(value))
172 }
173
174 #[cfg_attr(debug_assertions, track_caller)]
176 pub fn create_memo<T>(self, f: impl Fn(Option<&T>) -> T + 'static) -> Memo<T>
177 where
178 T: PartialEq + 'static,
179 {
180 self.enter(|| create_memo(f))
181 }
182
183 #[cfg_attr(debug_assertions, track_caller)]
185 pub fn create_trigger(self) -> Trigger {
186 self.enter(create_trigger)
187 }
188
189 #[cfg_attr(debug_assertions, track_caller)]
191 pub fn create_effect<T>(self, f: impl Fn(Option<T>) -> T + 'static)
192 where
193 T: Any + 'static,
194 {
195 self.enter(|| create_effect(f))
196 }
197
198 #[cfg_attr(debug_assertions, track_caller)]
200 pub fn create_updater<R>(
201 self,
202 compute: impl Fn() -> R + 'static,
203 on_change: impl Fn(R) + 'static,
204 ) -> R
205 where
206 R: 'static,
207 {
208 self.enter(|| create_updater(compute, on_change))
209 }
210
211 pub fn provide_context<T>(&self, value: T)
230 where
231 T: Clone + 'static,
232 {
233 self.enter(|| crate::context::Context::provide(value))
234 }
235
236 pub fn get_context<T>(&self) -> Option<T>
257 where
258 T: Clone + 'static,
259 {
260 self.enter(crate::context::Context::get::<T>)
261 }
262
263 #[cfg_attr(debug_assertions, track_caller)]
265 pub fn enter<T>(&self, f: impl FnOnce() -> T) -> T
266 where
267 T: 'static,
268 {
269 Runtime::assert_ui_thread();
270 let prev_scope = RUNTIME.with(|runtime| {
271 let mut current_scope = runtime.current_scope.borrow_mut();
272 let prev_scope = *current_scope;
273 *current_scope = self.0;
274 prev_scope
275 });
276
277 let result = f();
278
279 RUNTIME.with(|runtime| {
280 *runtime.current_scope.borrow_mut() = prev_scope;
281 });
282
283 result
284 }
285
286 #[cfg_attr(debug_assertions, track_caller)]
288 pub fn enter_child<T, U>(
289 self,
290 f: impl Fn(T) -> U + 'static,
291 ) -> impl Fn(T) -> (U, Scope) + 'static
292 where
293 T: 'static,
294 {
295 Runtime::assert_ui_thread();
296 let parent = self;
297 move |t| {
298 let scope = parent.create_child();
299 let prev_scope = RUNTIME.with(|runtime| {
300 let mut current_scope = runtime.current_scope.borrow_mut();
301 let prev_scope = *current_scope;
302 *current_scope = scope.0;
303 prev_scope
304 });
305
306 let result = f(t);
307
308 RUNTIME.with(|runtime| {
309 *runtime.current_scope.borrow_mut() = prev_scope;
310 });
311
312 (result, scope)
313 }
314 }
315
316 #[cfg_attr(debug_assertions, track_caller)]
319 pub fn track(&self) {
320 Runtime::assert_ui_thread();
321 let signal = if let Some(signal) = self.0.signal() {
322 signal
323 } else {
324 let signal = SignalState {
325 id: self.0,
326 subscribers: Arc::new(Mutex::new(HashSet::new())),
327 value: SignalValue::Local(Rc::new(RefCell::new(()))),
328 };
329 self.0.add_signal(signal.clone());
330 signal
331 };
332 signal.subscribe();
333 }
334
335 pub fn dispose(&self) {
338 self.0.dispose();
339 }
340}
341
342#[deprecated(
343 since = "0.2.0",
344 note = "Use Scope::enter instead; this will be removed in a future release"
345)]
346pub fn with_scope<T>(scope: Scope, f: impl FnOnce() -> T) -> T
348where
349 T: 'static,
350{
351 scope.enter(f)
352}
353
354#[deprecated(
357 since = "0.2.0",
358 note = "Use Scope::current().enter_child instead; this will be removed in a future release"
359)]
360pub fn as_child_of_current_scope<T, U>(f: impl Fn(T) -> U + 'static) -> impl Fn(T) -> (U, Scope)
361where
362 T: 'static,
363{
364 let parent = Scope::current();
365 move |t| {
366 let scope = parent.create_child();
367 let prev_scope = RUNTIME.with(|runtime| {
368 let mut current_scope = runtime.current_scope.borrow_mut();
369 let prev_scope = *current_scope;
370 *current_scope = scope.0;
371 prev_scope
372 });
373
374 let result = f(t);
375
376 RUNTIME.with(|runtime| {
377 *runtime.current_scope.borrow_mut() = prev_scope;
378 });
379
380 (result, scope)
381 }
382}