braid_core/antimatter/
sequence_crdt.rs1use serde::{Deserialize, Serialize};
2use std::collections::HashSet;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct SequenceNode {
6 pub version: Option<String>,
7 pub elems: SequenceElems,
8 pub next: Vec<SequenceNode>,
9 pub deleted_by: HashSet<String>,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub enum SequenceElems {
14 String(String),
15}
16
17impl SequenceNode {
18 pub fn text(version: &str, text: &str) -> Self {
19 Self {
20 version: Some(version.to_string()),
21 elems: SequenceElems::String(text.to_string()),
22 next: Vec::new(),
23 deleted_by: HashSet::new(),
24 }
25 }
26}
27
28pub fn content<F>(node: &SequenceNode, is_visible: F) -> String
29where
30 F: Fn(&str) -> bool + Copy,
31{
32 let mut result = String::new();
33 let visible = node.version.as_ref().map(|v| is_visible(v)).unwrap_or(true)
34 && node.deleted_by.iter().all(|v| !is_visible(v));
35
36 if visible {
37 match &node.elems {
38 SequenceElems::String(s) => result.push_str(s),
39 }
40 }
41
42 for child in &node.next {
43 result.push_str(&content(child, is_visible));
44 }
45
46 result
47}
48
49pub fn length<F>(node: &SequenceNode, is_visible: F) -> usize
50where
51 F: Fn(&str) -> bool + Copy,
52{
53 let visible = node.version.as_ref().map(|v| is_visible(v)).unwrap_or(true)
54 && node.deleted_by.iter().all(|v| !is_visible(v));
55
56 let mut len = if visible {
57 match &node.elems {
58 SequenceElems::String(s) => s.len(),
59 }
60 } else {
61 0
62 };
63
64 for child in &node.next {
65 len += length(child, is_visible);
66 }
67
68 len
69}
70
71pub fn get<F>(node: &SequenceNode, mut pos: usize, is_visible: F) -> Option<char>
72where
73 F: Fn(&str) -> bool + Copy,
74{
75 let visible = node.version.as_ref().map(|v| is_visible(v)).unwrap_or(true)
76 && node.deleted_by.iter().all(|v| !is_visible(v));
77
78 if visible {
79 match &node.elems {
80 SequenceElems::String(s) => {
81 if pos < s.len() {
82 return s.chars().nth(pos);
83 }
84 pos -= s.len();
85 }
86 }
87 }
88
89 for child in &node.next {
90 let child_len = length(child, is_visible);
91 if pos < child_len {
92 return get(child, pos, is_visible);
93 }
94 pos -= child_len;
95 }
96
97 None
98}
99
100pub fn prune(node: &mut SequenceNode, version: &str) {
101 if node.version.as_ref().map(|v| v == version).unwrap_or(false) {
102 node.version = None;
103 }
104 node.deleted_by.remove(version);
105
106 for child in &mut node.next {
107 prune(child, version);
108 }
109}