syntree/edit.rs
1//! Types associated with performing immutable editing of a tree.
2
3use core::cell::Cell;
4
5use alloc::vec::Vec;
6
7use std::collections::HashMap;
8
9use crate::error::Error;
10use crate::flavor::{Flavor, Storage};
11use crate::index::{Index, TreeIndex};
12use crate::links::Links;
13use crate::node::Node;
14use crate::pointer::Pointer;
15use crate::span::Span;
16use crate::tree::Tree;
17
18#[derive(Debug)]
19pub(crate) enum Change {
20 /// Delete the given node.
21 Delete,
22}
23
24/// A recorded set of tree modifications.
25///
26/// You can use [`ChangeSet::modify`] to construct a new modified tree from an
27/// existing one.
28///
29/// # Examples
30///
31/// ```
32/// use syntree::edit::ChangeSet;
33///
34/// let tree = syntree::tree! {
35/// "root" => {
36/// "child" => {
37/// ("lit", 1),
38/// ("lit", 2),
39/// },
40/// ("whitespace", 3),
41/// }
42/// };
43///
44/// let child = tree.first().and_then(|n| n.first()).ok_or("missing child")?;
45///
46/// let mut change_set = ChangeSet::new();
47/// change_set.remove(child.id());
48///
49/// assert_eq!(
50/// change_set.modify(&tree)?,
51/// syntree::tree! {
52/// "root" => {
53/// ("whitespace", 3)
54/// }
55/// }
56/// );
57///
58/// let lit = child.first().ok_or("missing lit")?;
59///
60/// let mut change_set = ChangeSet::new();
61/// change_set.remove(lit.id());
62///
63/// assert_eq!(
64/// change_set.modify(&tree)?,
65/// syntree::tree! {
66/// "root" => {
67/// "child" => {
68/// ("lit", 2),
69/// },
70/// ("whitespace", 3)
71/// }
72/// }
73/// );
74/// # Ok::<_, Box<dyn core::error::Error>>(())
75/// ```
76pub struct ChangeSet<T, F>
77where
78 T: Copy,
79 F: Flavor,
80{
81 changes: HashMap<F::Pointer, Change>,
82 #[allow(unused)]
83 trees: Vec<Tree<T, F>>,
84}
85
86impl<T, F> ChangeSet<T, F>
87where
88 T: Copy,
89 F: Flavor,
90{
91 /// Construct a new empty [`ChangeSet`].
92 #[must_use]
93 pub fn new() -> Self {
94 Self::default()
95 }
96}
97
98impl<T, F> ChangeSet<T, F>
99where
100 T: Copy,
101 F: Flavor,
102{
103 /// Register a node removal in the changeset. Only one kind of modification
104 /// for a given node will be preserved.
105 ///
106 /// # Examples
107 ///
108 /// ```
109 /// use syntree::edit::ChangeSet;
110 ///
111 /// let tree = syntree::tree! {
112 /// "root" => {
113 /// "child" => {
114 /// ("lit", 1),
115 /// ("lit", 2),
116 /// },
117 /// ("whitespace", 3),
118 /// }
119 /// };
120 ///
121 /// let child = tree.first().and_then(|n| n.first()).ok_or("missing child")?;
122 ///
123 /// let mut change_set = ChangeSet::new();
124 /// change_set.remove(child.id());
125 ///
126 /// assert_eq!(
127 /// change_set.modify(&tree)?,
128 /// syntree::tree! {
129 /// "root" => {
130 /// ("whitespace", 3)
131 /// }
132 /// }
133 /// );
134 /// # Ok::<_, Box<dyn core::error::Error>>(())
135 /// ```
136 pub fn remove(&mut self, id: F::Pointer) {
137 self.changes.insert(id, Change::Delete);
138 }
139
140 /// Construct a modified tree where the recorded modifications have been
141 /// applied.
142 ///
143 /// # Errors
144 ///
145 /// Errors with [`Error::Overflow`] in case we run out of node
146 /// identifiers.
147 ///
148 /// # Examples
149 ///
150 /// ```
151 /// use syntree::edit::ChangeSet;
152 ///
153 /// let tree = syntree::tree! {
154 /// "root" => {
155 /// "child" => {
156 /// ("lit", 1),
157 /// ("lit", 2),
158 /// },
159 /// ("whitespace", 3),
160 /// }
161 /// };
162 ///
163 /// let child = tree.first().and_then(|n| n.first()).ok_or("missing child")?;
164 /// let mut change_set = ChangeSet::new();
165 /// change_set.remove(child.id());
166 ///
167 /// assert_eq!(
168 /// change_set.modify(&tree)?,
169 /// syntree::tree! {
170 /// "root" => {
171 /// ("whitespace", 3)
172 /// }
173 /// }
174 /// );
175 /// # Ok::<_, Box<dyn core::error::Error>>(())
176 /// ```
177 pub fn modify(&mut self, tree: &Tree<T, F>) -> Result<Tree<T, F>, Error<F::Error>> {
178 let mut output = Tree::<T, F>::with_capacity(tree.capacity())?;
179
180 let mut refactor = RefactorWalk {
181 parents: Vec::new(),
182 prev: None,
183 };
184
185 let mut cursor = F::Index::EMPTY;
186
187 // The specified sub-tree depth is being deleted.
188 let mut current = tree.first().map(|node| (node, false));
189
190 while let Some((mut node, mut first)) = current.take() {
191 let node_id = F::Pointer::new(output.len()).ok_or(Error::Overflow)?;
192
193 if let Some(change) = self.changes.get(&node_id) {
194 match change {
195 Change::Delete => {
196 let Some(skipped) = refactor.skip_subtree(node, first) else {
197 continue;
198 };
199
200 node = skipped.node;
201 first = skipped.first;
202 }
203 }
204 }
205
206 if refactor.parents.is_empty() {
207 let (first, last) = output.links_mut();
208
209 if first.is_none() {
210 *first = Some(node_id);
211 }
212
213 *last = Some(node_id);
214 }
215
216 // Since we are the first node in the sequence we're obligated to
217 // set the first child of the parent.
218 let prev = if first {
219 None
220 } else {
221 let prev = refactor.prev.take();
222
223 if let Some(prev) = prev.and_then(|id| output.get_mut(id)) {
224 prev.next = Some(node_id);
225 }
226
227 prev
228 };
229
230 let span = if !node.has_children() && !node.span().is_empty() {
231 output.indexes_mut().push(TreeIndex {
232 index: cursor,
233 id: node_id,
234 })?;
235 let start = cursor;
236 cursor = cursor
237 .checked_add_len(node.span().len())
238 .ok_or(Error::Overflow)?;
239 Span::new(start, cursor)
240 } else {
241 Span::point(cursor)
242 };
243
244 let parent = refactor.parents.last().map(|n| n.1);
245
246 if let Some(parent) = parent.and_then(|id| output.get_mut(id)) {
247 if parent.first.is_none() {
248 parent.first = Some(node_id);
249 }
250
251 parent.last = Some(node_id);
252 parent.span.end = span.end;
253 }
254
255 output.push(Links {
256 data: Cell::new(node.value()),
257 span,
258 parent,
259 prev,
260 next: None,
261 first: None,
262 last: None,
263 })?;
264
265 current = refactor.step(node, node_id);
266 }
267
268 output.span_mut().end = cursor;
269 Ok(output)
270 }
271}
272
273impl<T, F> Default for ChangeSet<T, F>
274where
275 T: Copy,
276 F: Flavor,
277{
278 #[inline]
279 fn default() -> Self {
280 Self {
281 changes: HashMap::new(),
282 trees: Vec::new(),
283 }
284 }
285}
286
287/// The state of the skipped subtree.
288struct Skipped<'a, T, F>
289where
290 T: Copy,
291 F: Flavor,
292{
293 node: Node<'a, T, F>,
294 first: bool,
295}
296
297struct RefactorWalk<'a, T, F>
298where
299 T: Copy,
300 F: Flavor,
301{
302 parents: Vec<(Node<'a, T, F>, F::Pointer)>,
303 prev: Option<F::Pointer>,
304}
305
306impl<'a, T, F> RefactorWalk<'a, T, F>
307where
308 T: Copy,
309 F: Flavor,
310{
311 fn skip_subtree(&mut self, node: Node<'a, T, F>, first: bool) -> Option<Skipped<'a, T, F>> {
312 if let Some(next) = node.next() {
313 return Some(Skipped { node: next, first });
314 }
315
316 let (node, parent_id) = self.parents.pop()?;
317 self.prev = Some(parent_id);
318 Some(Skipped { node, first: false })
319 }
320
321 /// Advance the iteration.
322 fn step(
323 &mut self,
324 node: Node<'a, T, F>,
325 node_id: F::Pointer,
326 ) -> Option<(Node<'a, T, F>, bool)> {
327 if let Some(next) = node.first() {
328 self.parents.push((node, node_id));
329 return Some((next, true));
330 }
331
332 if let Some(next) = node.next() {
333 self.prev = Some(node_id);
334 return Some((next, false));
335 }
336
337 while let Some((parent, prev_id)) = self.parents.pop() {
338 if let Some(next) = parent.next() {
339 self.prev = Some(prev_id);
340 return Some((next, false));
341 }
342 }
343
344 None
345 }
346}