use im::vector;
use crate::{
mem_use::{MemUsage, MemUser},
object::ObjectState,
sort::IndexableList,
undo_redo::UndoRedoState,
};
use super::super::ops::{Op, OpID, OpKind};
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub(crate) struct ListState {
pub(super) create: Option<Op>,
pub(super) inserts: insert_op_store::InsertOpStore,
pub(super) undo_redos: UndoRedoState,
}
mod insert_op_store;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[repr(u8)]
pub enum Descendants {
Uninitialized,
Single(OpID),
Multiple(Box<im::Vector<OpID>>),
}
impl ListState {
pub fn new() -> Self {
ListState {
create: None,
inserts: insert_op_store::InsertOpStore::for_no_create_yet(),
undo_redos: UndoRedoState::new(),
}
}
pub fn inserts_in_order(&self) -> Vec<Op> {
let mut in_order = Vec::new();
if let Some(create) = &self.create {
let get_next_sibling = |node: &Op| -> Option<OpID> {
let parent_descendants = self
.inserts
.get_descendants(&node.prev)
.expect("Expected parent node to have descendants");
let index = parent_descendants
.iter()
.position(|sibling_hash| sibling_hash == &node.id)
.expect("Expected index for current sibling");
parent_descendants.get(index + 1).cloned()
};
let mut current_node_id = create.id;
let mut descendants_of_create_done = false;
while !descendants_of_create_done {
if current_node_id != create.id {
in_order.push(
self.inserts
.get_op(¤t_node_id)
.expect("Expected entry for current node hash")
.clone(),
)
}
let maybe_descendants = self.inserts.get_descendants(¤t_node_id);
let maybe_first_child_hash = maybe_descendants.and_then(|d| d.get(0).cloned());
if let Some(first_child_hash) = maybe_first_child_hash {
current_node_id = first_child_hash
} else {
loop {
if current_node_id == create.id {
descendants_of_create_done = true;
break;
}
let current_node = self
.inserts
.get_op(¤t_node_id)
.expect("Expected entry for current node hash");
if let Some(next_sibling_id) = get_next_sibling(¤t_node) {
current_node_id = next_sibling_id;
break;
} else {
let parent_id = current_node.prev;
current_node_id = parent_id;
}
}
}
}
}
in_order
}
}
impl ObjectState for ListState {
fn apply_op(&self, op: Op) -> Self {
match op.kind {
OpKind::ListCreate => {
if let Some(existing_entry) = &self.create {
if existing_entry.id == op.id {
return self.clone();
} else {
panic!("Already has a create op, with different id")
}
}
ListState {
inserts: insert_op_store::InsertOpStore::for_create_op(&op),
create: Some(op),
..self.clone()
}
}
OpKind::ListInsertAfter => {
if self.inserts.has(&op.id) {
return self.clone(); };
ListState {
inserts: self.inserts.add(op),
..self.clone()
}
}
OpKind::Undo | OpKind::Redo => ListState {
undo_redos: self.undo_redos.insert(op),
..self.clone()
},
_ => panic!("Unexpected op for list"),
}
}
fn ops_since(&self, maybe_other: Option<&Self>) -> Vec<Op> {
let other_create = maybe_other.and_then(|other| other.create.as_ref());
let missing_create = if other_create.is_some() {
None
} else {
self.create.clone()
};
let missing_inserts = if let Some(other) = maybe_other {
let mut missing_inserts = vec![];
for insert in self.inserts_in_order() {
if !other.inserts.has(&insert.id) {
missing_inserts.push(insert)
}
}
missing_inserts
} else {
self.inserts_in_order()
};
let missing_undo_redos = self
.undo_redos
.ops_since(maybe_other.map(|other| &other.undo_redos));
missing_create
.into_iter()
.chain(missing_inserts)
.chain(missing_undo_redos)
.collect()
}
}
impl MemUser for ListState {
fn mem_use(&self) -> MemUsage {
MemUsage::Struct {
name: "ListState",
fields: vec![
("create", self.create.mem_use()),
("inserts", self.inserts.mem_use()),
("undo_redos", self.undo_redos.mem_use()),
],
}
}
}
impl IndexableList<OpID> for Descendants {
fn size(&self) -> usize {
match self {
Descendants::Uninitialized => panic!("Uninitialized"),
Descendants::Single(_) => 1,
Descendants::Multiple(list) => list.len(),
}
}
fn at(&self, at: usize) -> Option<&OpID> {
match self {
Descendants::Uninitialized => panic!("Uninitialized"),
Descendants::Single(single) => {
if at == 0 {
Some(single)
} else {
None
}
}
Descendants::Multiple(list) => list.at(at),
}
}
fn last(&self) -> Option<&OpID> {
match self {
Descendants::Uninitialized => panic!("Uninitialized"),
Descendants::Single(single) => Some(single),
Descendants::Multiple(list) => list.last(),
}
}
fn iter<'a>(&'a self) -> Box<dyn DoubleEndedIterator<Item = &OpID> + 'a> {
match self {
Descendants::Uninitialized => panic!("Uninitialized"),
Descendants::Single(single) => Box::new(Some(single).into_iter()),
Descendants::Multiple(list) => Box::new(list.iter()),
}
}
}
impl Descendants {
fn insert(&mut self, at: usize, new_item: OpID) {
let old = std::mem::replace(self, Descendants::Uninitialized);
*self = match old {
Descendants::Uninitialized => {
if at == 0 {
Descendants::Single(new_item)
} else {
panic!("Tried to insert into empty descendants at non-zero index")
}
}
Descendants::Single(item) => {
if at == 0 {
Descendants::Multiple(Box::new(vector![new_item, item]))
} else if at == 1 {
Descendants::Multiple(Box::new(vector![item, new_item]))
} else {
panic!("Tried to insert into single descendant at index != 0, != 0")
}
}
Descendants::Multiple(mut items) => {
items.insert(at, new_item);
Descendants::Multiple(items)
}
}
}
fn get(&self, at: usize) -> Option<&OpID> {
self.at(at)
}
}
impl MemUser for Descendants {
fn mem_use(&self) -> MemUsage {
MemUsage::Enum {
name: "Descendants",
discriminant: std::mem::size_of::<u8>(),
min_size: std::mem::size_of::<Descendants>(),
variant: Box::new(match self {
Descendants::Uninitialized => ("None", MemUsage::Simple(0)),
Descendants::Single(_) => ("Single", MemUsage::Simple(0)),
Descendants::Multiple(items) => ("Multiple", items.mem_use()),
}),
}
}
}