1use std::fmt::{Debug, Formatter};
2use std::ops::{Deref, DerefMut};
3
4use generational_box::{GenerationalBox, Owner};
5
6use crate::{utils, ComposeNode, Composer, NodeKey, State};
7
8pub struct Recomposer<S, N>
9where
10 N: ComposeNode,
11{
12 #[allow(dead_code)]
13 pub(crate) owner: Owner,
14 pub(crate) composer: GenerationalBox<Composer<N>>,
15 pub(crate) root_state: State<S, N>,
16}
17
18impl<S, N> Recomposer<S, N>
19where
20 S: 'static,
21 N: ComposeNode,
22{
23 pub fn recompose(&mut self) {
24 let mut c = self.composer.write();
25 c.dirty_nodes.clear();
26 for state_id in c.dirty_states.drain().collect::<Vec<_>>() {
27 if let Some(nodes) = c.used_by.get(&state_id).cloned() {
28 c.dirty_nodes.extend(nodes);
29 }
30 }
31 let mut composables = Vec::with_capacity(c.dirty_nodes.len());
32 for node_key in &c.dirty_nodes {
33 if let Some(composable) = c.composables.get(node_key).cloned() {
34 composables.push((*node_key, composable));
35 }
36 }
37 drop(c);
38 for (node_key, composable) in composables {
39 {
40 let mut c = self.composer.write();
41 c.current_node_key = node_key;
42 }
43 composable.compose();
44 }
45 let mut c = self.composer.write();
46 let c = c.deref_mut();
47 let unmount_nodes = c
48 .unmount_nodes
49 .difference(&c.mount_nodes)
50 .cloned()
51 .collect::<Vec<_>>();
52 for n in unmount_nodes {
53 c.composables.remove(&n);
54 c.nodes.remove(n);
55 if let Some(node_states) = c.states.remove(&n) {
56 for state in node_states.keys() {
57 c.used_by.remove(state);
58 }
59 }
60 let use_states = c.uses.remove(&n);
61 if let Some(use_states) = use_states {
62 for state in use_states {
63 if let Some(used_by) = c.used_by.get_mut(&state) {
64 used_by.remove(&n);
65 }
66 }
67 }
68 }
69 c.mount_nodes.clear();
70 c.unmount_nodes.clear();
71 }
72
73 #[inline(always)]
74 pub fn recompose_with(&mut self, new_state: S) {
75 self.root_state.set(new_state);
76 self.recompose();
77 }
78
79 #[inline(always)]
80 pub fn root_node_key(&self) -> NodeKey {
81 self.composer.read().root_node_key
82 }
83
84 #[inline(always)]
85 pub fn with_context<F, T>(&self, func: F) -> T
86 where
87 F: FnOnce(&N::Context) -> T,
88 {
89 let c = self.composer.read();
90 func(&c.context)
91 }
92
93 #[inline(always)]
94 pub fn with_context_mut<F, T>(&mut self, func: F) -> T
95 where
96 F: FnOnce(&mut N::Context) -> T,
97 {
98 let mut c = self.composer.write();
99 func(&mut c.context)
100 }
101
102 #[inline(always)]
103 pub fn with_composer<F, T>(&self, func: F) -> T
104 where
105 F: FnOnce(&Composer<N>) -> T,
106 {
107 let c = self.composer.read();
108 func(c.deref())
109 }
110
111 #[inline(always)]
112 pub fn with_composer_mut<F, T>(&mut self, func: F) -> T
113 where
114 F: FnOnce(&mut Composer<N>) -> T,
115 {
116 let mut c = self.composer.write();
117 func(c.deref_mut())
118 }
119
120 #[inline(always)]
121 pub fn get_root_state(&self) -> S
122 where
123 S: Clone,
124 {
125 self.root_state.get_untracked()
126 }
127
128 #[inline(always)]
129 pub fn set_root_state(&mut self, val: S) {
130 self.root_state.set(val);
131 }
132
133 #[inline(always)]
134 pub fn with_root_state<F, T>(&self, func: F) -> T
135 where
136 F: Fn(&S) -> T,
137 {
138 self.root_state.with_untracked(func)
139 }
140
141 #[inline(always)]
142 pub fn with_root_state_mut<F, T>(&mut self, func: F) -> T
143 where
144 F: Fn(&mut S) -> T,
145 {
146 self.root_state.with_mut_untracked(func)
147 }
148
149 #[inline(always)]
150 pub fn print_tree(&self)
151 where
152 N: Debug,
153 {
154 self.print_tree_with(self.root_node_key(), |n| format!("{:?}", n));
155 }
156
157 #[inline(always)]
158 pub fn print_tree_with<D>(&self, node_key: NodeKey, display_fn: D)
159 where
160 D: Fn(Option<&N>) -> String,
161 {
162 let c = self.composer.read();
163 utils::print_tree(&c, node_key, display_fn);
164 }
165}
166
167impl<S, N> Debug for Recomposer<S, N>
168where
169 N: ComposeNode + Debug,
170{
171 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
172 let c = self.composer.read();
173 f.debug_struct("Recomposer")
174 .field("nodes", &c.nodes)
175 .field("states", &c.states)
176 .field("dirty_states", &c.dirty_states)
177 .field("used_by", &c.used_by)
178 .field("composables", &c.composables.keys())
179 .finish()
180 }
181}