1use std::fmt::{self, Debug, Formatter};
2use std::hash::Hash;
3use std::marker::PhantomData;
4use std::ops::DerefMut;
5
6use generational_box::GenerationalBox;
7use slab::Slab;
8
9use crate::composer::NodeKey;
10use crate::{AnyData, ComposeNode, Composer, Loc, Node, State, StateId};
11
12pub struct Scope<S, N>
13where
14 N: ComposeNode,
15{
16 pub id: ScopeId,
17 pub(crate) composer: GenerationalBox<Composer<N>>,
18 ty: PhantomData<S>,
19}
20
21impl<S, N> Clone for Scope<S, N>
22where
23 N: ComposeNode,
24{
25 fn clone(&self) -> Self {
26 *self
27 }
28}
29
30impl<S, N> Copy for Scope<S, N> where N: ComposeNode {}
31
32impl<S, N> Scope<S, N>
33where
34 S: 'static,
35 N: ComposeNode,
36{
37 #[inline(always)]
38 pub(crate) fn new(id: ScopeId, composer: GenerationalBox<Composer<N>>) -> Self {
39 Self {
40 id,
41 composer,
42 ty: PhantomData,
43 }
44 }
45
46 #[inline(always)]
47 pub(crate) fn set_key(&mut self, key: usize) {
48 self.id.set_key(key);
49 }
50
51 #[track_caller]
52 #[inline(always)]
53 pub fn child<C>(&self) -> Scope<C, N>
54 where
55 C: 'static,
56 {
57 let id = ScopeId::new();
58 Scope::new(id, self.composer)
59 }
60
61 #[track_caller]
62 pub fn use_state<F, T>(&self, init: F) -> State<T, N>
63 where
64 T: 'static,
65 F: Fn() -> T + 'static,
66 {
67 let mut c = self.composer.write();
68 let c = c.deref_mut();
69 let current_node_key = c.current_node_key;
70 let id = StateId::new(current_node_key);
71 let scope_states = c.states.entry(current_node_key).or_default();
72 let _ = scope_states.entry(id).or_insert_with(|| Box::new(init()));
73 State::new(id, self.composer)
74 }
75
76 #[track_caller]
77 #[inline(always)]
78 pub fn key<C>(&self, key: usize, content: C)
79 where
80 C: Fn(Self) + 'static,
81 {
82 self.composer.write().key_stack.push(key);
83 content(*self);
84 self.composer.write().key_stack.pop();
85 }
86
87 pub fn create_node<C, T, I, A, F, U>(
88 &self,
89 child_scope: Scope<T, N>,
90 content: C,
91 input: I,
92 factory: F,
93 update: U,
94 ) where
95 T: 'static,
96 C: Fn(Scope<T, N>) + Clone + 'static,
97 I: Fn() -> A + Clone + 'static,
98 A: 'static,
99 F: Fn(A, &mut N::Context) -> N + Clone + 'static,
100 U: Fn(&mut N, A, &mut N::Context) + Clone + 'static,
101 {
102 let parent_scope = *self;
103 let composable = move || {
104 let mut current_scope = child_scope;
105 let (parent_node_key, current_node_key, is_dirty) = {
106 let mut c = parent_scope.composer.write();
107 if let Some(key) = c.key_stack.last().copied() {
108 current_scope.set_key(key);
109 }
110 let parent_node_key = c.current_node_key;
111 c.start_node(parent_node_key, current_scope.id);
112 let current_node_key = c.current_node_key;
113 let is_visited = c.composables.contains_key(¤t_node_key);
114 let is_dirty = c.dirty_nodes.contains(¤t_node_key);
115 if !is_dirty && is_visited {
116 c.skip_node(parent_node_key);
117 return current_node_key;
118 }
119 drop(c);
120 let args = input();
121 let mut c = parent_scope.composer.write();
122 let c = c.deref_mut();
123 update_node(
124 current_node_key,
125 &mut c.context,
126 &mut c.nodes,
127 args,
128 &factory,
129 &update,
130 );
131 (parent_node_key, current_node_key, is_dirty)
132 };
133 content(current_scope);
134 let mut c = parent_scope.composer.write();
135 let c = c.deref_mut();
136 if is_dirty {
137 c.dirty_nodes.remove(¤t_node_key);
138 }
139 c.end_node(parent_node_key);
140 current_node_key
141 };
142 let current_node_key = composable();
143 let mut c = parent_scope.composer.write();
144 c.composables
145 .entry(current_node_key)
146 .or_insert_with(|| Box::new(composable));
147 }
148
149 #[inline(always)]
150 pub fn create_any_node<C, T, I, A, E, F, U>(
151 &self,
152 child_scope: Scope<T, N>,
153 content: C,
154 input: I,
155 factory: F,
156 update: U,
157 ) where
158 T: 'static,
159 C: Fn(Scope<T, N>) + Clone + 'static,
160 I: Fn() -> A + Clone + 'static,
161 A: 'static,
162 N: AnyData<E>,
163 E: 'static,
164 F: Fn(A, &mut N::Context) -> E + Clone + 'static,
165 U: Fn(&mut E, A, &mut N::Context) + Clone + 'static,
166 {
167 self.create_node(
168 child_scope,
169 content,
170 input,
171 move |args, ctx| {
172 let e = factory(args, ctx);
173 AnyData::new(e)
174 },
175 move |n, args, ctx| {
176 let e = n.value_mut();
177 update(e, args, ctx);
178 },
179 );
180 }
181}
182
183#[inline(always)]
186fn update_node<N, A, F, U>(
187 node_key: NodeKey,
188 context: &mut N::Context,
189 nodes: &mut Slab<Node<N>>,
190 args: A,
191 factory: &F,
192 update: &U,
193) where
194 N: ComposeNode,
195 A: 'static,
196 F: Fn(A, &mut N::Context) -> N + Clone + 'static,
197 U: Fn(&mut N, A, &mut N::Context) + Clone + 'static,
198{
199 let node = nodes.get_mut(node_key).unwrap();
200 if let Some(data) = node.data.as_mut() {
201 update(data, args, context);
202 } else {
203 let data = factory(args, context);
204 node.data = Some(data);
205 }
206}
207
208#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
209pub struct ScopeId {
210 pub loc: Loc,
211 pub key: usize,
212}
213
214impl ScopeId {
215 #[track_caller]
216 #[inline(always)]
217 pub fn new() -> Self {
218 let loc = Loc::new();
219 Self { loc, key: 0 }
220 }
221
222 #[inline(always)]
223 pub fn set_key(&mut self, key: usize) {
224 self.key = key;
225 }
226
227 #[inline(always)]
228 pub fn get_key(&self) -> usize {
229 self.key
230 }
231}
232
233impl Debug for ScopeId {
234 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
235 write!(f, "{:?}|{}", self.loc, self.key)
236 }
237}
238
239#[derive(Debug, Clone, Copy)]
240pub struct Root;