use smol_str::SmolStr;
use std::fmt;
use std::fmt::Display;
use std::sync::Arc;
use crate::op_tree::OpSetData;
use crate::types::{OpId, OpType};
use crate::value::ScalarValue;
use std::borrow::Cow;
use std::collections::BTreeMap;
#[derive(Debug, Clone, PartialEq)]
pub struct Mark<'a> {
pub start: usize,
pub end: usize,
pub(crate) data: Cow<'a, MarkData>,
}
impl<'a> Mark<'a> {
pub(crate) fn len(&self) -> usize {
self.end - self.start
}
pub(crate) fn into_mark_set(self) -> Arc<MarkSet> {
let mut m = MarkSet::default();
let data = self.data.into_owned();
m.insert(data.name, data.value);
Arc::new(m)
}
}
#[derive(Debug, Clone)]
struct MarkAccItem {
index: usize,
len: usize,
value: ScalarValue,
}
#[derive(Debug, Clone, Default)]
pub(crate) struct MarkAccumulator {
marks: BTreeMap<SmolStr, Vec<MarkAccItem>>,
}
impl MarkAccumulator {
pub(crate) fn into_iter(self) -> impl Iterator<Item = Mark<'static>> {
self.marks.into_iter().flat_map(|(name, items)| {
items.into_iter().map(move |i| {
Mark::new(name.to_string(), i.value.clone(), i.index, i.index + i.len)
})
})
}
pub(crate) fn into_iter_no_unmark(self) -> impl Iterator<Item = Mark<'static>> {
self.marks.into_iter().flat_map(|(name, items)| {
items
.into_iter()
.filter(|i| !i.value.is_null())
.map(move |i| {
Mark::new(name.to_string(), i.value.clone(), i.index, i.index + i.len)
})
})
}
pub(crate) fn add(&mut self, index: usize, len: usize, other: &MarkSet) {
for (name, value) in other.marks.iter() {
let entry = self.marks.entry(name.clone()).or_default();
if let Some(last) = entry.last_mut() {
if &last.value == value && last.index + last.len == index {
last.len += len;
continue;
}
}
entry.push(MarkAccItem {
index,
len,
value: value.clone(),
})
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct MarkSet {
marks: BTreeMap<SmolStr, ScalarValue>,
}
impl MarkSet {
pub fn iter(&self) -> impl Iterator<Item = (&str, &ScalarValue)> {
self.marks
.iter()
.map(|(name, value)| (name.as_str(), value))
}
fn inner(&self) -> &BTreeMap<SmolStr, ScalarValue> {
&self.marks
}
pub fn len(&self) -> usize {
self.marks.len()
}
fn insert(&mut self, name: SmolStr, value: ScalarValue) {
self.marks.insert(name, value);
}
fn remove(&mut self, name: &SmolStr) {
self.marks.remove(name);
}
pub fn is_empty(&self) -> bool {
self.inner().is_empty()
}
pub(crate) fn diff(&self, other: &Self) -> Self {
let mut diff = BTreeMap::default();
for (name, value) in self.marks.iter() {
match other.marks.get(name) {
Some(v) if v != value => {
diff.insert(name.clone(), v.clone());
}
None => {
diff.insert(name.clone(), ScalarValue::Null);
}
_ => {}
}
}
for (name, value) in other.marks.iter() {
if !self.marks.contains_key(name) {
diff.insert(name.clone(), value.clone());
}
}
MarkSet { marks: diff }
}
}
impl<'a> Mark<'a> {
pub fn new<V: Into<ScalarValue>>(
name: String,
value: V,
start: usize,
end: usize,
) -> Mark<'static> {
Mark {
data: Cow::Owned(MarkData {
name: name.into(),
value: value.into(),
}),
start,
end,
}
}
pub(crate) fn from_data(start: usize, end: usize, data: &MarkData) -> Mark<'_> {
Mark {
data: Cow::Borrowed(data),
start,
end,
}
}
pub fn into_owned(self) -> Mark<'static> {
Mark {
data: Cow::Owned(self.data.into_owned()),
start: self.start,
end: self.end,
}
}
pub fn name(&self) -> &str {
self.data.name.as_str()
}
pub fn value(&self) -> &ScalarValue {
&self.data.value
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub(crate) struct MarkStateMachine<'a> {
state: Vec<(OpId, &'a MarkData)>,
current: Arc<MarkSet>,
}
impl<'a> MarkStateMachine<'a> {
pub(crate) fn current(&self) -> Option<&Arc<MarkSet>> {
if self.current.is_empty() {
None
} else {
Some(&self.current)
}
}
pub(crate) fn process(&mut self, opid: OpId, action: &'a OpType, osd: &OpSetData) -> bool {
match action {
OpType::MarkBegin(_, data) => self.mark_begin(opid, data, osd),
OpType::MarkEnd(_) => self.mark_end(opid, osd),
_ => false,
}
}
pub(crate) fn mark_begin(&mut self, id: OpId, mark: &'a MarkData, osd: &OpSetData) -> bool {
let mut result = false;
let index = match self.find(id.prev(), osd).err() {
Some(index) => index,
None => return false,
};
if Self::mark_above(&self.state, index, mark).is_none() {
if let Some(below) = Self::mark_below(&mut self.state, index, mark) {
if below.value != mark.value {
Arc::make_mut(&mut self.current).insert(mark.name.clone(), mark.value.clone());
result = true
}
} else {
Arc::make_mut(&mut self.current).insert(mark.name.clone(), mark.value.clone());
result = true
}
}
self.state.insert(index, (id, mark));
result
}
pub(crate) fn mark_end(&mut self, id: OpId, osd: &OpSetData) -> bool {
let mut result = false;
let index = match self.find(id.prev(), osd).ok() {
Some(index) => index,
None => return false,
};
let mark = self.state.remove(index).1;
if Self::mark_above(&self.state, index, mark).is_none() {
match Self::mark_below(&mut self.state, index, mark) {
Some(below) if below.value == mark.value => {}
Some(below) => {
Arc::make_mut(&mut self.current)
.insert(below.name.clone(), below.value.clone());
result = true;
}
None => {
Arc::make_mut(&mut self.current).remove(&mark.name);
result = true;
}
}
}
result
}
fn find(&self, target: OpId, osd: &OpSetData) -> Result<usize, usize> {
self.state
.binary_search_by(|probe| osd.lamport_cmp(probe.0, target))
}
fn mark_above<'b>(
state: &'b [(OpId, &'a MarkData)],
index: usize,
mark: &MarkData,
) -> Option<&'b MarkData> {
Some(state[index..].iter().find(|(_, m)| m.name == mark.name)?.1)
}
fn mark_below<'b>(
state: &'b mut [(OpId, &'a MarkData)],
index: usize,
mark: &MarkData,
) -> Option<&'b MarkData> {
Some(
state[0..index]
.iter_mut()
.filter(|(_, m)| m.name == mark.name)
.last()?
.1,
)
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct MarkData {
pub name: SmolStr,
pub value: ScalarValue,
}
impl Display for MarkData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "name={} value={}", self.name, self.value)
}
}
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum ExpandMark {
Before,
After,
Both,
None,
}
impl Default for ExpandMark {
fn default() -> Self {
Self::After
}
}
impl ExpandMark {
pub fn from(before: bool, after: bool) -> Self {
match (before, after) {
(true, true) => Self::Both,
(false, true) => Self::After,
(true, false) => Self::Before,
(false, false) => Self::None,
}
}
pub fn before(&self) -> bool {
matches!(self, Self::Before | Self::Both)
}
pub fn after(&self) -> bool {
matches!(self, Self::After | Self::Both)
}
}