1use crate::node::{Mark, Node};
52use crate::text_diff::{self, DiffGranularity, DiffOptions};
53use serde::{Deserialize, Serialize};
54use serde_json::{Map, Value};
55use std::collections::{HashMap, HashSet};
56use std::fmt;
57
58#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
62#[serde(tag = "op", rename_all = "camelCase", rename_all_fields = "camelCase")]
63pub enum Change {
64 SetAttr {
66 path: Vec<usize>,
68 key: String,
70 value: Value,
72 },
73 RemoveAttr {
75 path: Vec<usize>,
77 key: String,
79 },
80 SetText {
82 path: Vec<usize>,
84 text: Option<String>,
86 },
87 SetMarks {
89 path: Vec<usize>,
91 marks: Option<Vec<Mark>>,
93 },
94 SetExtra {
96 path: Vec<usize>,
98 key: String,
100 value: Value,
102 },
103 RemoveExtra {
105 path: Vec<usize>,
107 key: String,
109 },
110 Insert {
112 path: Vec<usize>,
114 index: usize,
116 node: Node,
118 },
119 Remove {
121 path: Vec<usize>,
123 index: usize,
125 },
126 Replace {
128 path: Vec<usize>,
130 node: Node,
132 },
133 Move {
139 path: Vec<usize>,
141 from: usize,
143 to: usize,
145 },
146 SpliceText {
155 path: Vec<usize>,
157 from: usize,
159 len_del: usize,
161 insert: String,
163 },
164}
165
166#[derive(Debug, Clone, PartialEq, Eq)]
169pub struct ApplyError {
170 pub path: Vec<usize>,
172}
173
174impl fmt::Display for ApplyError {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 write!(f, "apply: no node at path {:?}", self.path)
177 }
178}
179
180impl std::error::Error for ApplyError {}
181
182impl Node {
183 pub fn diff(&self, other: &Node) -> Vec<Change> {
186 self.diff_with(other, &DiffOptions::default())
187 }
188
189 pub fn diff_with(&self, other: &Node, opts: &DiffOptions) -> Vec<Change> {
192 let mut out = Vec::new();
193 let mut path = Vec::new();
194 diff_node(self, other, &mut path, &mut out, opts);
195 out
196 }
197
198 pub fn apply(&mut self, changes: &[Change]) -> std::result::Result<(), ApplyError> {
200 apply(self, changes)
201 }
202
203 pub fn invert(&self, changes: &[Change]) -> std::result::Result<Vec<Change>, ApplyError> {
205 invert(self, changes)
206 }
207}
208
209pub(crate) fn diff_at(a: &Node, b: &Node, prefix: &[usize]) -> Vec<Change> {
212 let mut out = Vec::new();
213 let mut path = prefix.to_vec();
214 diff_node(a, b, &mut path, &mut out, &DiffOptions::default());
215 out
216}
217
218pub fn diff(a: &Node, b: &Node) -> Vec<Change> {
220 a.diff(b)
221}
222
223pub fn apply(root: &mut Node, changes: &[Change]) -> std::result::Result<(), ApplyError> {
229 for change in changes {
230 apply_one(root, change)?;
231 }
232 Ok(())
233}
234
235pub fn invert(base: &Node, changes: &[Change]) -> std::result::Result<Vec<Change>, ApplyError> {
255 let mut result = base.clone();
256 apply(&mut result, changes)?;
257 Ok(result.diff(base))
258}
259
260fn diff_node(a: &Node, b: &Node, path: &mut Vec<usize>, out: &mut Vec<Change>, opts: &DiffOptions) {
263 if a == b {
264 return; }
266 if a.node_type != b.node_type
267 || empty_shape_mismatch(
268 a.attrs.as_deref().map(Map::is_empty),
269 b.attrs.as_deref().map(Map::is_empty),
270 )
271 || empty_shape_mismatch(
272 a.content.as_ref().map(Vec::is_empty),
273 b.content.as_ref().map(Vec::is_empty),
274 )
275 {
276 out.push(Change::Replace {
279 path: path.clone(),
280 node: b.clone(),
281 });
282 return;
283 }
284 diff_attrs(a.attrs.as_deref(), b.attrs.as_deref(), path, out);
285 if a.text != b.text {
286 diff_text_field(a.text.as_deref(), b.text.as_deref(), path, out, opts);
287 }
288 if a.marks != b.marks {
289 out.push(Change::SetMarks {
290 path: path.clone(),
291 marks: b.marks.clone(),
292 });
293 }
294 diff_extra(a.extra.as_deref(), b.extra.as_deref(), path, out);
295 diff_children(a.children(), b.children(), path, out, opts);
296}
297
298fn diff_text_field(
300 a: Option<&str>,
301 b: Option<&str>,
302 path: &mut [usize],
303 out: &mut Vec<Change>,
304 opts: &DiffOptions,
305) {
306 if let (Some(at), Some(bt)) = (a, b) {
308 match opts.text {
309 DiffGranularity::Inline => {
310 let segs = text_diff::diff_text(at, bt);
311 text_diff::splices_from_segments(path, &segs, out);
312 return;
313 }
314 DiffGranularity::Smart { replace_threshold } => {
315 let segs = text_diff::diff_text(at, bt);
316 let total = at.chars().count() + bt.chars().count();
317 let changed = text_diff::changed_scalars(&segs);
318 if total == 0 || (changed as f32 / total as f32) <= replace_threshold {
319 text_diff::splices_from_segments(path, &segs, out);
320 return;
321 }
322 }
323 DiffGranularity::Block => {}
324 }
325 }
326 out.push(Change::SetText {
327 path: path.to_vec(),
328 text: b.map(str::to_owned),
329 });
330}
331
332fn empty_shape_mismatch(a_is_empty: Option<bool>, b_is_empty: Option<bool>) -> bool {
338 match b_is_empty {
339 Some(true) => a_is_empty != Some(true),
340 None => a_is_empty == Some(true),
341 Some(false) => false,
342 }
343}
344
345fn diff_attrs(
346 a: Option<&Map<String, Value>>,
347 b: Option<&Map<String, Value>>,
348 path: &mut [usize],
349 out: &mut Vec<Change>,
350) {
351 let empty = Map::new();
352 let am = a.unwrap_or(&empty);
353 let bm = b.unwrap_or(&empty);
354 for (k, v) in bm {
355 if am.get(k) != Some(v) {
356 out.push(Change::SetAttr {
357 path: path.to_vec(),
358 key: k.clone(),
359 value: v.clone(),
360 });
361 }
362 }
363 for k in am.keys() {
364 if !bm.contains_key(k) {
365 out.push(Change::RemoveAttr {
366 path: path.to_vec(),
367 key: k.clone(),
368 });
369 }
370 }
371}
372
373fn diff_extra(
374 a: Option<&Map<String, Value>>,
375 b: Option<&Map<String, Value>>,
376 path: &mut [usize],
377 out: &mut Vec<Change>,
378) {
379 if a.is_none_or(Map::is_empty) && b.is_none_or(Map::is_empty) {
380 return;
381 }
382 let empty = Map::new();
383 let am = a.unwrap_or(&empty);
384 let bm = b.unwrap_or(&empty);
385 for (k, v) in bm {
386 if am.get(k) != Some(v) {
387 out.push(Change::SetExtra {
388 path: path.to_vec(),
389 key: k.clone(),
390 value: v.clone(),
391 });
392 }
393 }
394 for k in am.keys() {
395 if !bm.contains_key(k) {
396 out.push(Change::RemoveExtra {
397 path: path.to_vec(),
398 key: k.clone(),
399 });
400 }
401 }
402}
403
404enum Step {
406 Match,
407 Del(usize),
408 Ins(usize),
409}
410
411#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
414enum Key {
415 Orig(usize),
416 New(usize),
417}
418
419enum Role {
422 Modify(usize),
423 Replace(usize),
424}
425
426fn diff_children(
427 a: &[Node],
428 b: &[Node],
429 path: &mut Vec<usize>,
430 out: &mut Vec<Change>,
431 opts: &DiffOptions,
432) {
433 let mut start = 0;
436 while start < a.len() && start < b.len() && a[start] == b[start] {
437 start += 1;
438 }
439 let mut ea = a.len();
440 let mut eb = b.len();
441 while ea > start && eb > start && a[ea - 1] == b[eb - 1] {
442 ea -= 1;
443 eb -= 1;
444 }
445
446 let am = &a[start..ea];
447 let bm = &b[start..eb];
448 if am.is_empty() && bm.is_empty() {
449 return;
450 }
451
452 let (ida, idb) = intern(am, bm);
455 let steps = lcs_align(&ida, &idb);
456
457 let mut gaps: Vec<(Vec<usize>, Vec<usize>)> = Vec::new();
460 let mut cur_dels: Vec<usize> = Vec::new();
461 let mut cur_inss: Vec<usize> = Vec::new();
462 let mut bm_match_src: HashMap<usize, usize> = HashMap::new(); let (mut ai, mut bj) = (0usize, 0usize);
464 for step in &steps {
465 match step {
466 Step::Match => {
467 gaps.push((std::mem::take(&mut cur_dels), std::mem::take(&mut cur_inss)));
468 bm_match_src.insert(bj, ai);
469 ai += 1;
470 bj += 1;
471 }
472 Step::Del(i) => {
473 cur_dels.push(*i);
474 ai += 1;
475 }
476 Step::Ins(j) => {
477 cur_inss.push(*j);
478 bj += 1;
479 }
480 }
481 }
482 gaps.push((cur_dels, cur_inss));
483
484 let mut dels_by_id: HashMap<u32, std::collections::VecDeque<usize>> = HashMap::new();
488 for (dels, _) in &gaps {
489 for &d in dels {
490 dels_by_id.entry(ida[d]).or_default().push_back(d);
491 }
492 }
493 let mut bm_move_src: HashMap<usize, usize> = HashMap::new(); let mut am_moved: HashSet<usize> = HashSet::new();
495 for (_, inss) in &gaps {
496 for &j in inss {
497 if let Some(d) = dels_by_id.get_mut(&idb[j]).and_then(|q| q.pop_front()) {
498 bm_move_src.insert(j, d);
499 am_moved.insert(d);
500 }
501 }
502 }
503
504 let mut bm_role: HashMap<usize, Role> = HashMap::new();
506 let mut removed_am: Vec<usize> = Vec::new();
507 for (dels, inss) in &gaps {
508 let rem_dels: Vec<usize> = dels
509 .iter()
510 .copied()
511 .filter(|d| !am_moved.contains(d))
512 .collect();
513 let rem_inss: Vec<usize> = inss
514 .iter()
515 .copied()
516 .filter(|j| !bm_move_src.contains_key(j))
517 .collect();
518 let pairs = rem_dels.len().min(rem_inss.len());
519 for k in 0..pairs {
520 let (d, j) = (rem_dels[k], rem_inss[k]);
521 if am[d].node_type == bm[j].node_type {
522 bm_role.insert(j, Role::Modify(d)); } else {
524 bm_role.insert(j, Role::Replace(d)); }
526 }
527 removed_am.extend_from_slice(&rem_dels[pairs..]);
528 }
529
530 let n_orig = am.len() as u32;
534 let mut target: Vec<u32> = Vec::with_capacity(bm.len());
535 for j in 0..bm.len() {
536 let key = if let Some(&i) = bm_match_src.get(&j) {
537 Key::Orig(i)
538 } else if let Some(&d) = bm_move_src.get(&j) {
539 Key::Orig(d)
540 } else {
541 match bm_role.get(&j) {
542 Some(Role::Modify(d) | Role::Replace(d)) => Key::Orig(*d),
543 None => Key::New(j),
544 }
545 };
546 target.push(match key {
547 Key::Orig(i) => i as u32,
548 Key::New(j) => n_orig + j as u32,
549 });
550 }
551 let n_ids = am.len() + bm.len();
552 let mut target_pos = vec![u32::MAX; n_ids];
553 for (t, &k) in target.iter().enumerate() {
554 target_pos[k as usize] = t as u32;
555 }
556 let mut is_moved = vec![false; n_ids];
557 for &d in &am_moved {
558 is_moved[d] = true;
559 }
560
561 for (k, &d) in removed_am.iter().enumerate() {
564 out.push(Change::Remove {
565 path: path.clone(),
566 index: start + d - k,
567 });
568 }
569 let mut is_removed = vec![false; am.len()];
570 for &d in &removed_am {
571 is_removed[d] = true;
572 }
573 let post_remove = || (0..n_orig).filter(|&i| !is_removed[i as usize]);
574
575 let mark = out.len();
578 if !settle_sorted(
579 bm,
580 &target,
581 &target_pos,
582 &is_moved,
583 am_moved.len(),
584 post_remove(),
585 start,
586 path,
587 out,
588 ) {
589 out.truncate(mark);
593 settle_cursor(bm, &target, &is_moved, post_remove(), start, path, out);
594 }
595
596 for (j, target_node) in bm.iter().enumerate() {
599 match bm_role.get(&j) {
600 Some(Role::Modify(d)) => {
601 path.push(start + j);
602 diff_node(&am[*d], target_node, path, out, opts);
603 path.pop();
604 }
605 Some(Role::Replace(_)) => {
606 let mut child = path.clone();
607 child.push(start + j);
608 out.push(Change::Replace {
609 path: child,
610 node: target_node.clone(),
611 });
612 }
613 None => {}
614 }
615 }
616}
617
618#[allow(clippy::too_many_arguments)]
625fn settle_sorted(
626 bm: &[Node],
627 target: &[u32],
628 target_pos: &[u32],
629 is_moved: &[bool],
630 budget: usize,
631 live0: impl Iterator<Item = u32>,
632 start: usize,
633 path: &[usize],
634 out: &mut Vec<Change>,
635) -> bool {
636 let n_orig = is_moved.len() - bm.len();
637 let mut live = LiveList::new(live0, is_moved.len());
638 let mut present = Fenwick::new(target.len());
640 for (t, &k) in target.iter().enumerate() {
641 if (k as usize) < n_orig {
642 present.add(t);
643 }
644 }
645 let mut moves = 0;
646 let mut p = 0;
647 while p < target.len() {
648 let want = target[p];
649 let cur = live.get(p);
650 if cur == Some(want) {
651 p += 1;
652 continue;
653 }
654 if want as usize >= n_orig {
655 out.push(Change::Insert {
656 path: path.to_vec(),
657 index: start + p,
658 node: bm[want as usize - n_orig].clone(),
659 });
660 live.insert(p, want);
661 present.add(p);
662 p += 1;
663 continue;
664 }
665 if moves == budget {
666 return false;
667 }
668 moves += 1;
669 let cur = cur.expect("original node missing from live list");
672 let mover = if is_moved[cur as usize] { cur } else { want };
673 let from = live.index_of(mover);
674 let dest = present.prefix(target_pos[mover as usize] as usize);
677 out.push(Change::Move {
678 path: path.to_vec(),
679 from: start + from,
680 to: start + dest,
681 });
682 let k = live.remove(from);
683 live.insert(dest, k);
684 }
686 true
687}
688
689fn settle_cursor(
695 bm: &[Node],
696 target: &[u32],
697 is_moved: &[bool],
698 live0: impl Iterator<Item = u32>,
699 start: usize,
700 path: &[usize],
701 out: &mut Vec<Change>,
702) {
703 let n_orig = is_moved.len() - bm.len();
704 let mut live = LiveList::new(live0, is_moved.len());
705 let mut cur = 0;
706 for &want in target {
707 if want as usize >= n_orig {
708 out.push(Change::Insert {
709 path: path.to_vec(),
710 index: start + cur,
711 node: bm[want as usize - n_orig].clone(),
712 });
713 live.insert(cur, want);
714 cur += 1;
715 continue;
716 }
717 let at = live.index_of(want);
718 if !is_moved[want as usize] {
719 debug_assert!(at >= cur, "non-moved node behind the cursor");
720 cur = at + 1;
721 continue;
722 }
723 if at == cur {
724 cur += 1;
725 continue;
726 }
727 live.remove(at);
728 if at < cur {
729 cur -= 1;
730 }
731 out.push(Change::Move {
732 path: path.to_vec(),
733 from: start + at,
734 to: start + cur,
735 });
736 live.insert(cur, want);
737 cur += 1;
738 }
739 debug_assert_eq!(
740 live.to_vec(),
741 target,
742 "diff move simulation diverged from target"
743 );
744}
745
746struct LiveList {
750 blocks: Vec<Vec<u32>>,
751 block_of: Vec<u32>,
753 cap: usize,
754}
755
756impl LiveList {
757 fn new(keys: impl Iterator<Item = u32>, n_ids: usize) -> Self {
758 let mut l = LiveList {
759 blocks: vec![keys.collect()],
760 block_of: vec![0; n_ids],
761 cap: 16,
762 };
763 l.rebuild();
764 l
765 }
766
767 fn rebuild(&mut self) {
769 let all = self.to_vec();
770 self.cap = (all.len() as f64).sqrt() as usize + 16;
771 self.blocks = all.chunks(self.cap).map(<[u32]>::to_vec).collect();
772 if self.blocks.is_empty() {
773 self.blocks.push(Vec::new());
774 }
775 for (b, blk) in self.blocks.iter().enumerate() {
776 for &k in blk {
777 self.block_of[k as usize] = b as u32;
778 }
779 }
780 }
781
782 fn to_vec(&self) -> Vec<u32> {
783 self.blocks.concat()
784 }
785
786 fn locate(&self, mut idx: usize) -> (usize, usize) {
789 let last = self.blocks.len() - 1;
790 for (b, blk) in self.blocks.iter().enumerate() {
791 if idx < blk.len() || b == last {
792 return (b, idx);
793 }
794 idx -= blk.len();
795 }
796 unreachable!()
797 }
798
799 fn get(&self, idx: usize) -> Option<u32> {
800 let (b, o) = self.locate(idx);
801 self.blocks[b].get(o).copied()
802 }
803
804 fn index_of(&self, key: u32) -> usize {
805 let b = self.block_of[key as usize] as usize;
806 let before: usize = self.blocks[..b].iter().map(Vec::len).sum();
807 before
808 + self.blocks[b]
809 .iter()
810 .position(|&k| k == key)
811 .expect("key in its block")
812 }
813
814 fn remove(&mut self, idx: usize) -> u32 {
815 let (b, o) = self.locate(idx);
816 self.blocks[b].remove(o)
817 }
818
819 fn insert(&mut self, idx: usize, key: u32) {
820 let (b, o) = self.locate(idx);
821 self.blocks[b].insert(o, key);
822 self.block_of[key as usize] = b as u32;
823 if self.blocks[b].len() > 2 * self.cap {
824 self.rebuild();
825 }
826 }
827}
828
829struct Fenwick(Vec<u32>);
831
832impl Fenwick {
833 fn new(n: usize) -> Self {
834 Fenwick(vec![0; n])
835 }
836
837 fn add(&mut self, mut i: usize) {
840 while i < self.0.len() {
841 self.0[i] += 1;
842 i |= i + 1;
843 }
844 }
845
846 fn prefix(&self, mut i: usize) -> usize {
848 let mut s = 0;
849 while i > 0 {
850 s += self.0[i - 1] as usize;
851 i &= i - 1;
852 }
853 s
854 }
855}
856
857const DP_CELLS: usize = 1 << 16;
862
863const MYERS_MAX_D: usize = 4096;
866const DP_FALLBACK_CELLS: usize = 1 << 24;
867
868fn lcs_align(a: &[u32], b: &[u32]) -> Vec<Step> {
871 let (m, n) = (a.len(), b.len());
872 if m == 0 {
873 return (0..n).map(Step::Ins).collect();
874 }
875 if n == 0 {
876 return (0..m).map(Step::Del).collect();
877 }
878 if m.saturating_mul(n) <= DP_CELLS {
879 return lcs_table(a, b);
880 }
881 if let Some(steps) = myers(a, b, MYERS_MAX_D) {
882 return steps;
883 }
884 if m.saturating_mul(n) <= DP_FALLBACK_CELLS {
885 return lcs_table(a, b);
886 }
887 (0..m).map(Step::Del).chain((0..n).map(Step::Ins)).collect()
890}
891
892fn lcs_table(a: &[u32], b: &[u32]) -> Vec<Step> {
894 let (m, n) = (a.len(), b.len());
895 let w = n + 1;
897 let mut dp = vec![0u32; (m + 1) * w];
898 for i in (0..m).rev() {
899 for j in (0..n).rev() {
900 dp[i * w + j] = if a[i] == b[j] {
901 dp[(i + 1) * w + j + 1] + 1
902 } else {
903 dp[(i + 1) * w + j].max(dp[i * w + j + 1])
904 };
905 }
906 }
907 let mut steps = Vec::with_capacity(m.max(n));
908 let (mut i, mut j) = (0usize, 0usize);
909 while i < m && j < n {
910 if a[i] == b[j] {
911 steps.push(Step::Match);
912 i += 1;
913 j += 1;
914 } else if dp[(i + 1) * w + j] >= dp[i * w + j + 1] {
915 steps.push(Step::Del(i));
916 i += 1;
917 } else {
918 steps.push(Step::Ins(j));
919 j += 1;
920 }
921 }
922 while i < m {
923 steps.push(Step::Del(i));
924 i += 1;
925 }
926 while j < n {
927 steps.push(Step::Ins(j));
928 j += 1;
929 }
930 steps
931}
932
933fn myers(a: &[u32], b: &[u32], max_d: usize) -> Option<Vec<Step>> {
936 if a.len().abs_diff(b.len()) > max_d {
938 return None;
939 }
940 let (n, m) = (a.len() as isize, b.len() as isize);
941 let max_d = max_d.min(a.len() + b.len()) as isize;
942 let off = max_d + 1;
943 let mut v = vec![0isize; (2 * off + 1) as usize];
945 let mut trace: Vec<Vec<isize>> = Vec::new();
947 let mut end_d = None;
948 'outer: for d in 0..=max_d {
949 trace.push(v[(off - d) as usize..=(off + d) as usize].to_vec());
950 let mut k = -d;
951 while k <= d {
952 let down = k == -d || (k != d && v[(off + k - 1) as usize] < v[(off + k + 1) as usize]);
953 let mut x = if down {
954 v[(off + k + 1) as usize]
955 } else {
956 v[(off + k - 1) as usize] + 1
957 };
958 let mut y = x - k;
959 while x < n && y < m && a[x as usize] == b[y as usize] {
960 x += 1;
961 y += 1;
962 }
963 v[(off + k) as usize] = x;
964 if x >= n && y >= m {
965 end_d = Some(d);
966 break 'outer;
967 }
968 k += 2;
969 }
970 }
971 end_d?;
972 let mut steps = Vec::with_capacity((n + m) as usize);
974 let (mut x, mut y) = (n, m);
975 for d in (0..trace.len() as isize).rev() {
976 if d == 0 {
977 while x > 0 && y > 0 {
978 steps.push(Step::Match);
979 x -= 1;
980 y -= 1;
981 }
982 break;
983 }
984 let vd = &trace[d as usize];
985 let get = |k: isize| vd[(k + d) as usize];
986 let k = x - y;
987 let prev_k = if k == -d || (k != d && get(k - 1) < get(k + 1)) {
988 k + 1
989 } else {
990 k - 1
991 };
992 let prev_x = get(prev_k);
993 let prev_y = prev_x - prev_k;
994 while x > prev_x && y > prev_y {
995 steps.push(Step::Match);
996 x -= 1;
997 y -= 1;
998 }
999 if x == prev_x {
1000 steps.push(Step::Ins((y - 1) as usize));
1001 } else {
1002 steps.push(Step::Del((x - 1) as usize));
1003 }
1004 x = prev_x;
1005 y = prev_y;
1006 }
1007 steps.reverse();
1008 Some(steps)
1009}
1010
1011fn intern(a: &[Node], b: &[Node]) -> (Vec<u32>, Vec<u32>) {
1016 let mut buckets: HashMap<u64, Vec<(u32, &Node)>> = HashMap::with_capacity(a.len() + b.len());
1017 let mut next = 0u32;
1018 let mut out_a = Vec::with_capacity(a.len());
1019 let mut out_b = Vec::with_capacity(b.len());
1020 for (side, nodes) in [(0, a), (1, b)] {
1021 for n in nodes {
1022 let bucket = buckets.entry(node_hash(n)).or_default();
1023 let found = bucket.iter().find(|(_, rep)| *rep == n).map(|(i, _)| *i);
1024 let i = found.unwrap_or_else(|| {
1025 let i = next;
1026 next += 1;
1027 bucket.push((i, n));
1028 i
1029 });
1030 if side == 0 {
1031 out_a.push(i);
1032 } else {
1033 out_b.push(i);
1034 }
1035 }
1036 }
1037 (out_a, out_b)
1038}
1039
1040fn node_hash(n: &Node) -> u64 {
1043 let mut h = Fx::default();
1044 hash_node(n, &mut h);
1045 h.0
1046}
1047
1048#[derive(Default)]
1049struct Fx(u64);
1050
1051impl Fx {
1052 #[inline]
1053 fn add(&mut self, x: u64) {
1054 self.0 = (self.0.rotate_left(5) ^ x).wrapping_mul(0x51_7c_c1_b7_27_22_0a_95);
1055 }
1056 #[inline]
1057 fn bytes(&mut self, s: &[u8]) {
1058 let (chunks, rest) = s.as_chunks::<8>();
1059 for c in chunks {
1060 self.add(u64::from_le_bytes(*c));
1061 }
1062 let mut tail = [0u8; 8];
1063 tail[..rest.len()].copy_from_slice(rest);
1064 self.add(u64::from_le_bytes(tail) ^ ((s.len() as u64) << 56));
1065 }
1066 #[inline]
1067 fn opt_str(&mut self, s: Option<&str>) {
1068 match s {
1069 None => self.add(0x9e37),
1070 Some(s) => self.bytes(s.as_bytes()),
1071 }
1072 }
1073}
1074
1075fn hash_node(n: &Node, h: &mut Fx) {
1076 h.opt_str(n.node_type.as_deref());
1077 hash_opt_map(n.attrs.as_deref(), h);
1078 match &n.content {
1079 None => h.add(1),
1080 Some(c) => {
1081 h.add(2 ^ ((c.len() as u64) << 8));
1082 for child in c {
1083 hash_node(child, h);
1084 }
1085 }
1086 }
1087 match &n.marks {
1088 None => h.add(3),
1089 Some(ms) => {
1090 h.add(4 ^ ((ms.len() as u64) << 8));
1091 for m in ms {
1092 h.bytes(m.mark_type.as_bytes());
1093 hash_opt_map(m.attrs.as_deref(), h);
1094 hash_extra(m.extra.as_deref(), h);
1095 }
1096 }
1097 }
1098 h.opt_str(n.text.as_deref());
1099 hash_extra(n.extra.as_deref(), h);
1100}
1101
1102fn hash_opt_map(m: Option<&Map<String, Value>>, h: &mut Fx) {
1103 match m {
1104 None => h.add(5),
1105 Some(m) => hash_map(m, h),
1106 }
1107}
1108
1109fn hash_extra(m: Option<&Map<String, Value>>, h: &mut Fx) {
1111 match m {
1112 Some(m) => hash_map(m, h),
1113 None => {
1114 h.add(6);
1115 h.add(0);
1116 }
1117 }
1118}
1119
1120fn hash_map(m: &Map<String, Value>, h: &mut Fx) {
1122 let mut sum = 0u64;
1123 for (k, v) in m {
1124 let mut e = Fx::default();
1125 e.bytes(k.as_bytes());
1126 hash_value(v, &mut e);
1127 sum = sum.wrapping_add(e.0);
1128 }
1129 h.add(6 ^ ((m.len() as u64) << 8));
1130 h.add(sum);
1131}
1132
1133fn hash_value(v: &Value, h: &mut Fx) {
1134 match v {
1135 Value::Null => h.add(10),
1136 Value::Bool(b) => h.add(11 + *b as u64),
1137 Value::Number(n) => {
1138 if let Some(u) = n.as_u64() {
1139 h.add(13);
1140 h.add(u);
1141 } else if let Some(i) = n.as_i64() {
1142 h.add(14);
1143 h.add(i as u64);
1144 } else {
1145 let f = n.as_f64().unwrap_or(0.0);
1147 h.add(15);
1148 h.add(if f == 0.0 { 0 } else { f.to_bits() });
1149 }
1150 }
1151 Value::String(s) => {
1152 h.add(16);
1153 h.bytes(s.as_bytes());
1154 }
1155 Value::Array(a) => {
1156 h.add(17 ^ ((a.len() as u64) << 8));
1157 for x in a {
1158 hash_value(x, h);
1159 }
1160 }
1161 Value::Object(m) => {
1162 h.add(18);
1163 hash_map(m, h);
1164 }
1165 }
1166}
1167
1168fn node_at_mut<'a>(
1171 root: &'a mut Node,
1172 path: &[usize],
1173) -> std::result::Result<&'a mut Node, ApplyError> {
1174 root.node_at_mut(path).ok_or_else(|| ApplyError {
1175 path: path.to_vec(),
1176 })
1177}
1178
1179fn apply_one(root: &mut Node, change: &Change) -> std::result::Result<(), ApplyError> {
1180 match change {
1181 Change::SetAttr { path, key, value } => {
1182 node_at_mut(root, path)?.set_attr(key.clone(), value.clone());
1183 }
1184 Change::RemoveAttr { path, key } => {
1185 node_at_mut(root, path)?.remove_attr(key);
1186 }
1187 Change::SetText { path, text } => {
1188 node_at_mut(root, path)?.text = text.clone();
1189 }
1190 Change::SpliceText {
1191 path,
1192 from,
1193 len_del,
1194 insert,
1195 } => {
1196 let node = node_at_mut(root, path)?;
1197 let (start, end) = {
1202 let cur = node.text.as_deref().unwrap_or("");
1203 let scalars = cur.chars().count();
1204 let end_scalar = match from.checked_add(*len_del) {
1205 Some(e) if *from <= scalars && e <= scalars => e,
1206 _ => return Err(ApplyError { path: path.clone() }),
1207 };
1208 let start = cur.char_indices().nth(*from).map_or(cur.len(), |(b, _)| b);
1209 let end = cur
1210 .char_indices()
1211 .nth(end_scalar)
1212 .map_or(cur.len(), |(b, _)| b);
1213 (start, end)
1214 };
1215 if start != end || !insert.is_empty() {
1219 node.text
1220 .get_or_insert_with(String::new)
1221 .replace_range(start..end, insert);
1222 }
1223 }
1224 Change::SetMarks { path, marks } => {
1225 node_at_mut(root, path)?.marks = marks.clone();
1226 }
1227 Change::SetExtra { path, key, value } => {
1228 node_at_mut(root, path)?
1229 .extra_mut()
1230 .insert(key.clone(), value.clone());
1231 }
1232 Change::RemoveExtra { path, key } => {
1233 node_at_mut(root, path)?.remove_extra(key);
1234 }
1235 Change::Insert { path, index, node } => {
1236 let parent = node_at_mut(root, path)?;
1237 if *index > parent.child_count() {
1238 let mut p = path.clone();
1239 p.push(*index);
1240 return Err(ApplyError { path: p });
1241 }
1242 parent.insert_child(*index, node.clone());
1243 }
1244 Change::Remove { path, index } => {
1245 if node_at_mut(root, path)?.remove_child(*index).is_none() {
1246 let mut p = path.clone();
1247 p.push(*index);
1248 return Err(ApplyError { path: p });
1249 }
1250 }
1251 Change::Replace { path, node } => {
1252 if path.is_empty() {
1253 *root = node.clone();
1254 } else {
1255 let (parent_path, last) = path.split_at(path.len() - 1);
1256 let parent = node_at_mut(root, parent_path)?;
1257 if parent.replace_child(last[0], node.clone()).is_none() {
1258 return Err(ApplyError { path: path.clone() });
1259 }
1260 }
1261 }
1262 Change::Move { path, from, to } => {
1263 let parent = node_at_mut(root, path)?;
1264 let len = parent.child_count();
1265 if *from >= len || *to >= len {
1268 let mut p = path.clone();
1269 p.push(if *from >= len { *from } else { *to });
1270 return Err(ApplyError { path: p });
1271 }
1272 let node = parent.remove_child(*from).expect("from bounds-checked");
1273 parent.insert_child(*to, node);
1274 }
1275 }
1276 Ok(())
1277}