compose_rt/
composer.rs

1use std::any::Any;
2use std::fmt::{Debug, Formatter};
3
4use generational_box::{AnyStorage, UnsyncStorage};
5use slab::Slab;
6
7use crate::map::{HashMapExt, HashSetExt, Map, Set};
8use crate::{Recomposer, Root, Scope, ScopeId, State, StateId};
9
10pub trait Composable {
11    fn compose(&self) -> NodeKey;
12    fn clone_box(&self) -> Box<dyn Composable>;
13}
14
15impl<T> Composable for T
16where
17    T: Fn() -> NodeKey + Clone + 'static,
18{
19    fn compose(&self) -> NodeKey {
20        self()
21    }
22
23    fn clone_box(&self) -> Box<dyn Composable> {
24        Box::new(self.clone())
25    }
26}
27
28impl Clone for Box<dyn Composable> {
29    fn clone(&self) -> Self {
30        self.clone_box()
31    }
32}
33
34pub trait ComposeNode: 'static {
35    type Context;
36}
37
38impl ComposeNode for () {
39    type Context = ();
40}
41
42pub trait AnyData<T> {
43    fn new(val: T) -> Self;
44    fn value(&self) -> &T;
45    fn value_mut(&mut self) -> &mut T;
46}
47
48impl<T> AnyData<T> for Box<dyn Any>
49where
50    T: 'static,
51{
52    #[inline(always)]
53    fn new(val: T) -> Self {
54        Box::new(val)
55    }
56
57    #[inline(always)]
58    fn value(&self) -> &T {
59        self.downcast_ref::<T>().unwrap()
60    }
61
62    #[inline(always)]
63    fn value_mut(&mut self) -> &mut T {
64        self.downcast_mut::<T>().unwrap()
65    }
66}
67
68pub type NodeKey = usize;
69
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct Node<T> {
72    pub scope_id: ScopeId,
73    pub parent: NodeKey,
74    pub children: Vec<NodeKey>,
75    pub data: Option<T>,
76}
77
78impl<T> Node<T> {
79    #[inline(always)]
80    pub fn new(scope_id: ScopeId, parent: NodeKey) -> Self {
81        Self {
82            scope_id,
83            parent,
84            children: Vec::new(),
85            data: None,
86        }
87    }
88}
89
90pub struct Composer<N>
91where
92    N: ComposeNode,
93{
94    pub context: N::Context,
95    pub nodes: Slab<Node<N>>,
96    pub(crate) initialized: bool,
97    pub(crate) root_node_key: NodeKey,
98    pub(crate) composables: Map<NodeKey, Box<dyn Composable>>,
99    pub(crate) states: Map<NodeKey, Map<StateId, Box<dyn Any>>>,
100    pub(crate) used_by: Map<StateId, Set<NodeKey>>,
101    pub(crate) uses: Map<NodeKey, Set<StateId>>,
102    pub(crate) current_node_key: NodeKey,
103    pub(crate) key_stack: Vec<usize>,
104    pub(crate) child_idx_stack: Vec<usize>,
105    pub(crate) dirty_states: Set<StateId>,
106    pub(crate) dirty_nodes: Set<NodeKey>,
107    pub(crate) mount_nodes: Set<NodeKey>,
108    pub(crate) unmount_nodes: Set<NodeKey>,
109}
110
111impl<N> Composer<N>
112where
113    N: ComposeNode,
114{
115    pub fn new(context: N::Context) -> Self {
116        Self {
117            context,
118            nodes: Slab::new(),
119            initialized: false,
120            root_node_key: 0,
121            composables: Map::new(),
122            states: Map::new(),
123            used_by: Map::new(),
124            uses: Map::new(),
125            current_node_key: 0,
126            key_stack: Vec::new(),
127            child_idx_stack: Vec::new(),
128            dirty_states: Set::new(),
129            dirty_nodes: Set::new(),
130            mount_nodes: Set::new(),
131            unmount_nodes: Set::new(),
132        }
133    }
134
135    pub fn with_capacity(context: N::Context, capacity: usize) -> Self {
136        Self {
137            context,
138            nodes: Slab::with_capacity(capacity),
139            initialized: false,
140            root_node_key: 0,
141            composables: Map::with_capacity(capacity),
142            states: Map::with_capacity(capacity),
143            used_by: Map::with_capacity(capacity),
144            uses: Map::with_capacity(capacity),
145            current_node_key: 0,
146            child_idx_stack: Vec::new(),
147            key_stack: Vec::new(),
148            dirty_states: Set::new(),
149            dirty_nodes: Set::new(),
150            mount_nodes: Set::with_capacity(capacity),
151            unmount_nodes: Set::new(),
152        }
153    }
154
155    // TODO: fine control over the capacity of the HashMaps
156    #[track_caller]
157    pub fn compose<R>(root: R, context: N::Context) -> Recomposer<(), N>
158    where
159        R: Fn(Scope<Root, N>),
160    {
161        let owner = UnsyncStorage::owner();
162        let composer = owner.insert(Composer::with_capacity(context, 1024));
163        let id = ScopeId::new();
164        let scope = Scope::new(id, composer);
165        composer.write().start_root(scope.id);
166        let root_state = scope.use_state(|| {});
167        root(scope);
168        composer.write().end_root();
169        let mut c = composer.write();
170        c.initialized = true;
171        Recomposer {
172            owner,
173            composer,
174            root_state,
175        }
176    }
177
178    #[track_caller]
179    pub fn compose_with<R, F, T>(root: R, context: N::Context, state_fn: F) -> Recomposer<T, N>
180    where
181        R: Fn(Scope<Root, N>, State<T, N>),
182        F: Fn() -> T + 'static,
183        T: 'static,
184    {
185        let owner = UnsyncStorage::owner();
186        let composer = owner.insert(Composer::with_capacity(context, 1024));
187        let id = ScopeId::new();
188        let scope = Scope::new(id, composer);
189        composer.write().start_root(scope.id);
190        let root_state = scope.use_state(state_fn);
191        root(scope, root_state);
192        composer.write().end_root();
193        let mut c = composer.write();
194        c.initialized = true;
195        Recomposer {
196            owner,
197            composer,
198            root_state,
199        }
200    }
201
202    #[inline(always)]
203    pub(crate) fn start_root(&mut self, scope_id: ScopeId) {
204        let parent_node_key = 0;
205        let node_key = self.nodes.insert(Node::new(scope_id, parent_node_key));
206        self.child_idx_stack.push(0);
207        self.current_node_key = node_key;
208    }
209
210    #[inline(always)]
211    pub(crate) fn end_root(&mut self) {
212        let child_count = self.child_idx_stack.pop().unwrap();
213        assert_eq!(1, child_count, "Root scope must have exactly one child");
214        self.root_node_key = self.nodes[self.current_node_key].children[0];
215    }
216
217    #[inline(always)]
218    pub(crate) fn start_node(&mut self, parent_node_key: NodeKey, scope_id: ScopeId) {
219        if self.initialized {
220            let child_idx = self.child_idx_stack.last().cloned();
221            if let Some(child_idx) = child_idx {
222                let parent_node = &mut self.nodes[parent_node_key];
223                if child_idx < parent_node.children.len() {
224                    let child_key = parent_node.children[child_idx];
225                    let child_node = &mut self.nodes[child_key];
226                    if child_node.scope_id == scope_id {
227                        // reuse existing node
228                        self.current_node_key = child_key;
229                        self.mount_nodes.insert(child_key);
230                        self.child_idx_stack.push(0);
231                    } else {
232                        // replace existing node
233                        let node_key = self.nodes.insert(Node::new(scope_id, parent_node_key));
234                        self.nodes[parent_node_key].children[child_idx] = node_key;
235                        self.unmount_nodes.insert(child_key);
236                        self.mount_nodes.insert(node_key);
237                        self.current_node_key = node_key;
238                        self.child_idx_stack.push(0);
239                    }
240                } else {
241                    // append new node
242                    let node_key = self.nodes.insert(Node::new(scope_id, parent_node_key));
243                    self.nodes[parent_node_key].children.push(node_key);
244                    self.mount_nodes.insert(node_key);
245                    self.current_node_key = node_key;
246                    self.child_idx_stack.push(0);
247                }
248            } else {
249                // recompose root
250                self.child_idx_stack.push(0);
251            }
252        } else {
253            // first compose
254            let node_key = self.nodes.insert(Node::new(scope_id, parent_node_key));
255            self.nodes[parent_node_key].children.push(node_key);
256            self.current_node_key = node_key;
257            self.child_idx_stack.push(0);
258        }
259    }
260
261    #[inline(always)]
262    pub(crate) fn end_node(&mut self, parent_node_key: NodeKey) {
263        let child_count = self.child_idx_stack.pop().unwrap();
264        let node = &mut self.nodes[self.current_node_key];
265        let old_child_count = node.children.len();
266        if child_count < old_child_count {
267            let unmount_nodes = node.children.drain(child_count..);
268            self.unmount_nodes.extend(unmount_nodes);
269        }
270        if let Some(parent_child_count) = self.child_idx_stack.last_mut() {
271            *parent_child_count += 1;
272        }
273        self.current_node_key = parent_node_key;
274    }
275
276    #[inline(always)]
277    pub(crate) fn skip_node(&mut self, parent_node_key: NodeKey) {
278        let _ = self.child_idx_stack.pop().unwrap();
279        if let Some(parent_child_count) = self.child_idx_stack.last_mut() {
280            *parent_child_count += 1;
281        }
282        self.current_node_key = parent_node_key;
283    }
284}
285
286impl<N> Debug for Composer<N>
287where
288    N: ComposeNode + Debug,
289{
290    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
291        f.debug_struct("Composer")
292            .field("nodes", &self.nodes)
293            .field("states", &self.states)
294            .field("dirty_states", &self.dirty_states)
295            .field("used_by", &self.used_by)
296            .finish()
297    }
298}