use std::hash::Hash;
use crate::{
mem_use::{MemUsage, MemUser},
object::ObjectState,
ops::Op,
};
use super::super::{
ops::OpKind,
sort::only_in_first_sorted_list,
sort::{noncausal_sort, search_from_back},
undo_redo::UndoRedoState,
};
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub(crate) struct MapState {
pub(super) create: Option<Op>,
pub(super) ops_for_key: im::HashMap<String, im::Vector<Op>>,
undo_redos: UndoRedoState,
}
impl MapState {
pub fn new() -> MapState {
MapState {
create: None,
ops_for_key: Default::default(),
undo_redos: UndoRedoState::new(),
}
}
fn insert_op_into_list_for_key(&self, key: String, op: Op) -> Self {
let new_ops_for_key = self.ops_for_key.alter(
|maybe_ops_for_key| {
let ops_for_key = maybe_ops_for_key.unwrap_or_default();
let insertion_position = search_from_back(&ops_for_key, &op, noncausal_sort);
match insertion_position {
Ok(_) => Some(ops_for_key),
Err(pos) => {
let mut new_ops_for_key = ops_for_key;
new_ops_for_key.insert(pos, op.clone());
Some(new_ops_for_key)
}
}
},
key,
);
MapState {
ops_for_key: new_ops_for_key,
..self.clone()
}
}
fn _sets_not_undone(&self) -> Vec<litl::Val> {
self.ops_for_key
.iter()
.filter_map(move |(_key, ops_for_key)| {
ops_for_key
.iter()
.rev()
.find(|op| !self.undo_redos.is_undone(op.id))
.map(|last_op| match last_op.kind {
OpKind::MapSet => last_op.val.as_ref().unwrap()[0].clone(),
_ => unreachable!("Has to be map set"),
})
})
.collect()
}
pub fn last_op_for_key(&self, key: &str) -> Option<Op> {
self.ops_for_key
.get(key)
.and_then(|list| list.last().cloned())
}
pub fn last_op_for_key_not_undone(&self, key: &str) -> Option<Op> {
self.ops_for_key.get(key).and_then(|list| {
list.iter()
.rev()
.find(|op| !self.undo_redos.is_undone(op.id))
.cloned()
})
}
}
impl ObjectState for MapState {
fn apply_op(&self, op: Op) -> Self {
match (&op.kind, &op.val) {
(OpKind::MapCreate, None) => {
if let Some(existing_op) = &self.create {
if existing_op.id == op.id {
return self.clone();
} else {
panic!("Already has a create op, with different id")
}
}
MapState {
create: Some(op),
..self.clone()
}
}
(OpKind::MapSet, Some(entry)) => {
self.insert_op_into_list_for_key(entry[0].clone().as_str().unwrap().to_owned(), op)
}
(OpKind::Undo, None) | (OpKind::Redo, None) => MapState {
undo_redos: self.undo_redos.insert(op),
..self.clone()
},
_ => panic!("Unexpected op for map {:?}", op),
}
}
fn ops_since(&self, maybe_other: Option<&Self>) -> Vec<Op> {
let other_create = maybe_other.and_then(|other| other.create.as_ref());
let maybe_other_ops_for_key = maybe_other.map(|other| &other.ops_for_key);
let missing_create = if other_create.is_some() {
None
} else {
self.create.clone()
};
let missing_ops_for_key = self
.ops_for_key
.iter()
.flat_map(move |(key, entries_for_key)| {
if let Some(entries_for_key_in_other) = maybe_other_ops_for_key
.as_ref()
.and_then(|other_ops_for_key| other_ops_for_key.get(key))
{
only_in_first_sorted_list(
entries_for_key,
entries_for_key_in_other,
noncausal_sort,
)
} else {
entries_for_key.iter().cloned().collect()
}
})
.collect::<Vec<_>>();
let missing_undo_redos = self
.undo_redos
.ops_since(maybe_other.map(|other| &other.undo_redos));
missing_create
.into_iter()
.chain(missing_ops_for_key)
.chain(missing_undo_redos)
.collect()
}
}
impl MemUser for MapState {
fn mem_use(&self) -> MemUsage {
MemUsage::Struct {
name: "MapState",
fields: vec![
("create", self.create.mem_use()),
("ops_for_key", self.ops_for_key.mem_use()),
("undo_redos", self.undo_redos.mem_use()),
],
}
}
}