use serde::{Deserialize, Serialize};
use std::collections::HashSet;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SequenceNode {
pub version: Option<String>,
pub elems: SequenceElems,
pub next: Vec<SequenceNode>,
pub deleted_by: HashSet<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SequenceElems {
String(String),
}
impl SequenceNode {
pub fn text(version: &str, text: &str) -> Self {
Self {
version: Some(version.to_string()),
elems: SequenceElems::String(text.to_string()),
next: Vec::new(),
deleted_by: HashSet::new(),
}
}
}
pub fn content<F>(node: &SequenceNode, is_visible: F) -> String
where
F: Fn(&str) -> bool + Copy,
{
let mut result = String::new();
let visible = node.version.as_ref().map(|v| is_visible(v)).unwrap_or(true)
&& node.deleted_by.iter().all(|v| !is_visible(v));
if visible {
match &node.elems {
SequenceElems::String(s) => result.push_str(s),
}
}
for child in &node.next {
result.push_str(&content(child, is_visible));
}
result
}
pub fn length<F>(node: &SequenceNode, is_visible: F) -> usize
where
F: Fn(&str) -> bool + Copy,
{
let visible = node.version.as_ref().map(|v| is_visible(v)).unwrap_or(true)
&& node.deleted_by.iter().all(|v| !is_visible(v));
let mut len = if visible {
match &node.elems {
SequenceElems::String(s) => s.len(),
}
} else {
0
};
for child in &node.next {
len += length(child, is_visible);
}
len
}
pub fn get<F>(node: &SequenceNode, mut pos: usize, is_visible: F) -> Option<char>
where
F: Fn(&str) -> bool + Copy,
{
let visible = node.version.as_ref().map(|v| is_visible(v)).unwrap_or(true)
&& node.deleted_by.iter().all(|v| !is_visible(v));
if visible {
match &node.elems {
SequenceElems::String(s) => {
if pos < s.len() {
return s.chars().nth(pos);
}
pos -= s.len();
}
}
}
for child in &node.next {
let child_len = length(child, is_visible);
if pos < child_len {
return get(child, pos, is_visible);
}
pos -= child_len;
}
None
}
pub fn prune(node: &mut SequenceNode, version: &str) {
if node.version.as_ref().map(|v| v == version).unwrap_or(false) {
node.version = None;
}
node.deleted_by.remove(version);
for child in &mut node.next {
prune(child, version);
}
}