use thiserror::Error; use uuid::Uuid; use wasm_bindgen::prelude::*; use crate::{ doc::{ApplyOpError, Doc}, op::{CreateGrid, Op, OpKind}, vector_clock::VectorClock, }; mod doc; mod op; mod vector_clock; #[derive(Error, Debug)] pub enum Error { #[error("error while realizing state")] RealizeError(#[from] ApplyOpError), } #[wasm_bindgen] pub struct State { actor_id: Uuid, ops: Vec, } #[wasm_bindgen] impl State { #[wasm_bindgen(constructor)] pub fn new() -> Self { let actor_id = Uuid::now_v7(); Self { actor_id, ops: vec![], } } pub fn create_grid(&mut self) { self.append_op(OpKind::CreateGrid(CreateGrid { rows: 4, base_cells_per_row: 16, })); } pub fn to_json(&self) -> JsValue { let doc = self.realize().unwrap(); serde_wasm_bindgen::to_value(&doc).unwrap() } } impl State { pub fn append_op(&mut self, kind: OpKind) { let clock = self .ops .last() .map(|op| op.clock.inc(&self.actor_id)) .unwrap_or_else(|| VectorClock::new().inc(&self.actor_id)); self.ops.push(Op { id: Uuid::now_v7(), clock, kind, }); } pub fn realize(&self) -> Result { let mut doc = Doc::default(); for op in &self.ops { doc.apply_op(op)?; } Ok(doc) } } #[cfg(test)] mod tests { use crate::op::CreateGrid; use super::*; #[test] fn test() { let mut state = State::new(); state.append_op(OpKind::CreateGrid(CreateGrid { rows: 4, base_cells_per_row: 16, })); let doc = state.realize().unwrap(); let grid = doc.grids.first().unwrap(); assert_eq!(grid.rows.len(), 4); } }