use std::{
collections::{HashMap, HashSet},
hash::Hash,
};
use super::{
super::ops::{Op, OpID, OpKind},
list_state::ListState,
};
pub(crate) struct ListTranslator {
pub(super) list: ListState,
pub op_before_index: Vec<Op>,
pub index_after_op_id: HashMap<OpID, usize>,
}
impl ListTranslator {
pub fn new(list: ListState) -> ListTranslator {
let mut op_before_index = Vec::new();
let mut index_after_op_hash = HashMap::new();
let mut undone = HashSet::new();
if let Some(create_op) = &list.create {
index_after_op_hash.insert(create_op.id, 0);
op_before_index.insert(0, create_op.clone());
}
for undone_hash in list.undo_redos.keys() {
if list.inserts.has(undone_hash) && list.undo_redos.is_undone(*undone_hash) {
undone.insert(*undone_hash);
}
}
let mut i = 1;
for insert_op in list.inserts_in_order() {
index_after_op_hash.insert(insert_op.id, i);
if !undone.contains(&insert_op.id) {
op_before_index.insert(i, insert_op);
i += 1;
}
}
ListTranslator {
list,
op_before_index,
index_after_op_id: index_after_op_hash,
}
}
pub fn len(&self) -> usize {
self.op_before_index.len().saturating_sub(1)
}
pub fn at(&self, index: usize) -> Option<&litl::Val> {
self.op_before_index
.get(index + 1)
.map(|op| match &op.kind {
OpKind::ListInsertAfter => op.val.as_ref().expect("Insert op should have value"),
_ => unreachable!("Should only have insert ops"),
})
}
pub fn prev_op_for_insert_at(&self, index: usize) -> OpID {
self.op_before_index[index].id
}
pub fn prev_op_for_delete_at(&self, index: usize) -> OpID {
self.op_before_index[index + 1].id
}
pub fn iter_items(&self) -> impl Iterator<Item = &litl::Val> {
self.op_before_index[1..].iter().map(|op| match op.kind {
OpKind::ListInsertAfter => op.val.as_ref().expect("Insert op should have value"),
_ => panic!("Expected ListInsert"),
})
}
}
impl PartialEq for ListTranslator {
fn eq(&self, other: &Self) -> bool {
self.list == other.list
}
}
impl Hash for ListTranslator {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.list.hash(state)
}
}