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_ref().map(Map::is_empty),
269 b.attrs.as_ref().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_ref(), b.attrs.as_ref(), 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, &b.extra, 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 am: &Map<String, Value>,
375 bm: &Map<String, Value>,
376 path: &mut [usize],
377 out: &mut Vec<Change>,
378) {
379 for (k, v) in bm {
380 if am.get(k) != Some(v) {
381 out.push(Change::SetExtra {
382 path: path.to_vec(),
383 key: k.clone(),
384 value: v.clone(),
385 });
386 }
387 }
388 for k in am.keys() {
389 if !bm.contains_key(k) {
390 out.push(Change::RemoveExtra {
391 path: path.to_vec(),
392 key: k.clone(),
393 });
394 }
395 }
396}
397
398enum Step {
400 Match,
401 Del(usize),
402 Ins(usize),
403}
404
405#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
408enum Key {
409 Orig(usize),
410 New(usize),
411}
412
413enum Role {
416 Modify(usize),
417 Replace(usize),
418}
419
420fn diff_children(
421 a: &[Node],
422 b: &[Node],
423 path: &mut Vec<usize>,
424 out: &mut Vec<Change>,
425 opts: &DiffOptions,
426) {
427 let mut start = 0;
430 while start < a.len() && start < b.len() && a[start] == b[start] {
431 start += 1;
432 }
433 let mut ea = a.len();
434 let mut eb = b.len();
435 while ea > start && eb > start && a[ea - 1] == b[eb - 1] {
436 ea -= 1;
437 eb -= 1;
438 }
439
440 let am = &a[start..ea];
441 let bm = &b[start..eb];
442 if am.is_empty() && bm.is_empty() {
443 return;
444 }
445
446 let (ida, idb) = intern(am, bm);
449 let steps = lcs_align(&ida, &idb);
450
451 let mut gaps: Vec<(Vec<usize>, Vec<usize>)> = Vec::new();
454 let mut cur_dels: Vec<usize> = Vec::new();
455 let mut cur_inss: Vec<usize> = Vec::new();
456 let mut bm_match_src: HashMap<usize, usize> = HashMap::new(); let (mut ai, mut bj) = (0usize, 0usize);
458 for step in &steps {
459 match step {
460 Step::Match => {
461 gaps.push((std::mem::take(&mut cur_dels), std::mem::take(&mut cur_inss)));
462 bm_match_src.insert(bj, ai);
463 ai += 1;
464 bj += 1;
465 }
466 Step::Del(i) => {
467 cur_dels.push(*i);
468 ai += 1;
469 }
470 Step::Ins(j) => {
471 cur_inss.push(*j);
472 bj += 1;
473 }
474 }
475 }
476 gaps.push((cur_dels, cur_inss));
477
478 let mut dels_by_id: HashMap<u32, std::collections::VecDeque<usize>> = HashMap::new();
482 for (dels, _) in &gaps {
483 for &d in dels {
484 dels_by_id.entry(ida[d]).or_default().push_back(d);
485 }
486 }
487 let mut bm_move_src: HashMap<usize, usize> = HashMap::new(); let mut am_moved: HashSet<usize> = HashSet::new();
489 for (_, inss) in &gaps {
490 for &j in inss {
491 if let Some(d) = dels_by_id.get_mut(&idb[j]).and_then(|q| q.pop_front()) {
492 bm_move_src.insert(j, d);
493 am_moved.insert(d);
494 }
495 }
496 }
497
498 let mut bm_role: HashMap<usize, Role> = HashMap::new();
500 let mut removed_am: Vec<usize> = Vec::new();
501 for (dels, inss) in &gaps {
502 let rem_dels: Vec<usize> = dels
503 .iter()
504 .copied()
505 .filter(|d| !am_moved.contains(d))
506 .collect();
507 let rem_inss: Vec<usize> = inss
508 .iter()
509 .copied()
510 .filter(|j| !bm_move_src.contains_key(j))
511 .collect();
512 let pairs = rem_dels.len().min(rem_inss.len());
513 for k in 0..pairs {
514 let (d, j) = (rem_dels[k], rem_inss[k]);
515 if am[d].node_type == bm[j].node_type {
516 bm_role.insert(j, Role::Modify(d)); } else {
518 bm_role.insert(j, Role::Replace(d)); }
520 }
521 removed_am.extend_from_slice(&rem_dels[pairs..]);
522 }
523
524 let n_orig = am.len() as u32;
528 let mut target: Vec<u32> = Vec::with_capacity(bm.len());
529 for j in 0..bm.len() {
530 let key = if let Some(&i) = bm_match_src.get(&j) {
531 Key::Orig(i)
532 } else if let Some(&d) = bm_move_src.get(&j) {
533 Key::Orig(d)
534 } else {
535 match bm_role.get(&j) {
536 Some(Role::Modify(d) | Role::Replace(d)) => Key::Orig(*d),
537 None => Key::New(j),
538 }
539 };
540 target.push(match key {
541 Key::Orig(i) => i as u32,
542 Key::New(j) => n_orig + j as u32,
543 });
544 }
545 let n_ids = am.len() + bm.len();
546 let mut target_pos = vec![u32::MAX; n_ids];
547 for (t, &k) in target.iter().enumerate() {
548 target_pos[k as usize] = t as u32;
549 }
550 let mut is_moved = vec![false; n_ids];
551 for &d in &am_moved {
552 is_moved[d] = true;
553 }
554
555 for (k, &d) in removed_am.iter().enumerate() {
558 out.push(Change::Remove {
559 path: path.clone(),
560 index: start + d - k,
561 });
562 }
563 let mut is_removed = vec![false; am.len()];
564 for &d in &removed_am {
565 is_removed[d] = true;
566 }
567 let post_remove = || (0..n_orig).filter(|&i| !is_removed[i as usize]);
568
569 let mark = out.len();
572 if !settle_sorted(
573 bm,
574 &target,
575 &target_pos,
576 &is_moved,
577 am_moved.len(),
578 post_remove(),
579 start,
580 path,
581 out,
582 ) {
583 out.truncate(mark);
587 settle_cursor(bm, &target, &is_moved, post_remove(), start, path, out);
588 }
589
590 for (j, target_node) in bm.iter().enumerate() {
593 match bm_role.get(&j) {
594 Some(Role::Modify(d)) => {
595 path.push(start + j);
596 diff_node(&am[*d], target_node, path, out, opts);
597 path.pop();
598 }
599 Some(Role::Replace(_)) => {
600 let mut child = path.clone();
601 child.push(start + j);
602 out.push(Change::Replace {
603 path: child,
604 node: target_node.clone(),
605 });
606 }
607 None => {}
608 }
609 }
610}
611
612#[allow(clippy::too_many_arguments)]
619fn settle_sorted(
620 bm: &[Node],
621 target: &[u32],
622 target_pos: &[u32],
623 is_moved: &[bool],
624 budget: usize,
625 live0: impl Iterator<Item = u32>,
626 start: usize,
627 path: &[usize],
628 out: &mut Vec<Change>,
629) -> bool {
630 let n_orig = is_moved.len() - bm.len();
631 let mut live = LiveList::new(live0, is_moved.len());
632 let mut present = Fenwick::new(target.len());
634 for (t, &k) in target.iter().enumerate() {
635 if (k as usize) < n_orig {
636 present.add(t);
637 }
638 }
639 let mut moves = 0;
640 let mut p = 0;
641 while p < target.len() {
642 let want = target[p];
643 let cur = live.get(p);
644 if cur == Some(want) {
645 p += 1;
646 continue;
647 }
648 if want as usize >= n_orig {
649 out.push(Change::Insert {
650 path: path.to_vec(),
651 index: start + p,
652 node: bm[want as usize - n_orig].clone(),
653 });
654 live.insert(p, want);
655 present.add(p);
656 p += 1;
657 continue;
658 }
659 if moves == budget {
660 return false;
661 }
662 moves += 1;
663 let cur = cur.expect("original node missing from live list");
666 let mover = if is_moved[cur as usize] { cur } else { want };
667 let from = live.index_of(mover);
668 let dest = present.prefix(target_pos[mover as usize] as usize);
671 out.push(Change::Move {
672 path: path.to_vec(),
673 from: start + from,
674 to: start + dest,
675 });
676 let k = live.remove(from);
677 live.insert(dest, k);
678 }
680 true
681}
682
683fn settle_cursor(
689 bm: &[Node],
690 target: &[u32],
691 is_moved: &[bool],
692 live0: impl Iterator<Item = u32>,
693 start: usize,
694 path: &[usize],
695 out: &mut Vec<Change>,
696) {
697 let n_orig = is_moved.len() - bm.len();
698 let mut live = LiveList::new(live0, is_moved.len());
699 let mut cur = 0;
700 for &want in target {
701 if want as usize >= n_orig {
702 out.push(Change::Insert {
703 path: path.to_vec(),
704 index: start + cur,
705 node: bm[want as usize - n_orig].clone(),
706 });
707 live.insert(cur, want);
708 cur += 1;
709 continue;
710 }
711 let at = live.index_of(want);
712 if !is_moved[want as usize] {
713 debug_assert!(at >= cur, "non-moved node behind the cursor");
714 cur = at + 1;
715 continue;
716 }
717 if at == cur {
718 cur += 1;
719 continue;
720 }
721 live.remove(at);
722 if at < cur {
723 cur -= 1;
724 }
725 out.push(Change::Move {
726 path: path.to_vec(),
727 from: start + at,
728 to: start + cur,
729 });
730 live.insert(cur, want);
731 cur += 1;
732 }
733 debug_assert_eq!(
734 live.to_vec(),
735 target,
736 "diff move simulation diverged from target"
737 );
738}
739
740struct LiveList {
744 blocks: Vec<Vec<u32>>,
745 block_of: Vec<u32>,
747 cap: usize,
748}
749
750impl LiveList {
751 fn new(keys: impl Iterator<Item = u32>, n_ids: usize) -> Self {
752 let mut l = LiveList {
753 blocks: vec![keys.collect()],
754 block_of: vec![0; n_ids],
755 cap: 16,
756 };
757 l.rebuild();
758 l
759 }
760
761 fn rebuild(&mut self) {
763 let all = self.to_vec();
764 self.cap = (all.len() as f64).sqrt() as usize + 16;
765 self.blocks = all.chunks(self.cap).map(<[u32]>::to_vec).collect();
766 if self.blocks.is_empty() {
767 self.blocks.push(Vec::new());
768 }
769 for (b, blk) in self.blocks.iter().enumerate() {
770 for &k in blk {
771 self.block_of[k as usize] = b as u32;
772 }
773 }
774 }
775
776 fn to_vec(&self) -> Vec<u32> {
777 self.blocks.concat()
778 }
779
780 fn locate(&self, mut idx: usize) -> (usize, usize) {
783 let last = self.blocks.len() - 1;
784 for (b, blk) in self.blocks.iter().enumerate() {
785 if idx < blk.len() || b == last {
786 return (b, idx);
787 }
788 idx -= blk.len();
789 }
790 unreachable!()
791 }
792
793 fn get(&self, idx: usize) -> Option<u32> {
794 let (b, o) = self.locate(idx);
795 self.blocks[b].get(o).copied()
796 }
797
798 fn index_of(&self, key: u32) -> usize {
799 let b = self.block_of[key as usize] as usize;
800 let before: usize = self.blocks[..b].iter().map(Vec::len).sum();
801 before
802 + self.blocks[b]
803 .iter()
804 .position(|&k| k == key)
805 .expect("key in its block")
806 }
807
808 fn remove(&mut self, idx: usize) -> u32 {
809 let (b, o) = self.locate(idx);
810 self.blocks[b].remove(o)
811 }
812
813 fn insert(&mut self, idx: usize, key: u32) {
814 let (b, o) = self.locate(idx);
815 self.blocks[b].insert(o, key);
816 self.block_of[key as usize] = b as u32;
817 if self.blocks[b].len() > 2 * self.cap {
818 self.rebuild();
819 }
820 }
821}
822
823struct Fenwick(Vec<u32>);
825
826impl Fenwick {
827 fn new(n: usize) -> Self {
828 Fenwick(vec![0; n])
829 }
830
831 fn add(&mut self, mut i: usize) {
834 while i < self.0.len() {
835 self.0[i] += 1;
836 i |= i + 1;
837 }
838 }
839
840 fn prefix(&self, mut i: usize) -> usize {
842 let mut s = 0;
843 while i > 0 {
844 s += self.0[i - 1] as usize;
845 i &= i - 1;
846 }
847 s
848 }
849}
850
851const DP_CELLS: usize = 1 << 16;
856
857const MYERS_MAX_D: usize = 4096;
860const DP_FALLBACK_CELLS: usize = 1 << 24;
861
862fn lcs_align(a: &[u32], b: &[u32]) -> Vec<Step> {
865 let (m, n) = (a.len(), b.len());
866 if m == 0 {
867 return (0..n).map(Step::Ins).collect();
868 }
869 if n == 0 {
870 return (0..m).map(Step::Del).collect();
871 }
872 if m.saturating_mul(n) <= DP_CELLS {
873 return lcs_table(a, b);
874 }
875 if let Some(steps) = myers(a, b, MYERS_MAX_D) {
876 return steps;
877 }
878 if m.saturating_mul(n) <= DP_FALLBACK_CELLS {
879 return lcs_table(a, b);
880 }
881 (0..m).map(Step::Del).chain((0..n).map(Step::Ins)).collect()
884}
885
886fn lcs_table(a: &[u32], b: &[u32]) -> Vec<Step> {
888 let (m, n) = (a.len(), b.len());
889 let w = n + 1;
891 let mut dp = vec![0u32; (m + 1) * w];
892 for i in (0..m).rev() {
893 for j in (0..n).rev() {
894 dp[i * w + j] = if a[i] == b[j] {
895 dp[(i + 1) * w + j + 1] + 1
896 } else {
897 dp[(i + 1) * w + j].max(dp[i * w + j + 1])
898 };
899 }
900 }
901 let mut steps = Vec::with_capacity(m.max(n));
902 let (mut i, mut j) = (0usize, 0usize);
903 while i < m && j < n {
904 if a[i] == b[j] {
905 steps.push(Step::Match);
906 i += 1;
907 j += 1;
908 } else if dp[(i + 1) * w + j] >= dp[i * w + j + 1] {
909 steps.push(Step::Del(i));
910 i += 1;
911 } else {
912 steps.push(Step::Ins(j));
913 j += 1;
914 }
915 }
916 while i < m {
917 steps.push(Step::Del(i));
918 i += 1;
919 }
920 while j < n {
921 steps.push(Step::Ins(j));
922 j += 1;
923 }
924 steps
925}
926
927fn myers(a: &[u32], b: &[u32], max_d: usize) -> Option<Vec<Step>> {
930 if a.len().abs_diff(b.len()) > max_d {
932 return None;
933 }
934 let (n, m) = (a.len() as isize, b.len() as isize);
935 let max_d = max_d.min(a.len() + b.len()) as isize;
936 let off = max_d + 1;
937 let mut v = vec![0isize; (2 * off + 1) as usize];
939 let mut trace: Vec<Vec<isize>> = Vec::new();
941 let mut end_d = None;
942 'outer: for d in 0..=max_d {
943 trace.push(v[(off - d) as usize..=(off + d) as usize].to_vec());
944 let mut k = -d;
945 while k <= d {
946 let down = k == -d || (k != d && v[(off + k - 1) as usize] < v[(off + k + 1) as usize]);
947 let mut x = if down {
948 v[(off + k + 1) as usize]
949 } else {
950 v[(off + k - 1) as usize] + 1
951 };
952 let mut y = x - k;
953 while x < n && y < m && a[x as usize] == b[y as usize] {
954 x += 1;
955 y += 1;
956 }
957 v[(off + k) as usize] = x;
958 if x >= n && y >= m {
959 end_d = Some(d);
960 break 'outer;
961 }
962 k += 2;
963 }
964 }
965 end_d?;
966 let mut steps = Vec::with_capacity((n + m) as usize);
968 let (mut x, mut y) = (n, m);
969 for d in (0..trace.len() as isize).rev() {
970 if d == 0 {
971 while x > 0 && y > 0 {
972 steps.push(Step::Match);
973 x -= 1;
974 y -= 1;
975 }
976 break;
977 }
978 let vd = &trace[d as usize];
979 let get = |k: isize| vd[(k + d) as usize];
980 let k = x - y;
981 let prev_k = if k == -d || (k != d && get(k - 1) < get(k + 1)) {
982 k + 1
983 } else {
984 k - 1
985 };
986 let prev_x = get(prev_k);
987 let prev_y = prev_x - prev_k;
988 while x > prev_x && y > prev_y {
989 steps.push(Step::Match);
990 x -= 1;
991 y -= 1;
992 }
993 if x == prev_x {
994 steps.push(Step::Ins((y - 1) as usize));
995 } else {
996 steps.push(Step::Del((x - 1) as usize));
997 }
998 x = prev_x;
999 y = prev_y;
1000 }
1001 steps.reverse();
1002 Some(steps)
1003}
1004
1005fn intern(a: &[Node], b: &[Node]) -> (Vec<u32>, Vec<u32>) {
1010 let mut buckets: HashMap<u64, Vec<(u32, &Node)>> = HashMap::with_capacity(a.len() + b.len());
1011 let mut next = 0u32;
1012 let mut out_a = Vec::with_capacity(a.len());
1013 let mut out_b = Vec::with_capacity(b.len());
1014 for (side, nodes) in [(0, a), (1, b)] {
1015 for n in nodes {
1016 let bucket = buckets.entry(node_hash(n)).or_default();
1017 let found = bucket.iter().find(|(_, rep)| *rep == n).map(|(i, _)| *i);
1018 let i = found.unwrap_or_else(|| {
1019 let i = next;
1020 next += 1;
1021 bucket.push((i, n));
1022 i
1023 });
1024 if side == 0 {
1025 out_a.push(i);
1026 } else {
1027 out_b.push(i);
1028 }
1029 }
1030 }
1031 (out_a, out_b)
1032}
1033
1034fn node_hash(n: &Node) -> u64 {
1037 let mut h = Fx::default();
1038 hash_node(n, &mut h);
1039 h.0
1040}
1041
1042#[derive(Default)]
1043struct Fx(u64);
1044
1045impl Fx {
1046 #[inline]
1047 fn add(&mut self, x: u64) {
1048 self.0 = (self.0.rotate_left(5) ^ x).wrapping_mul(0x51_7c_c1_b7_27_22_0a_95);
1049 }
1050 #[inline]
1051 fn bytes(&mut self, s: &[u8]) {
1052 let (chunks, rest) = s.as_chunks::<8>();
1053 for c in chunks {
1054 self.add(u64::from_le_bytes(*c));
1055 }
1056 let mut tail = [0u8; 8];
1057 tail[..rest.len()].copy_from_slice(rest);
1058 self.add(u64::from_le_bytes(tail) ^ ((s.len() as u64) << 56));
1059 }
1060 #[inline]
1061 fn opt_str(&mut self, s: Option<&str>) {
1062 match s {
1063 None => self.add(0x9e37),
1064 Some(s) => self.bytes(s.as_bytes()),
1065 }
1066 }
1067}
1068
1069fn hash_node(n: &Node, h: &mut Fx) {
1070 h.opt_str(n.node_type.as_deref());
1071 hash_opt_map(n.attrs.as_ref(), h);
1072 match &n.content {
1073 None => h.add(1),
1074 Some(c) => {
1075 h.add(2 ^ ((c.len() as u64) << 8));
1076 for child in c {
1077 hash_node(child, h);
1078 }
1079 }
1080 }
1081 match &n.marks {
1082 None => h.add(3),
1083 Some(ms) => {
1084 h.add(4 ^ ((ms.len() as u64) << 8));
1085 for m in ms {
1086 h.bytes(m.mark_type.as_bytes());
1087 hash_opt_map(m.attrs.as_ref(), h);
1088 hash_map(&m.extra, h);
1089 }
1090 }
1091 }
1092 h.opt_str(n.text.as_deref());
1093 hash_map(&n.extra, h);
1094}
1095
1096fn hash_opt_map(m: Option<&Map<String, Value>>, h: &mut Fx) {
1097 match m {
1098 None => h.add(5),
1099 Some(m) => hash_map(m, h),
1100 }
1101}
1102
1103fn hash_map(m: &Map<String, Value>, h: &mut Fx) {
1105 let mut sum = 0u64;
1106 for (k, v) in m {
1107 let mut e = Fx::default();
1108 e.bytes(k.as_bytes());
1109 hash_value(v, &mut e);
1110 sum = sum.wrapping_add(e.0);
1111 }
1112 h.add(6 ^ ((m.len() as u64) << 8));
1113 h.add(sum);
1114}
1115
1116fn hash_value(v: &Value, h: &mut Fx) {
1117 match v {
1118 Value::Null => h.add(10),
1119 Value::Bool(b) => h.add(11 + *b as u64),
1120 Value::Number(n) => {
1121 if let Some(u) = n.as_u64() {
1122 h.add(13);
1123 h.add(u);
1124 } else if let Some(i) = n.as_i64() {
1125 h.add(14);
1126 h.add(i as u64);
1127 } else {
1128 let f = n.as_f64().unwrap_or(0.0);
1130 h.add(15);
1131 h.add(if f == 0.0 { 0 } else { f.to_bits() });
1132 }
1133 }
1134 Value::String(s) => {
1135 h.add(16);
1136 h.bytes(s.as_bytes());
1137 }
1138 Value::Array(a) => {
1139 h.add(17 ^ ((a.len() as u64) << 8));
1140 for x in a {
1141 hash_value(x, h);
1142 }
1143 }
1144 Value::Object(m) => {
1145 h.add(18);
1146 hash_map(m, h);
1147 }
1148 }
1149}
1150
1151fn node_at_mut<'a>(
1154 root: &'a mut Node,
1155 path: &[usize],
1156) -> std::result::Result<&'a mut Node, ApplyError> {
1157 root.node_at_mut(path).ok_or_else(|| ApplyError {
1158 path: path.to_vec(),
1159 })
1160}
1161
1162fn apply_one(root: &mut Node, change: &Change) -> std::result::Result<(), ApplyError> {
1163 match change {
1164 Change::SetAttr { path, key, value } => {
1165 node_at_mut(root, path)?.set_attr(key.clone(), value.clone());
1166 }
1167 Change::RemoveAttr { path, key } => {
1168 node_at_mut(root, path)?.remove_attr(key);
1169 }
1170 Change::SetText { path, text } => {
1171 node_at_mut(root, path)?.text = text.clone();
1172 }
1173 Change::SpliceText {
1174 path,
1175 from,
1176 len_del,
1177 insert,
1178 } => {
1179 let node = node_at_mut(root, path)?;
1180 let (start, end) = {
1185 let cur = node.text.as_deref().unwrap_or("");
1186 let scalars = cur.chars().count();
1187 let end_scalar = match from.checked_add(*len_del) {
1188 Some(e) if *from <= scalars && e <= scalars => e,
1189 _ => return Err(ApplyError { path: path.clone() }),
1190 };
1191 let start = cur.char_indices().nth(*from).map_or(cur.len(), |(b, _)| b);
1192 let end = cur
1193 .char_indices()
1194 .nth(end_scalar)
1195 .map_or(cur.len(), |(b, _)| b);
1196 (start, end)
1197 };
1198 if start != end || !insert.is_empty() {
1202 node.text
1203 .get_or_insert_with(String::new)
1204 .replace_range(start..end, insert);
1205 }
1206 }
1207 Change::SetMarks { path, marks } => {
1208 node_at_mut(root, path)?.marks = marks.clone();
1209 }
1210 Change::SetExtra { path, key, value } => {
1211 node_at_mut(root, path)?
1212 .extra
1213 .insert(key.clone(), value.clone());
1214 }
1215 Change::RemoveExtra { path, key } => {
1216 node_at_mut(root, path)?.extra.remove(key);
1217 }
1218 Change::Insert { path, index, node } => {
1219 let parent = node_at_mut(root, path)?;
1220 if *index > parent.child_count() {
1221 let mut p = path.clone();
1222 p.push(*index);
1223 return Err(ApplyError { path: p });
1224 }
1225 parent.insert_child(*index, node.clone());
1226 }
1227 Change::Remove { path, index } => {
1228 if node_at_mut(root, path)?.remove_child(*index).is_none() {
1229 let mut p = path.clone();
1230 p.push(*index);
1231 return Err(ApplyError { path: p });
1232 }
1233 }
1234 Change::Replace { path, node } => {
1235 if path.is_empty() {
1236 *root = node.clone();
1237 } else {
1238 let (parent_path, last) = path.split_at(path.len() - 1);
1239 let parent = node_at_mut(root, parent_path)?;
1240 if parent.replace_child(last[0], node.clone()).is_none() {
1241 return Err(ApplyError { path: path.clone() });
1242 }
1243 }
1244 }
1245 Change::Move { path, from, to } => {
1246 let parent = node_at_mut(root, path)?;
1247 let len = parent.child_count();
1248 if *from >= len || *to >= len {
1251 let mut p = path.clone();
1252 p.push(if *from >= len { *from } else { *to });
1253 return Err(ApplyError { path: p });
1254 }
1255 let node = parent.remove_child(*from).expect("from bounds-checked");
1256 parent.insert_child(*to, node);
1257 }
1258 }
1259 Ok(())
1260}