1use std::collections::HashMap;
25
26use crate::parse::{Attr, Child, Element, File, Value};
27
28mod remembering;
29
30pub use remembering::{Parses, Remembering};
31
32pub const MAX_EDITS: usize = 256;
34
35const MAX_DEPTH: usize = 64;
37
38pub fn matched(mut new: File, last: &File) -> File {
41 let mut next = last.next_id;
42 if new.root.name == last.root.name {
43 pair(&mut new.root, &last.root, &mut next);
44 } else {
45 fresh(&mut new.root, &mut next);
46 }
47 new.next_id = next;
48 new
49}
50
51pub fn key(el: &Element) -> Option<&str> {
53 el.attrs.iter().find_map(|a| match (&*a.name, &a.value) {
54 ("key", Value::Str(s, _)) => Some(s.as_str()),
55 _ => None,
56 })
57}
58
59fn fresh(el: &mut Element, next: &mut u32) {
60 el.id = *next;
61 *next += 1;
62 for child in &mut el.children {
63 if let Child::Element(e) = child {
64 fresh(e, next);
65 }
66 }
67}
68
69fn pair(new: &mut Element, old: &Element, next: &mut u32) {
70 new.id = old.id;
71 let olds: Vec<&Element> = elements(&old.children).collect();
72 let mut news: Vec<&mut Element> = new
73 .children
74 .iter_mut()
75 .filter_map(|c| match c {
76 Child::Element(e) => Some(e),
77 Child::Text(..) => None,
78 })
79 .collect();
80 let matches = siblings(&news.iter().map(|e| &**e).collect::<Vec<_>>(), &olds);
81 for (n, el) in news.iter_mut().enumerate() {
82 match matches[n] {
83 Some(o) => pair(el, olds[o], next),
84 None => fresh(el, next),
85 }
86 }
87}
88
89fn elements(children: &[Child]) -> impl Iterator<Item = &Element> {
90 children.iter().filter_map(|c| match c {
91 Child::Element(e) => Some(e),
92 Child::Text(..) => None,
93 })
94}
95
96fn siblings(news: &[&Element], olds: &[&Element]) -> Vec<Option<usize>> {
98 let mut out = vec![None; news.len()];
99 let mut taken = vec![false; olds.len()];
100 let mut keyed: HashMap<(&str, &str), usize> = HashMap::new();
102 for (o, el) in olds.iter().enumerate() {
103 if let Some(k) = key(el) {
104 keyed.entry((&el.name, k)).or_insert(o);
105 }
106 }
107 for (n, el) in news.iter().enumerate() {
108 if let Some(k) = key(el)
109 && let Some(&o) = keyed.get(&(el.name.as_str(), k))
110 && !taken[o]
111 {
112 out[n] = Some(o);
113 taken[o] = true;
114 }
115 }
116 let free_new: Vec<usize> = (0..news.len())
118 .filter(|&n| out[n].is_none() && key(news[n]).is_none())
119 .collect();
120 let free_old: Vec<usize> = (0..olds.len())
121 .filter(|&o| !taken[o] && key(olds[o]).is_none())
122 .collect();
123 let shapes_new: Vec<u64> = free_new.iter().map(|&n| shape(news[n])).collect();
127 let shapes_old: Vec<u64> = free_old.iter().map(|&o| shape(olds[o])).collect();
128 let same = |n: usize, o: usize| {
129 shapes_new[n] == shapes_old[o] && same_own(news[free_new[n]], olds[free_old[o]])
130 };
131 let pairs = common(
132 free_new.len(),
133 free_old.len(),
134 &same,
135 &shapes_new,
136 &shapes_old,
137 );
138 let mut new_taken = vec![false; free_new.len()];
139 let mut old_taken = vec![false; free_old.len()];
140 for &(n, o) in &pairs {
141 out[free_new[n]] = Some(free_old[o]);
142 new_taken[n] = true;
143 old_taken[o] = true;
144 }
145 let anchors = increasing(&pairs);
148 let mut last = (0, 0);
149 let ends = anchors
150 .iter()
151 .copied()
152 .chain([(free_new.len(), free_old.len())]);
153 for (an, ao) in ends {
154 let mut olds_left: Vec<usize> = (last.1..ao).filter(|&o| !old_taken[o]).collect();
155 for n in (last.0..an).filter(|&n| !new_taken[n]) {
156 let name = &news[free_new[n]].name;
157 if let Some(at) = olds_left
158 .iter()
159 .position(|&o| olds[free_old[o]].name == *name)
160 {
161 let o = olds_left.remove(at);
162 out[free_new[n]] = Some(free_old[o]);
163 olds_left.drain(..at);
165 }
166 }
167 last = (an + 1, ao + 1);
168 }
169 out
170}
171
172fn common(
178 n: usize,
179 m: usize,
180 same: &dyn Fn(usize, usize) -> bool,
181 keys_new: &[u64],
182 keys_old: &[u64],
183) -> Vec<(usize, usize)> {
184 let mut out = Vec::new();
185 let news: Vec<usize> = (0..n).collect();
186 let olds: Vec<usize> = (0..m).collect();
187 diff(&news, &olds, same, keys_new, keys_old, 0, &mut out);
188 out.sort_unstable();
189 out
190}
191
192fn diff(
197 news: &[usize],
198 olds: &[usize],
199 same: &dyn Fn(usize, usize) -> bool,
200 keys_new: &[u64],
201 keys_old: &[u64],
202 depth: usize,
203 out: &mut Vec<(usize, usize)>,
204) {
205 let (n, m) = (news.len(), olds.len());
206 let mut pre = 0;
207 while pre < n && pre < m && same(news[pre], olds[pre]) {
208 out.push((news[pre], olds[pre]));
209 pre += 1;
210 }
211 let mut suf = 0;
212 while suf < n - pre && suf < m - pre && same(news[n - 1 - suf], olds[m - 1 - suf]) {
213 out.push((news[n - 1 - suf], olds[m - 1 - suf]));
214 suf += 1;
215 }
216 let (news, olds) = (&news[pre..n - suf], &olds[pre..m - suf]);
217 if news.is_empty() || olds.is_empty() {
218 return;
219 }
220 if let Some(pairs) = myers(news.len(), olds.len(), &|i, j| same(news[i], olds[j])) {
221 out.extend(pairs.into_iter().map(|(i, j)| (news[i], olds[j])));
222 return;
223 }
224 let mut count: HashMap<u64, (u32, u32, usize, usize)> = HashMap::new();
227 for (i, &x) in news.iter().enumerate() {
228 let c = count.entry(keys_new[x]).or_insert((0, 0, 0, 0));
229 c.0 += 1;
230 c.2 = i;
231 }
232 for (j, &y) in olds.iter().enumerate() {
233 if let Some(c) = count.get_mut(&keys_old[y]) {
234 c.1 += 1;
235 c.3 = j;
236 }
237 }
238 let mut unique: Vec<(usize, usize)> = count
239 .values()
240 .filter(|&&(a, b, i, j)| a == 1 && b == 1 && same(news[i], olds[j]))
241 .map(|&(_, _, i, j)| (i, j))
242 .collect();
243 if unique.is_empty() || depth == MAX_DEPTH {
247 return;
249 }
250 unique.sort_unstable();
251 out.extend(unique.iter().map(|&(i, j)| (news[i], olds[j])));
252 let mut used_new = vec![false; news.len()];
255 let mut used_old = vec![false; olds.len()];
256 for &(i, j) in &unique {
257 used_new[i] = true;
258 used_old[j] = true;
259 }
260 let mut last = (0, 0);
261 for (i, j) in increasing(&unique)
262 .into_iter()
263 .chain([(news.len(), olds.len())])
264 {
265 let gap_new: Vec<usize> = (last.0..i)
266 .filter(|&k| !used_new[k])
267 .map(|k| news[k])
268 .collect();
269 let gap_old: Vec<usize> = (last.1..j)
270 .filter(|&k| !used_old[k])
271 .map(|k| olds[k])
272 .collect();
273 diff(&gap_new, &gap_old, same, keys_new, keys_old, depth + 1, out);
274 last = (i + 1, j + 1);
275 }
276}
277
278fn increasing(pairs: &[(usize, usize)]) -> Vec<(usize, usize)> {
281 let mut tails: Vec<usize> = Vec::new();
284 let mut prev = vec![usize::MAX; pairs.len()];
285 for (at, &(_, o)) in pairs.iter().enumerate() {
286 let k = tails.partition_point(|&t| pairs[t].1 < o);
287 if k > 0 {
288 prev[at] = tails[k - 1];
289 }
290 if k == tails.len() {
291 tails.push(at);
292 } else {
293 tails[k] = at;
294 }
295 }
296 let mut run = Vec::with_capacity(tails.len());
297 let mut at = tails.last().copied().unwrap_or(usize::MAX);
298 while at != usize::MAX {
299 run.push(pairs[at]);
300 at = prev[at];
301 }
302 run.reverse();
303 run
304}
305
306fn myers(n: usize, m: usize, same: &dyn Fn(usize, usize) -> bool) -> Option<Vec<(usize, usize)>> {
309 if n == 0 || m == 0 {
310 return Some(Vec::new());
311 }
312 let max = (n + m).min(MAX_EDITS);
313 let off = max as isize + 1;
314 let mut v = vec![0isize; 2 * max + 3];
315 let mut trace: Vec<Vec<isize>> = Vec::new();
316 for d in 0..=max as isize {
317 trace.push(v.clone());
318 let mut k = -d;
319 while k <= d {
320 let at = (k + off) as usize;
321 let mut x = if k == -d || (k != d && v[at - 1] < v[at + 1]) {
322 v[at + 1]
323 } else {
324 v[at - 1] + 1
325 };
326 let mut y = x - k;
327 while (x as usize) < n && y >= 0 && (y as usize) < m && same(x as usize, y as usize) {
328 x += 1;
329 y += 1;
330 }
331 v[at] = x;
332 if x >= n as isize && y >= m as isize {
333 return Some(backtrack(&trace, d, n, m, off));
334 }
335 k += 2;
336 }
337 }
338 None
339}
340
341fn backtrack(
344 trace: &[Vec<isize>],
345 d: isize,
346 n: usize,
347 m: usize,
348 off: isize,
349) -> Vec<(usize, usize)> {
350 let mut out = Vec::new();
351 let (mut x, mut y) = (n as isize, m as isize);
352 for d in (1..=d).rev() {
353 let v = &trace[d as usize];
354 let k = x - y;
355 let at = |k: isize| v[(k + off) as usize];
356 let prev_k = if k == -d || (k != d && at(k - 1) < at(k + 1)) {
357 k + 1
358 } else {
359 k - 1
360 };
361 let prev_x = at(prev_k);
362 let prev_y = prev_x - prev_k;
363 let (sx, sy) = if prev_k == k + 1 {
365 (prev_x, prev_y + 1)
366 } else {
367 (prev_x + 1, prev_y)
368 };
369 while x > sx && y > sy {
370 x -= 1;
371 y -= 1;
372 out.push((x as usize, y as usize));
373 }
374 x = prev_x;
375 y = prev_y;
376 }
377 while x > 0 && y > 0 {
378 x -= 1;
379 y -= 1;
380 out.push((x as usize, y as usize));
381 }
382 out.reverse();
383 out
384}
385
386fn shape(el: &Element) -> u64 {
389 use std::hash::{Hash, Hasher};
390 fn value(v: &Value, h: &mut std::collections::hash_map::DefaultHasher) {
391 match v {
392 Value::Str(s, _) => (0u8, s).hash(h),
393 Value::Theme(s, _) => (1u8, s).hash(h),
394 Value::Num(n) => (2u8, n.to_bits()).hash(h),
395 Value::Bool(b) => (3u8, b).hash(h),
396 Value::Prop(p) => (4u8, p).hash(h),
397 Value::Array(items) => {
398 (5u8, items.len()).hash(h);
399 for i in items {
400 value(i, h);
401 }
402 }
403 Value::Object(fields) => {
404 (6u8, fields.len()).hash(h);
405 for (k, v) in fields {
406 k.hash(h);
407 value(v, h);
408 }
409 }
410 other => format!("{other:?}").hash(h),
411 }
412 }
413 fn walk(el: &Element, h: &mut std::collections::hash_map::DefaultHasher) {
414 el.name.hash(h);
415 el.attrs.len().hash(h);
416 for a in &el.attrs {
417 a.name.hash(h);
418 value(&a.value, h);
419 }
420 el.children.len().hash(h);
421 for c in &el.children {
422 match c {
423 Child::Element(e) => walk(e, h),
424 Child::Text(parts, _) => {
425 for p in parts {
426 match p {
427 crate::parse::TextPart::Literal(s) => (0u8, s).hash(h),
428 crate::parse::TextPart::Prop(s) => (1u8, s).hash(h),
429 crate::parse::TextPart::Theme(s, _) => (2u8, s).hash(h),
430 }
431 }
432 }
433 }
434 }
435 }
436 let mut h = std::collections::hash_map::DefaultHasher::new();
437 walk(el, &mut h);
438 h.finish()
439}
440
441pub(crate) fn same_own(a: &Element, b: &Element) -> bool {
445 a.name == b.name
446 && a.attrs.len() == b.attrs.len()
447 && a.attrs.iter().zip(&b.attrs).all(|(x, y)| same_attr(x, y))
448}
449
450fn same_attr(a: &Attr, b: &Attr) -> bool {
451 a.name == b.name && same_value(&a.value, &b.value)
452}
453
454pub(crate) fn same_value(a: &Value, b: &Value) -> bool {
455 match (a, b) {
456 (Value::Str(x, _), Value::Str(y, _)) => x == y,
457 (Value::Theme(x, _), Value::Theme(y, _)) => x == y,
458 (Value::Array(x), Value::Array(y)) => {
459 x.len() == y.len() && x.iter().zip(y).all(|(a, b)| same_value(a, b))
460 }
461 (Value::Object(x), Value::Object(y)) => {
462 x.len() == y.len()
463 && x.iter()
464 .zip(y)
465 .all(|((ka, a), (kb, b))| ka == kb && same_value(a, b))
466 }
467 _ => a == b,
468 }
469}
470
471#[cfg(test)]
472mod tests;