use serde::{Deserialize, Serialize};
use std::cmp::{Eq, Ordering, PartialEq};
use super::{Clock, LogOpMove, OpMove, Tree, TreeId, TreeMeta, TreeNode};
use crdts::{Actor, CmRDT};
use log::warn;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct State<ID: TreeId, TM: TreeMeta, A: Actor> {
log_op_list: Vec<LogOpMove<ID, TM, A>>,
tree: Tree<ID, TM>,
}
impl<ID: TreeId, TM: TreeMeta, A: Actor> State<ID, TM, A> {
pub fn new() -> Self {
Self {
log_op_list: Vec::<LogOpMove<ID, TM, A>>::default(),
tree: Tree::<ID, TM>::new(),
}
}
#[inline]
pub fn tree(&self) -> &Tree<ID, TM> {
&self.tree
}
#[inline]
pub fn tree_mut(&mut self) -> &mut Tree<ID, TM> {
&mut self.tree
}
#[inline]
pub fn log(&self) -> &Vec<LogOpMove<ID, TM, A>> {
&self.log_op_list
}
pub fn add_log_entry(&mut self, entry: LogOpMove<ID, TM, A>) {
self.log_op_list.insert(0, entry);
}
pub fn truncate_log_before(&mut self, timestamp: &Clock<A>) -> bool {
let len = self.log_op_list.len();
let mut last_idx: usize = len - 1;
for (i, v) in self.log_op_list.iter().rev().enumerate() {
if v.timestamp() < timestamp {
last_idx = len - 1 - i;
} else {
break;
}
}
loop {
let idx = self.log_op_list.len() - 1;
if idx < last_idx {
break;
}
self.log_op_list.remove(idx);
}
last_idx + 1 < len
}
pub fn do_op(&mut self, op: OpMove<ID, TM, A>) -> LogOpMove<ID, TM, A> {
let oldp = self.tree.find(op.child_id()).cloned();
if op.child_id() == op.parent_id() || self.tree.is_ancestor(op.parent_id(), op.child_id()) {
return LogOpMove::new(op, oldp);
}
self.tree.rm_child(op.child_id());
let tt = TreeNode::new(op.parent_id().to_owned(), op.metadata().to_owned());
self.tree.add_node(op.child_id().to_owned(), tt);
LogOpMove::new(op, oldp)
}
pub fn undo_op(&mut self, log: &LogOpMove<ID, TM, A>) {
self.tree.rm_child(log.child_id());
if let Some(oldp) = log.oldp() {
let tn = TreeNode::new(oldp.parent_id().to_owned(), oldp.metadata().to_owned());
self.tree.add_node(log.child_id().to_owned(), tn);
}
}
pub fn redo_op(&mut self, log: LogOpMove<ID, TM, A>) {
let op = OpMove::from(log);
let logop2 = self.do_op(op);
self.add_log_entry(logop2);
}
pub fn apply_op(&mut self, op1: OpMove<ID, TM, A>) {
if self.log_op_list.is_empty() {
let op2 = self.do_op(op1);
self.log_op_list = vec![op2];
} else {
match op1.timestamp().cmp(self.log_op_list[0].timestamp()) {
Ordering::Equal => {
warn!("op with timestamp equal to previous op ignored. (not applied). Every op must have a unique timestamp.");
}
Ordering::Less => {
let logop = self.log_op_list.remove(0); self.undo_op(&logop);
self.apply_op(op1);
self.redo_op(logop);
}
Ordering::Greater => {
let op2 = self.do_op(op1);
self.add_log_entry(op2);
}
}
}
}
pub fn apply_ops_into(&mut self, ops: Vec<OpMove<ID, TM, A>>) {
for op in ops {
self.apply_op(op);
}
}
pub fn apply_ops(&mut self, ops: &[OpMove<ID, TM, A>]) {
self.apply_ops_into(ops.to_vec())
}
}
impl<ID: TreeId, A: Actor, TM: TreeMeta> Default for State<ID, TM, A> {
fn default() -> Self {
Self::new()
}
}
type LogOpList<ID, TM, A> = Vec<LogOpMove<ID, TM, A>>;
impl<ID: TreeId, A: Actor, TM: TreeMeta> From<(Vec<LogOpMove<ID, TM, A>>, Tree<ID, TM>)>
for State<ID, TM, A>
{
fn from(e: (LogOpList<ID, TM, A>, Tree<ID, TM>)) -> Self {
Self {
log_op_list: e.0,
tree: e.1,
}
}
}
impl<ID: TreeId, TM: TreeMeta, A: Actor> CmRDT for State<ID, TM, A> {
type Op = OpMove<ID, TM, A>;
fn apply(&mut self, op: Self::Op) {
self.apply_op(op);
}
}
impl<ID: TreeId, TM: TreeMeta, A: Actor> IntoIterator for State<ID, TM, A> {
type Item = (ID, TreeNode<ID, TM>);
type IntoIter = std::collections::hash_map::IntoIter<ID, TreeNode<ID, TM>>;
fn into_iter(self) -> Self::IntoIter {
self.tree.into_iter()
}
}