diff options
Diffstat (limited to 'crdt/src')
| -rw-r--r-- | crdt/src/lib.rs | 115 | ||||
| -rw-r--r-- | crdt/src/vector_clock.rs | 2 |
2 files changed, 85 insertions, 32 deletions
diff --git a/crdt/src/lib.rs b/crdt/src/lib.rs index dcef55c..df8425d 100644 --- a/crdt/src/lib.rs +++ b/crdt/src/lib.rs @@ -4,28 +4,20 @@ use uuid::Uuid; use crate::vector_clock::VectorClock; +#[derive(Default)] pub struct Doc { ops: Vec<Op>, } impl Doc { - pub fn new(actor_id: &Uuid) -> Self { - Self { - ops: vec![Op { - id: Uuid::now_v7(), - clock: VectorClock::new().inc(actor_id), - payload: OpPayload::Init, - }], - } - } - - pub fn append_op(&mut self, payload: OpPayload, actor_id: &Uuid) { + pub fn append_op(&mut self, actor_id: &Uuid, payload: OpPayload) { + // Increment the last clock for the provided actor let clock = self .ops .last() - .expect("doc should have at least an Init op") - .clock - .inc(actor_id); + .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(), @@ -34,11 +26,13 @@ impl Doc { }); } - pub fn realize(&self) -> RealizedDoc { + pub fn realize(&self) -> RealizedDoc<'_> { let mut realized = RealizedDoc::default(); + for op in &self.ops { op.apply(&mut realized); } + realized } } @@ -50,32 +44,72 @@ pub struct Op { } impl Op { - fn apply(&self, realized: &mut RealizedDoc) { - match self.payload { - OpPayload::Init => {} - OpPayload::ChangeSubdivisions { rowId } => {} + fn apply<'a>(&'a self, realized: &mut RealizedDoc<'a>) { + match &self.payload { + OpPayload::CreateGrid { + id: grid_id, + rows, + base_cells_per_row, + } => { + let rows = (0..*rows) + .map(|row_idx| { + let cells = (0..*base_cells_per_row) + .map(|cell_idx| Cell { + id: DerivedId::new(grid_id, "cell", cell_idx), + }) + .collect(); + + Row { + id: DerivedId::new(grid_id, "row", row_idx), + cells, + } + }) + .collect(); + + realized.grids.push(Grid { id: grid_id, rows }); + } } } } pub enum OpPayload { - Init, - ChangeSubdivisions { rowId: Uuid }, + CreateGrid { + id: Uuid, + rows: usize, + base_cells_per_row: usize, + }, } -pub struct RealizedDoc { - grids: Vec<Grid>, +#[derive(Default)] +pub struct RealizedDoc<'a> { + grids: Vec<Grid<'a>>, } -impl Default for RealizedDoc { - fn default() -> Self { - RealizedDoc { - grids: vec![Grid {}], - } - } +pub struct Grid<'a> { + id: &'a Uuid, + rows: Vec<Row<'a>>, +} + +pub struct Row<'a> { + id: DerivedId<'a>, + cells: Vec<Cell<'a>>, +} + +pub struct Cell<'a> { + id: DerivedId<'a>, } -pub struct Grid {} +pub struct DerivedId<'a> { + id: &'a Uuid, + tag: &'static str, + index: usize, +} + +impl<'a> DerivedId<'a> { + pub fn new(id: &'a Uuid, tag: &'static str, index: usize) -> Self { + Self { id, tag, index } + } +} #[cfg(test)] mod tests { @@ -84,9 +118,28 @@ mod tests { #[test] fn realize_doc() { let actor_id = Uuid::now_v7(); - let doc = Doc::new(&actor_id); + + let mut doc = Doc::default(); + + doc.append_op( + &actor_id, + OpPayload::CreateGrid { + id: Uuid::now_v7(), + 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); } } diff --git a/crdt/src/vector_clock.rs b/crdt/src/vector_clock.rs index e80180f..e5a39c4 100644 --- a/crdt/src/vector_clock.rs +++ b/crdt/src/vector_clock.rs @@ -5,7 +5,7 @@ use std::{ use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct VectorClock(HashMap<Uuid, u64>); impl VectorClock { |
