blockworx/document_ng/
document.rs1use std::ops::{Deref, DerefMut};
11use std::sync::atomic::{AtomicU64, Ordering};
12
13use super::{Block, BlockPath};
14use crate::store::{IdMap, IdMapExt, RectId};
15
16#[derive(Clone, Copy, PartialEq, Eq, Debug)]
21pub struct Generation(u64);
22
23impl Generation {
24 fn next() -> Self {
25 static NEXT: AtomicU64 = AtomicU64::new(0);
26 Self(NEXT.fetch_add(1, Ordering::Relaxed))
27 }
28}
29
30#[derive(Clone, Debug)]
34pub struct Blocks {
35 map: IdMap<RectId, Block>,
36 generation: Generation,
37}
38
39impl Blocks {
40 pub fn generation(&self) -> Generation {
41 self.generation
42 }
43}
44
45impl PartialEq for Blocks {
49 fn eq(&self, other: &Self) -> bool {
50 self.map == other.map
51 }
52}
53
54impl Default for Blocks {
55 fn default() -> Self {
56 IdMap::default().into()
57 }
58}
59
60impl From<IdMap<RectId, Block>> for Blocks {
61 fn from(map: IdMap<RectId, Block>) -> Self {
62 Self {
63 map,
64 generation: Generation::next(),
65 }
66 }
67}
68
69impl Deref for Blocks {
70 type Target = IdMap<RectId, Block>;
71 fn deref(&self) -> &Self::Target {
72 &self.map
73 }
74}
75
76impl DerefMut for Blocks {
77 fn deref_mut(&mut self) -> &mut Self::Target {
78 self.generation = Generation::next();
79 &mut self.map
80 }
81}
82
83#[derive(Clone, Debug, PartialEq)]
85pub struct Document {
86 pub top_id: RectId,
88 pub blocks: Blocks,
92}
93
94impl Default for Document {
95 fn default() -> Self {
96 let mut blocks = Blocks::default();
98 let top_id = blocks.insert_value(Block::default());
99 Self { top_id, blocks }
100 }
101}
102
103impl Document {
104 pub fn generation(&self) -> Generation {
106 self.blocks.generation()
107 }
108
109 pub fn add_child(&mut self, parent: RectId, block: Block) -> RectId {
114 let id = self.blocks.insert_value(block);
115 if let Some(p) = self.blocks.get_mut(&parent) {
116 p.children.insert(id);
117 }
118 id
119 }
120
121 pub fn block(&self, id: RectId) -> Option<&Block> {
122 self.blocks.get(&id)
123 }
124 pub fn block_mut(&mut self, id: RectId) -> Option<&mut Block> {
125 self.blocks.get_mut(&id)
126 }
127
128 pub fn current_id(&self, path: &BlockPath) -> RectId {
133 path.segments()
134 .last()
135 .copied()
136 .filter(|id| self.blocks.contains_key(id))
137 .unwrap_or(self.top_id)
138 }
139
140 pub fn child_blocks(&self, id: RectId) -> impl Iterator<Item = (RectId, &Block)> + '_ {
144 self.blocks.get(&id).into_iter().flat_map(move |b| {
145 b.children
146 .iter()
147 .filter_map(move |&cid| self.blocks.get(&cid).map(|cb| (cid, cb)))
148 })
149 }
150
151 pub fn path_to_parent(&self, target: RectId) -> Option<BlockPath> {
158 fn descend(doc: &Document, node: RectId, target: RectId, trail: &mut Vec<RectId>) -> bool {
159 let Some(block) = doc.blocks.get(&node) else {
160 return false;
161 };
162 for &cid in &block.children {
163 if cid == target {
164 return true;
165 }
166 trail.push(cid);
167 if descend(doc, cid, target, trail) {
168 return true;
169 }
170 trail.pop();
171 }
172 false
173 }
174 let mut trail = Vec::new();
175 descend(self, self.top_id, target, &mut trail).then(|| {
176 let mut path = BlockPath::empty();
177 for id in trail {
178 path.push(id);
179 }
180 path
181 })
182 }
183
184 #[cfg(test)]
185 fn add_named(&mut self, parent: RectId) -> RectId {
186 use crate::document_ng::Block;
187 self.add_child(
188 parent,
189 Block::new(
190 String::new(),
191 egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)),
192 ),
193 )
194 }
195
196 pub fn descendants(&self, id: RectId) -> Vec<RectId> {
199 let mut out = Vec::new();
200 let mut stack: Vec<RectId> = self
201 .blocks
202 .get(&id)
203 .map(|b| b.children.iter().copied().collect())
204 .unwrap_or_default();
205 while let Some(cid) = stack.pop() {
206 out.push(cid);
207 if let Some(b) = self.blocks.get(&cid) {
208 stack.extend(b.children.iter().copied());
209 }
210 }
211 out
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218
219 #[test]
220 fn path_to_parent_walks_from_the_top_child_down_to_the_parent() {
221 let mut doc = Document::default();
222 let top = doc.top_id;
223 let a = doc.add_named(top); let b = doc.add_named(a); let c = doc.add_named(b); let sib = doc.add_named(top); assert_eq!(doc.path_to_parent(a), Some(BlockPath::empty()));
230 assert_eq!(doc.path_to_parent(sib), Some(BlockPath::empty()));
231
232 let mut want_b = BlockPath::empty();
234 want_b.push(a);
235 assert_eq!(doc.path_to_parent(b), Some(want_b));
236
237 let mut want_c = BlockPath::empty();
238 want_c.push(a);
239 want_c.push(b);
240 assert_eq!(doc.path_to_parent(c), Some(want_c));
241
242 assert_eq!(doc.path_to_parent(top), None);
244 assert_eq!(doc.path_to_parent(RectId::nth_default(999)), None);
245 }
246}