cojson 0.6.0

Collaborative JSON (A high performance CRDT)
Documentation
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(),
        }
    }

    // Stackless depth-first-search using parent pointers
    // https://stackoverflow.com/a/5285417/387873
    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(&current_node_id)
                            .expect("Expected entry for current node hash")
                            .clone(),
                    )
                }
                let maybe_descendants = self.inserts.get_descendants(&current_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 {
                    // children done, go to next sibling or up the tree
                    loop {
                        if current_node_id == create.id {
                            descendants_of_create_done = true;
                            break;
                        }
                        let current_node = self
                            .inserts
                            .get_op(&current_node_id)
                            .expect("Expected entry for current node hash");

                        if let Some(next_sibling_id) = get_next_sibling(&current_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(); // op already exists
                };

                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()
        };

        // TODO(optimization): traverse insert store directly
        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()),
            }),
        }
    }
}