cojson 0.6.0

Collaborative JSON (A high performance CRDT)
Documentation
use serde_derive::{Deserialize, Serialize};

use crate::{
    mem_use::{MemUsage, MemUser},
    ops::{ObjID, Op, OpKind},
};

#[derive(Clone, Debug)]
pub(crate) struct TextState {
    pub(super) create: Option<Op>,
    pub(super) root: Option<TextRoot>,
}

#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
pub(crate) struct TextRoot {
    pub ranges: ObjID,
    pub graphemes: ObjID,
}

impl TextState {
    pub fn new() -> Self {
        TextState {
            create: None,
            root: None,
        }
    }

    pub fn apply_op(&self, op: Op) -> Self {
        match op.kind {
            OpKind::TextCreate => {
                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")
                    }
                }

                TextState {
                    root: Some(
                        litl::from_val(
                            op.val
                                .clone()
                                .expect("Expected text root as val on create op"),
                        )
                        .expect("Expected valid text root in create op"),
                    ),
                    create: Some(op),
                }
            }
            _ => panic!("Unexpected op for text"),
        }
    }

    pub fn apply_ops<II: IntoIterator<Item = Op>>(&self, ops: II) -> Self {
        let mut next = self.clone();
        for op in ops {
            next = next.apply_op(op);
        }
        next
    }

    pub(crate) fn ops_since(&self, maybe_other: Option<&Self>) -> Vec<Op> {
        if let Some(create) = &self.create {
            if maybe_other.map(|other| &other.create).is_none() {
                vec![create.clone()]
            } else {
                vec![]
            }
        } else {
            vec![]
        }
    }
}

impl MemUser for TextState {
    fn mem_use(&self) -> MemUsage {
        MemUsage::Struct {
            name: "TextState",
            fields: vec![
                ("create", self.create.mem_use()),
                ("root", self.root.mem_use()),
            ],
        }
    }
}

impl MemUser for TextRoot {
    fn mem_use(&self) -> MemUsage {
        MemUsage::Struct {
            name: "TextRoot",
            fields: vec![
                ("ranges", self.ranges.mem_use()),
                ("graphemes", self.graphemes.mem_use()),
            ],
        }
    }
}