summaryrefslogtreecommitdiff
path: root/crdt/src
diff options
context:
space:
mode:
Diffstat (limited to 'crdt/src')
-rw-r--r--crdt/src/lib.rs115
-rw-r--r--crdt/src/vector_clock.rs2
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 {