cojson 0.6.0

Collaborative JSON (A high performance CRDT)
Documentation
use litl::{impl_debug_as_litl, impl_single_tagged_data_serde, SingleTaggedData};
use thiserror::Error;
use ti64::MsSinceEpoch;

use crate::ops::{ObjID, Op, OpID, OpKind, OpWithTarget};

use rand::{rngs::OsRng, RngCore};

use crate::mem_use::{MemUsage, MemUser};

#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SrcID([u8; 16]);

impl SingleTaggedData for SrcID {
    const TAG: &'static str = "opSrc";

    fn as_bytes(&self) -> std::borrow::Cow<'_, [u8]> {
        std::borrow::Cow::Borrowed(&self.0)
    }

    fn from_bytes(data: &[u8]) -> Result<Self, litl::TaggedDataError>
    where
        Self: Sized,
    {
        let bytes: [u8; 16] = data
            .try_into()
            .map_err(Into::<SrcIDError>::into)
            .map_err(litl::TaggedDataError::data_error)?;
        Ok(SrcID(bytes))
    }
}

#[derive(Debug, Error)]
pub enum SrcIDError {
    #[error("Invalid length for LogID")]
    InvalidLength(#[from] std::array::TryFromSliceError),
}

impl_single_tagged_data_serde!(SrcID);
impl_debug_as_litl!(SrcID);

impl SrcID {
    pub fn new_random() -> SrcID {
        let mut id = [0u8; 16];
        OsRng {}.fill_bytes(&mut id);
        SrcID(id)
    }

    pub fn as_bytes(&self) -> &[u8; 16] {
        &self.0
    }
}

impl MemUser for SrcID {
    fn mem_use(&self) -> MemUsage {
        MemUsage::Simple(std::mem::size_of::<SrcID>())
    }
}

pub struct OpOutput {
    pub src_id: SrcID,
    sender: Box<dyn OpSender>,
    next_sequence_idx: u32,
}

impl OpOutput {
    pub fn next_sequence_idx(&self) -> u32 {
        self.next_sequence_idx
    }
}

pub trait OpSender {
    fn send(&mut self, value: OpWithTarget) -> Result<(), String>;

    fn test_get_past_sent_ops(&mut self) -> Option<Vec<OpWithTarget>>;
}

#[derive(Default)]
struct DummySender {
    sent_ops: Vec<OpWithTarget>,
}

impl OpSender for DummySender {
    // TODO: use Box<dyn Error> here
    fn send(&mut self, value: OpWithTarget) -> Result<(), String> {
        self.sent_ops.push(value);
        Ok(())
    }

    fn test_get_past_sent_ops(&mut self) -> Option<Vec<OpWithTarget>> {
        Some(std::mem::take(&mut self.sent_ops))
    }
}

impl OpOutput {
    pub fn new_dummy() -> OpOutput {
        OpOutput {
            src_id: SrcID::new_random(),
            next_sequence_idx: 0,
            sender: Box::new(DummySender::default()),
        }
    }

    pub fn new(sender: Box<dyn OpSender>) -> OpOutput {
        OpOutput {
            src_id: SrcID::new_random(),
            next_sequence_idx: 0,
            sender,
        }
    }

    pub fn write_op_at_time(
        &mut self,
        target_obj_id: ObjID,
        time: MsSinceEpoch,
        prev: OpID,
        kind: OpKind,
        val: Option<litl::Val>,
    ) -> Op {
        let op = Op {
            id: OpID(self.src_id, self.next_sequence_idx),
            time,
            prev,
            kind,
            val,
        };

        self.next_sequence_idx += 1;

        self.sender
            .send(OpWithTarget {
                target_obj_id,
                op: op.clone(),
            })
            .unwrap();

        op
    }

    pub fn write_op_now(
        &mut self,
        target_obj_id: ObjID,
        prev: OpID,
        kind: OpKind,
        val: Option<litl::Val>,
    ) -> Op {
        let op = Op::new(OpID(self.src_id, self.next_sequence_idx), prev, kind, val);

        self.next_sequence_idx += 1;

        self.sender
            .send(OpWithTarget {
                target_obj_id,
                op: op.clone(),
            })
            .unwrap();

        op
    }

    pub fn write_create_op(&mut self, kind: OpKind, val: Option<litl::Val>) -> (Op, ObjID) {
        let op = Op::new_initial(OpID(self.src_id, self.next_sequence_idx), kind, val);

        let obj_id = ObjID::from_first_op_id(op.id);

        self.next_sequence_idx += 1;

        self.sender
            .send(OpWithTarget {
                target_obj_id: obj_id,
                op: op.clone(),
            })
            .unwrap();

        (op, obj_id)
    }

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