mod vector_clock; use uuid::Uuid; use crate::vector_clock::VectorClock; #[derive(Default)] pub struct Doc { ops: Vec, } impl Doc { pub fn append_op(&mut self, actor_id: &Uuid, payload: OpPayload) { // Increment the last clock for the provided actor let clock = self .ops .last() .map(|Op { clock, .. }| clock.inc(actor_id)) // For an empty document, initialize a new clock .unwrap_or_else(|| VectorClock::default().inc(actor_id)); self.ops.push(Op { id: Uuid::now_v7(), clock, payload, }); } pub fn realize(&self) -> RealizedDoc { let mut realized = RealizedDoc::default(); for op in &self.ops { op.apply(&mut realized); } realized } } pub struct Op { id: Uuid, payload: OpPayload, clock: VectorClock, } impl Op { fn apply(&self, realized: &mut RealizedDoc) { match &self.payload { OpPayload::CreateGrid { rows, base_cells_per_row, } => { let rows = (0..*rows) .map(|row_idx| { let cells = (0..*base_cells_per_row) .map(|cell_idx| Cell { id: self.id.derive_id("cell", cell_idx), }) .collect(); Row { id: self.id.derive_id("row", row_idx), cells, } }) .collect(); realized.grids.push(Grid { id: self.id.derive_id("grid", 0), rows, }); } } } } pub enum OpPayload { CreateGrid { rows: usize, base_cells_per_row: usize, }, } #[derive(Default)] pub struct RealizedDoc { grids: Vec, } pub struct Grid { id: DerivedId, rows: Vec, } pub struct Row { id: DerivedId, cells: Vec, } pub struct Cell { id: DerivedId, } pub struct DerivedId { id: Uuid, tag: &'static str, index: usize, } trait DerivableId { fn derive_id(&self, tag: &'static str, index: usize) -> DerivedId; } impl DerivableId for Uuid { fn derive_id(&self, tag: &'static str, index: usize) -> DerivedId { DerivedId { id: self.clone(), tag, index, } } } #[cfg(test)] mod tests { use super::*; #[test] fn realize_doc() { let actor_id = Uuid::now_v7(); let mut doc = Doc::default(); doc.append_op( &actor_id, OpPayload::CreateGrid { rows: 4, base_cells_per_row: 16, }, ); let realized = doc.realize(); assert!(realized.grids.len() == 1); let grid = realized.grids.first().unwrap(); assert!(grid.rows.len() == 4); let row = grid.rows.first().unwrap(); assert!(row.cells.len() == 16); } }