jmbl 0.5.0

A high performance CRDT
Documentation
use std::ops::Deref;

use crate::{
    input::Input,
    io::OpOutput,
    ops::{OpWithTarget},
    view::{
        jmbl_view::{JMBLView, JMBLViewRef},
        value::Value,
    },
};

use super::{jmbl_state::ReadableJMBL, ops::ObjID};

pub struct JMBL {
    pub readable: ReadableJMBL,
    op_output: Option<OpOutput>,
}

impl Deref for JMBL {
    type Target = ReadableJMBL;

    fn deref(&self) -> &Self::Target {
        &self.readable
    }
}

impl JMBL {
    pub fn start_changing_object(&mut self) -> JMBLViewRef {
        let op_output = self.op_output.take().unwrap();

        JMBLViewRef::new(JMBLView::new(
            Some(op_output),
            self.readable.state.clone(),
        ))
    }

    pub fn finish_changing_object(&mut self, mut write_view: JMBLViewRef) -> Vec<OpWithTarget> {
        let (op_output, edit_ops) = write_view.finalize_writing();

        // TODO(optimization): keep most of jmbl view
        let new_state = write_view.get().jmbl_state.clone();

        self.readable = ReadableJMBL::new_from(new_state);
        self.op_output = Some(op_output);

        edit_ops
    }

    pub fn change_object<CFn: Fn(&mut Value)>(
        &mut self,
        obj_id: &ObjID,
        changer: CFn,
    ) -> Vec<OpWithTarget> {
        let write_view = self.start_changing_object();

        changer(&mut write_view.obj_id_to_value(obj_id));

        self.finish_changing_object(write_view)
    }

    pub fn change<CFn: Fn(&mut Value)>(&mut self, changer: CFn) -> Vec<OpWithTarget> {
        let (root_id, _) = *self
            .readable
            .root
            .as_ref()
            .expect("Expected to have root to change");
        self.change_object(&root_id, changer)
    }

    pub fn new_empty() -> JMBL {
        JMBL {
            readable: ReadableJMBL::new(),
            op_output: None,
        }
    }

    pub fn new_from_root<I: Into<Input>>(input: I, op_output: OpOutput) -> Self {
        let mut jmbl = JMBL::new_empty();
        jmbl.op_output = Some(op_output);

        let mut write_view = jmbl.start_changing_object();

        write_view.create_root(input);

        jmbl.finish_changing_object(write_view);
        jmbl
    }

    pub fn switch_to_new_op_output(&mut self, op_output: OpOutput) -> Self {
        self.op_output = None;
        JMBL {
            readable: self.readable.clone(),
            op_output: Some(op_output),
        }
    }

    pub fn make_readable(&mut self) {
        self.op_output = None;
    }

    pub fn apply_ops<'a, I: IntoIterator<Item = &'a OpWithTarget>>(&mut self, ops: I) {
        self.readable = self.readable.with_ops_applied(ops);
    }

    pub fn test_get_past_sent_ops(&mut self) -> Option<Vec<OpWithTarget>> {
        self.op_output.as_mut().unwrap().test_get_past_sent_ops()
    }
}