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 fn diff(a: &Node, b: &Node) -> Vec<Change> {
211 a.diff(b)
212}
213
214pub fn apply(root: &mut Node, changes: &[Change]) -> std::result::Result<(), ApplyError> {
220 for change in changes {
221 apply_one(root, change)?;
222 }
223 Ok(())
224}
225
226pub fn invert(base: &Node, changes: &[Change]) -> std::result::Result<Vec<Change>, ApplyError> {
246 let mut result = base.clone();
247 apply(&mut result, changes)?;
248 Ok(result.diff(base))
249}
250
251fn diff_node(a: &Node, b: &Node, path: &mut Vec<usize>, out: &mut Vec<Change>, opts: &DiffOptions) {
254 if a == b {
255 return; }
257 if a.node_type != b.node_type
258 || empty_shape_mismatch(
259 a.attrs.as_ref().map(Map::is_empty),
260 b.attrs.as_ref().map(Map::is_empty),
261 )
262 || empty_shape_mismatch(
263 a.content.as_ref().map(Vec::is_empty),
264 b.content.as_ref().map(Vec::is_empty),
265 )
266 {
267 out.push(Change::Replace {
270 path: path.clone(),
271 node: b.clone(),
272 });
273 return;
274 }
275 diff_attrs(a.attrs.as_ref(), b.attrs.as_ref(), path, out);
276 if a.text != b.text {
277 diff_text_field(a.text.as_deref(), b.text.as_deref(), path, out, opts);
278 }
279 if a.marks != b.marks {
280 out.push(Change::SetMarks {
281 path: path.clone(),
282 marks: b.marks.clone(),
283 });
284 }
285 diff_extra(&a.extra, &b.extra, path, out);
286 diff_children(a.children(), b.children(), path, out, opts);
287}
288
289fn diff_text_field(
291 a: Option<&str>,
292 b: Option<&str>,
293 path: &mut [usize],
294 out: &mut Vec<Change>,
295 opts: &DiffOptions,
296) {
297 if let (Some(at), Some(bt)) = (a, b) {
299 match opts.text {
300 DiffGranularity::Inline => {
301 let segs = text_diff::diff_text(at, bt);
302 text_diff::splices_from_segments(path, &segs, out);
303 return;
304 }
305 DiffGranularity::Smart { replace_threshold } => {
306 let segs = text_diff::diff_text(at, bt);
307 let total = at.chars().count() + bt.chars().count();
308 let changed = text_diff::changed_scalars(&segs);
309 if total == 0 || (changed as f32 / total as f32) <= replace_threshold {
310 text_diff::splices_from_segments(path, &segs, out);
311 return;
312 }
313 }
314 DiffGranularity::Block => {}
315 }
316 }
317 out.push(Change::SetText {
318 path: path.to_vec(),
319 text: b.map(str::to_owned),
320 });
321}
322
323fn empty_shape_mismatch(a_is_empty: Option<bool>, b_is_empty: Option<bool>) -> bool {
329 match b_is_empty {
330 Some(true) => a_is_empty != Some(true),
331 None => a_is_empty == Some(true),
332 Some(false) => false,
333 }
334}
335
336fn diff_attrs(
337 a: Option<&Map<String, Value>>,
338 b: Option<&Map<String, Value>>,
339 path: &mut [usize],
340 out: &mut Vec<Change>,
341) {
342 let empty = Map::new();
343 let am = a.unwrap_or(&empty);
344 let bm = b.unwrap_or(&empty);
345 for (k, v) in bm {
346 if am.get(k) != Some(v) {
347 out.push(Change::SetAttr {
348 path: path.to_vec(),
349 key: k.clone(),
350 value: v.clone(),
351 });
352 }
353 }
354 for k in am.keys() {
355 if !bm.contains_key(k) {
356 out.push(Change::RemoveAttr {
357 path: path.to_vec(),
358 key: k.clone(),
359 });
360 }
361 }
362}
363
364fn diff_extra(
365 am: &Map<String, Value>,
366 bm: &Map<String, Value>,
367 path: &mut [usize],
368 out: &mut Vec<Change>,
369) {
370 for (k, v) in bm {
371 if am.get(k) != Some(v) {
372 out.push(Change::SetExtra {
373 path: path.to_vec(),
374 key: k.clone(),
375 value: v.clone(),
376 });
377 }
378 }
379 for k in am.keys() {
380 if !bm.contains_key(k) {
381 out.push(Change::RemoveExtra {
382 path: path.to_vec(),
383 key: k.clone(),
384 });
385 }
386 }
387}
388
389enum Step {
391 Match,
392 Del(usize),
393 Ins(usize),
394}
395
396#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
399enum Key {
400 Orig(usize),
401 New(usize),
402}
403
404enum Role {
407 Modify(usize),
408 Replace(usize),
409}
410
411fn diff_children(
412 a: &[Node],
413 b: &[Node],
414 path: &mut Vec<usize>,
415 out: &mut Vec<Change>,
416 opts: &DiffOptions,
417) {
418 let mut start = 0;
421 while start < a.len() && start < b.len() && a[start] == b[start] {
422 start += 1;
423 }
424 let mut ea = a.len();
425 let mut eb = b.len();
426 while ea > start && eb > start && a[ea - 1] == b[eb - 1] {
427 ea -= 1;
428 eb -= 1;
429 }
430
431 let am = &a[start..ea];
432 let bm = &b[start..eb];
433 if am.is_empty() && bm.is_empty() {
434 return;
435 }
436
437 let (ida, idb) = intern(am, bm);
440 let steps = lcs_align(&ida, &idb);
441
442 let mut gaps: Vec<(Vec<usize>, Vec<usize>)> = Vec::new();
445 let mut cur_dels: Vec<usize> = Vec::new();
446 let mut cur_inss: Vec<usize> = Vec::new();
447 let mut bm_match_src: HashMap<usize, usize> = HashMap::new(); let (mut ai, mut bj) = (0usize, 0usize);
449 for step in &steps {
450 match step {
451 Step::Match => {
452 gaps.push((std::mem::take(&mut cur_dels), std::mem::take(&mut cur_inss)));
453 bm_match_src.insert(bj, ai);
454 ai += 1;
455 bj += 1;
456 }
457 Step::Del(i) => {
458 cur_dels.push(*i);
459 ai += 1;
460 }
461 Step::Ins(j) => {
462 cur_inss.push(*j);
463 bj += 1;
464 }
465 }
466 }
467 gaps.push((cur_dels, cur_inss));
468
469 let mut dels_by_id: HashMap<u32, std::collections::VecDeque<usize>> = HashMap::new();
473 for (dels, _) in &gaps {
474 for &d in dels {
475 dels_by_id.entry(ida[d]).or_default().push_back(d);
476 }
477 }
478 let mut bm_move_src: HashMap<usize, usize> = HashMap::new(); let mut am_moved: HashSet<usize> = HashSet::new();
480 for (_, inss) in &gaps {
481 for &j in inss {
482 if let Some(d) = dels_by_id.get_mut(&idb[j]).and_then(|q| q.pop_front()) {
483 bm_move_src.insert(j, d);
484 am_moved.insert(d);
485 }
486 }
487 }
488
489 let mut bm_role: HashMap<usize, Role> = HashMap::new();
491 let mut removed_am: Vec<usize> = Vec::new();
492 for (dels, inss) in &gaps {
493 let rem_dels: Vec<usize> = dels
494 .iter()
495 .copied()
496 .filter(|d| !am_moved.contains(d))
497 .collect();
498 let rem_inss: Vec<usize> = inss
499 .iter()
500 .copied()
501 .filter(|j| !bm_move_src.contains_key(j))
502 .collect();
503 let pairs = rem_dels.len().min(rem_inss.len());
504 for k in 0..pairs {
505 let (d, j) = (rem_dels[k], rem_inss[k]);
506 if am[d].node_type == bm[j].node_type {
507 bm_role.insert(j, Role::Modify(d)); } else {
509 bm_role.insert(j, Role::Replace(d)); }
511 }
512 removed_am.extend_from_slice(&rem_dels[pairs..]);
513 }
514
515 let n_orig = am.len() as u32;
519 let mut target: Vec<u32> = Vec::with_capacity(bm.len());
520 for j in 0..bm.len() {
521 let key = if let Some(&i) = bm_match_src.get(&j) {
522 Key::Orig(i)
523 } else if let Some(&d) = bm_move_src.get(&j) {
524 Key::Orig(d)
525 } else {
526 match bm_role.get(&j) {
527 Some(Role::Modify(d) | Role::Replace(d)) => Key::Orig(*d),
528 None => Key::New(j),
529 }
530 };
531 target.push(match key {
532 Key::Orig(i) => i as u32,
533 Key::New(j) => n_orig + j as u32,
534 });
535 }
536 let n_ids = am.len() + bm.len();
537 let mut target_pos = vec![u32::MAX; n_ids];
538 for (t, &k) in target.iter().enumerate() {
539 target_pos[k as usize] = t as u32;
540 }
541 let mut is_moved = vec![false; n_ids];
542 for &d in &am_moved {
543 is_moved[d] = true;
544 }
545
546 for (k, &d) in removed_am.iter().enumerate() {
549 out.push(Change::Remove {
550 path: path.clone(),
551 index: start + d - k,
552 });
553 }
554 let mut is_removed = vec![false; am.len()];
555 for &d in &removed_am {
556 is_removed[d] = true;
557 }
558 let post_remove = || (0..n_orig).filter(|&i| !is_removed[i as usize]);
559
560 let mark = out.len();
563 if !settle_sorted(
564 bm,
565 &target,
566 &target_pos,
567 &is_moved,
568 am_moved.len(),
569 post_remove(),
570 start,
571 path,
572 out,
573 ) {
574 out.truncate(mark);
578 settle_cursor(bm, &target, &is_moved, post_remove(), start, path, out);
579 }
580
581 for (j, target_node) in bm.iter().enumerate() {
584 match bm_role.get(&j) {
585 Some(Role::Modify(d)) => {
586 path.push(start + j);
587 diff_node(&am[*d], target_node, path, out, opts);
588 path.pop();
589 }
590 Some(Role::Replace(_)) => {
591 let mut child = path.clone();
592 child.push(start + j);
593 out.push(Change::Replace {
594 path: child,
595 node: target_node.clone(),
596 });
597 }
598 None => {}
599 }
600 }
601}
602
603#[allow(clippy::too_many_arguments)]
610fn settle_sorted(
611 bm: &[Node],
612 target: &[u32],
613 target_pos: &[u32],
614 is_moved: &[bool],
615 budget: usize,
616 live0: impl Iterator<Item = u32>,
617 start: usize,
618 path: &[usize],
619 out: &mut Vec<Change>,
620) -> bool {
621 let n_orig = is_moved.len() - bm.len();
622 let mut live = LiveList::new(live0, is_moved.len());
623 let mut present = Fenwick::new(target.len());
625 for (t, &k) in target.iter().enumerate() {
626 if (k as usize) < n_orig {
627 present.add(t);
628 }
629 }
630 let mut moves = 0;
631 let mut p = 0;
632 while p < target.len() {
633 let want = target[p];
634 let cur = live.get(p);
635 if cur == Some(want) {
636 p += 1;
637 continue;
638 }
639 if want as usize >= n_orig {
640 out.push(Change::Insert {
641 path: path.to_vec(),
642 index: start + p,
643 node: bm[want as usize - n_orig].clone(),
644 });
645 live.insert(p, want);
646 present.add(p);
647 p += 1;
648 continue;
649 }
650 if moves == budget {
651 return false;
652 }
653 moves += 1;
654 let cur = cur.expect("original node missing from live list");
657 let mover = if is_moved[cur as usize] { cur } else { want };
658 let from = live.index_of(mover);
659 let dest = present.prefix(target_pos[mover as usize] as usize);
662 out.push(Change::Move {
663 path: path.to_vec(),
664 from: start + from,
665 to: start + dest,
666 });
667 let k = live.remove(from);
668 live.insert(dest, k);
669 }
671 true
672}
673
674fn settle_cursor(
680 bm: &[Node],
681 target: &[u32],
682 is_moved: &[bool],
683 live0: impl Iterator<Item = u32>,
684 start: usize,
685 path: &[usize],
686 out: &mut Vec<Change>,
687) {
688 let n_orig = is_moved.len() - bm.len();
689 let mut live = LiveList::new(live0, is_moved.len());
690 let mut cur = 0;
691 for &want in target {
692 if want as usize >= n_orig {
693 out.push(Change::Insert {
694 path: path.to_vec(),
695 index: start + cur,
696 node: bm[want as usize - n_orig].clone(),
697 });
698 live.insert(cur, want);
699 cur += 1;
700 continue;
701 }
702 let at = live.index_of(want);
703 if !is_moved[want as usize] {
704 debug_assert!(at >= cur, "non-moved node behind the cursor");
705 cur = at + 1;
706 continue;
707 }
708 if at == cur {
709 cur += 1;
710 continue;
711 }
712 live.remove(at);
713 if at < cur {
714 cur -= 1;
715 }
716 out.push(Change::Move {
717 path: path.to_vec(),
718 from: start + at,
719 to: start + cur,
720 });
721 live.insert(cur, want);
722 cur += 1;
723 }
724 debug_assert_eq!(
725 live.to_vec(),
726 target,
727 "diff move simulation diverged from target"
728 );
729}
730
731struct LiveList {
735 blocks: Vec<Vec<u32>>,
736 block_of: Vec<u32>,
738 cap: usize,
739}
740
741impl LiveList {
742 fn new(keys: impl Iterator<Item = u32>, n_ids: usize) -> Self {
743 let mut l = LiveList {
744 blocks: vec![keys.collect()],
745 block_of: vec![0; n_ids],
746 cap: 16,
747 };
748 l.rebuild();
749 l
750 }
751
752 fn rebuild(&mut self) {
754 let all = self.to_vec();
755 self.cap = (all.len() as f64).sqrt() as usize + 16;
756 self.blocks = all.chunks(self.cap).map(<[u32]>::to_vec).collect();
757 if self.blocks.is_empty() {
758 self.blocks.push(Vec::new());
759 }
760 for (b, blk) in self.blocks.iter().enumerate() {
761 for &k in blk {
762 self.block_of[k as usize] = b as u32;
763 }
764 }
765 }
766
767 fn to_vec(&self) -> Vec<u32> {
768 self.blocks.concat()
769 }
770
771 fn locate(&self, mut idx: usize) -> (usize, usize) {
774 let last = self.blocks.len() - 1;
775 for (b, blk) in self.blocks.iter().enumerate() {
776 if idx < blk.len() || b == last {
777 return (b, idx);
778 }
779 idx -= blk.len();
780 }
781 unreachable!()
782 }
783
784 fn get(&self, idx: usize) -> Option<u32> {
785 let (b, o) = self.locate(idx);
786 self.blocks[b].get(o).copied()
787 }
788
789 fn index_of(&self, key: u32) -> usize {
790 let b = self.block_of[key as usize] as usize;
791 let before: usize = self.blocks[..b].iter().map(Vec::len).sum();
792 before
793 + self.blocks[b]
794 .iter()
795 .position(|&k| k == key)
796 .expect("key in its block")
797 }
798
799 fn remove(&mut self, idx: usize) -> u32 {
800 let (b, o) = self.locate(idx);
801 self.blocks[b].remove(o)
802 }
803
804 fn insert(&mut self, idx: usize, key: u32) {
805 let (b, o) = self.locate(idx);
806 self.blocks[b].insert(o, key);
807 self.block_of[key as usize] = b as u32;
808 if self.blocks[b].len() > 2 * self.cap {
809 self.rebuild();
810 }
811 }
812}
813
814struct Fenwick(Vec<u32>);
816
817impl Fenwick {
818 fn new(n: usize) -> Self {
819 Fenwick(vec![0; n])
820 }
821
822 fn add(&mut self, mut i: usize) {
825 while i < self.0.len() {
826 self.0[i] += 1;
827 i |= i + 1;
828 }
829 }
830
831 fn prefix(&self, mut i: usize) -> usize {
833 let mut s = 0;
834 while i > 0 {
835 s += self.0[i - 1] as usize;
836 i &= i - 1;
837 }
838 s
839 }
840}
841
842const DP_CELLS: usize = 1 << 16;
847
848const MYERS_MAX_D: usize = 4096;
851const DP_FALLBACK_CELLS: usize = 1 << 24;
852
853fn lcs_align(a: &[u32], b: &[u32]) -> Vec<Step> {
856 let (m, n) = (a.len(), b.len());
857 if m == 0 {
858 return (0..n).map(Step::Ins).collect();
859 }
860 if n == 0 {
861 return (0..m).map(Step::Del).collect();
862 }
863 if m.saturating_mul(n) <= DP_CELLS {
864 return lcs_table(a, b);
865 }
866 if let Some(steps) = myers(a, b, MYERS_MAX_D) {
867 return steps;
868 }
869 if m.saturating_mul(n) <= DP_FALLBACK_CELLS {
870 return lcs_table(a, b);
871 }
872 (0..m).map(Step::Del).chain((0..n).map(Step::Ins)).collect()
875}
876
877fn lcs_table(a: &[u32], b: &[u32]) -> Vec<Step> {
879 let (m, n) = (a.len(), b.len());
880 let w = n + 1;
882 let mut dp = vec![0u32; (m + 1) * w];
883 for i in (0..m).rev() {
884 for j in (0..n).rev() {
885 dp[i * w + j] = if a[i] == b[j] {
886 dp[(i + 1) * w + j + 1] + 1
887 } else {
888 dp[(i + 1) * w + j].max(dp[i * w + j + 1])
889 };
890 }
891 }
892 let mut steps = Vec::with_capacity(m.max(n));
893 let (mut i, mut j) = (0usize, 0usize);
894 while i < m && j < n {
895 if a[i] == b[j] {
896 steps.push(Step::Match);
897 i += 1;
898 j += 1;
899 } else if dp[(i + 1) * w + j] >= dp[i * w + j + 1] {
900 steps.push(Step::Del(i));
901 i += 1;
902 } else {
903 steps.push(Step::Ins(j));
904 j += 1;
905 }
906 }
907 while i < m {
908 steps.push(Step::Del(i));
909 i += 1;
910 }
911 while j < n {
912 steps.push(Step::Ins(j));
913 j += 1;
914 }
915 steps
916}
917
918fn myers(a: &[u32], b: &[u32], max_d: usize) -> Option<Vec<Step>> {
921 if a.len().abs_diff(b.len()) > max_d {
923 return None;
924 }
925 let (n, m) = (a.len() as isize, b.len() as isize);
926 let max_d = max_d.min(a.len() + b.len()) as isize;
927 let off = max_d + 1;
928 let mut v = vec![0isize; (2 * off + 1) as usize];
930 let mut trace: Vec<Vec<isize>> = Vec::new();
932 let mut end_d = None;
933 'outer: for d in 0..=max_d {
934 trace.push(v[(off - d) as usize..=(off + d) as usize].to_vec());
935 let mut k = -d;
936 while k <= d {
937 let down = k == -d || (k != d && v[(off + k - 1) as usize] < v[(off + k + 1) as usize]);
938 let mut x = if down {
939 v[(off + k + 1) as usize]
940 } else {
941 v[(off + k - 1) as usize] + 1
942 };
943 let mut y = x - k;
944 while x < n && y < m && a[x as usize] == b[y as usize] {
945 x += 1;
946 y += 1;
947 }
948 v[(off + k) as usize] = x;
949 if x >= n && y >= m {
950 end_d = Some(d);
951 break 'outer;
952 }
953 k += 2;
954 }
955 }
956 end_d?;
957 let mut steps = Vec::with_capacity((n + m) as usize);
959 let (mut x, mut y) = (n, m);
960 for d in (0..trace.len() as isize).rev() {
961 if d == 0 {
962 while x > 0 && y > 0 {
963 steps.push(Step::Match);
964 x -= 1;
965 y -= 1;
966 }
967 break;
968 }
969 let vd = &trace[d as usize];
970 let get = |k: isize| vd[(k + d) as usize];
971 let k = x - y;
972 let prev_k = if k == -d || (k != d && get(k - 1) < get(k + 1)) {
973 k + 1
974 } else {
975 k - 1
976 };
977 let prev_x = get(prev_k);
978 let prev_y = prev_x - prev_k;
979 while x > prev_x && y > prev_y {
980 steps.push(Step::Match);
981 x -= 1;
982 y -= 1;
983 }
984 if x == prev_x {
985 steps.push(Step::Ins((y - 1) as usize));
986 } else {
987 steps.push(Step::Del((x - 1) as usize));
988 }
989 x = prev_x;
990 y = prev_y;
991 }
992 steps.reverse();
993 Some(steps)
994}
995
996fn intern(a: &[Node], b: &[Node]) -> (Vec<u32>, Vec<u32>) {
1001 let mut buckets: HashMap<u64, Vec<(u32, &Node)>> = HashMap::with_capacity(a.len() + b.len());
1002 let mut next = 0u32;
1003 let mut out_a = Vec::with_capacity(a.len());
1004 let mut out_b = Vec::with_capacity(b.len());
1005 for (side, nodes) in [(0, a), (1, b)] {
1006 for n in nodes {
1007 let bucket = buckets.entry(node_hash(n)).or_default();
1008 let found = bucket.iter().find(|(_, rep)| *rep == n).map(|(i, _)| *i);
1009 let i = found.unwrap_or_else(|| {
1010 let i = next;
1011 next += 1;
1012 bucket.push((i, n));
1013 i
1014 });
1015 if side == 0 {
1016 out_a.push(i);
1017 } else {
1018 out_b.push(i);
1019 }
1020 }
1021 }
1022 (out_a, out_b)
1023}
1024
1025fn node_hash(n: &Node) -> u64 {
1028 let mut h = Fx::default();
1029 hash_node(n, &mut h);
1030 h.0
1031}
1032
1033#[derive(Default)]
1034struct Fx(u64);
1035
1036impl Fx {
1037 #[inline]
1038 fn add(&mut self, x: u64) {
1039 self.0 = (self.0.rotate_left(5) ^ x).wrapping_mul(0x51_7c_c1_b7_27_22_0a_95);
1040 }
1041 #[inline]
1042 fn bytes(&mut self, s: &[u8]) {
1043 let (chunks, rest) = s.as_chunks::<8>();
1044 for c in chunks {
1045 self.add(u64::from_le_bytes(*c));
1046 }
1047 let mut tail = [0u8; 8];
1048 tail[..rest.len()].copy_from_slice(rest);
1049 self.add(u64::from_le_bytes(tail) ^ ((s.len() as u64) << 56));
1050 }
1051 #[inline]
1052 fn opt_str(&mut self, s: Option<&str>) {
1053 match s {
1054 None => self.add(0x9e37),
1055 Some(s) => self.bytes(s.as_bytes()),
1056 }
1057 }
1058}
1059
1060fn hash_node(n: &Node, h: &mut Fx) {
1061 h.opt_str(n.node_type.as_deref());
1062 hash_opt_map(n.attrs.as_ref(), h);
1063 match &n.content {
1064 None => h.add(1),
1065 Some(c) => {
1066 h.add(2 ^ ((c.len() as u64) << 8));
1067 for child in c {
1068 hash_node(child, h);
1069 }
1070 }
1071 }
1072 match &n.marks {
1073 None => h.add(3),
1074 Some(ms) => {
1075 h.add(4 ^ ((ms.len() as u64) << 8));
1076 for m in ms {
1077 h.bytes(m.mark_type.as_bytes());
1078 hash_opt_map(m.attrs.as_ref(), h);
1079 hash_map(&m.extra, h);
1080 }
1081 }
1082 }
1083 h.opt_str(n.text.as_deref());
1084 hash_map(&n.extra, h);
1085}
1086
1087fn hash_opt_map(m: Option<&Map<String, Value>>, h: &mut Fx) {
1088 match m {
1089 None => h.add(5),
1090 Some(m) => hash_map(m, h),
1091 }
1092}
1093
1094fn hash_map(m: &Map<String, Value>, h: &mut Fx) {
1096 let mut sum = 0u64;
1097 for (k, v) in m {
1098 let mut e = Fx::default();
1099 e.bytes(k.as_bytes());
1100 hash_value(v, &mut e);
1101 sum = sum.wrapping_add(e.0);
1102 }
1103 h.add(6 ^ ((m.len() as u64) << 8));
1104 h.add(sum);
1105}
1106
1107fn hash_value(v: &Value, h: &mut Fx) {
1108 match v {
1109 Value::Null => h.add(10),
1110 Value::Bool(b) => h.add(11 + *b as u64),
1111 Value::Number(n) => {
1112 if let Some(u) = n.as_u64() {
1113 h.add(13);
1114 h.add(u);
1115 } else if let Some(i) = n.as_i64() {
1116 h.add(14);
1117 h.add(i as u64);
1118 } else {
1119 let f = n.as_f64().unwrap_or(0.0);
1121 h.add(15);
1122 h.add(if f == 0.0 { 0 } else { f.to_bits() });
1123 }
1124 }
1125 Value::String(s) => {
1126 h.add(16);
1127 h.bytes(s.as_bytes());
1128 }
1129 Value::Array(a) => {
1130 h.add(17 ^ ((a.len() as u64) << 8));
1131 for x in a {
1132 hash_value(x, h);
1133 }
1134 }
1135 Value::Object(m) => {
1136 h.add(18);
1137 hash_map(m, h);
1138 }
1139 }
1140}
1141
1142fn node_at_mut<'a>(
1145 root: &'a mut Node,
1146 path: &[usize],
1147) -> std::result::Result<&'a mut Node, ApplyError> {
1148 root.node_at_mut(path).ok_or_else(|| ApplyError {
1149 path: path.to_vec(),
1150 })
1151}
1152
1153fn apply_one(root: &mut Node, change: &Change) -> std::result::Result<(), ApplyError> {
1154 match change {
1155 Change::SetAttr { path, key, value } => {
1156 node_at_mut(root, path)?.set_attr(key.clone(), value.clone());
1157 }
1158 Change::RemoveAttr { path, key } => {
1159 node_at_mut(root, path)?.remove_attr(key);
1160 }
1161 Change::SetText { path, text } => {
1162 node_at_mut(root, path)?.text = text.clone();
1163 }
1164 Change::SpliceText {
1165 path,
1166 from,
1167 len_del,
1168 insert,
1169 } => {
1170 let node = node_at_mut(root, path)?;
1171 let (start, end) = {
1176 let cur = node.text.as_deref().unwrap_or("");
1177 let scalars = cur.chars().count();
1178 let end_scalar = match from.checked_add(*len_del) {
1179 Some(e) if *from <= scalars && e <= scalars => e,
1180 _ => return Err(ApplyError { path: path.clone() }),
1181 };
1182 let start = cur.char_indices().nth(*from).map_or(cur.len(), |(b, _)| b);
1183 let end = cur
1184 .char_indices()
1185 .nth(end_scalar)
1186 .map_or(cur.len(), |(b, _)| b);
1187 (start, end)
1188 };
1189 if start != end || !insert.is_empty() {
1193 node.text
1194 .get_or_insert_with(String::new)
1195 .replace_range(start..end, insert);
1196 }
1197 }
1198 Change::SetMarks { path, marks } => {
1199 node_at_mut(root, path)?.marks = marks.clone();
1200 }
1201 Change::SetExtra { path, key, value } => {
1202 node_at_mut(root, path)?
1203 .extra
1204 .insert(key.clone(), value.clone());
1205 }
1206 Change::RemoveExtra { path, key } => {
1207 node_at_mut(root, path)?.extra.remove(key);
1208 }
1209 Change::Insert { path, index, node } => {
1210 let parent = node_at_mut(root, path)?;
1211 if *index > parent.child_count() {
1212 let mut p = path.clone();
1213 p.push(*index);
1214 return Err(ApplyError { path: p });
1215 }
1216 parent.insert_child(*index, node.clone());
1217 }
1218 Change::Remove { path, index } => {
1219 if node_at_mut(root, path)?.remove_child(*index).is_none() {
1220 let mut p = path.clone();
1221 p.push(*index);
1222 return Err(ApplyError { path: p });
1223 }
1224 }
1225 Change::Replace { path, node } => {
1226 if path.is_empty() {
1227 *root = node.clone();
1228 } else {
1229 let (parent_path, last) = path.split_at(path.len() - 1);
1230 let parent = node_at_mut(root, parent_path)?;
1231 if parent.replace_child(last[0], node.clone()).is_none() {
1232 return Err(ApplyError { path: path.clone() });
1233 }
1234 }
1235 }
1236 Change::Move { path, from, to } => {
1237 let parent = node_at_mut(root, path)?;
1238 let len = parent.child_count();
1239 if *from >= len || *to >= len {
1242 let mut p = path.clone();
1243 p.push(if *from >= len { *from } else { *to });
1244 return Err(ApplyError { path: p });
1245 }
1246 let node = parent.remove_child(*from).expect("from bounds-checked");
1247 parent.insert_child(*to, node);
1248 }
1249 }
1250 Ok(())
1251}