summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock92
-rw-r--r--apps/web/src/components/app/index.ts11
-rw-r--r--apps/web/src/index.ts5
-rw-r--r--packages/doc/Cargo.toml1
-rw-r--r--packages/doc/package.json9
-rw-r--r--packages/doc/src/doc.rs67
-rw-r--r--packages/doc/src/lib.rs5
-rw-r--r--packages/doc/src/vector_clock.rs47
8 files changed, 160 insertions, 77 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fceb274..82a0f6b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -33,6 +33,25 @@ dependencies = [
]
[[package]]
+name = "gloo-utils"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
+dependencies = [
+ "js-sys",
+ "serde",
+ "serde_json",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
name = "js-sys"
version = "0.3.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -49,6 +68,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
[[package]]
+name = "memchr"
+version = "2.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
+
+[[package]]
name = "notive-doc"
version = "0.1.0"
dependencies = [
@@ -56,6 +81,7 @@ dependencies = [
"serde",
"serde-wasm-bindgen",
"thiserror",
+ "tsify",
"uuid",
"wasm-bindgen",
]
@@ -136,6 +162,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -177,6 +209,30 @@ dependencies = [
]
[[package]]
+name = "serde_derive_internals"
+version = "0.29.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.145"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
name = "syn"
version = "2.0.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -208,6 +264,32 @@ dependencies = [
]
[[package]]
+name = "tsify"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ec5505497c87f1c050b4392d3f11b49a04537fcb9dc0da57bc0af168a6331f2"
+dependencies = [
+ "gloo-utils",
+ "serde",
+ "serde-wasm-bindgen",
+ "serde_json",
+ "tsify-macros",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "tsify-macros"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fc2c44dc9fe4baf55b88e032621b7a11b215a1f0a7de8d0aa04367207d915bc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "serde_derive_internals",
+ "syn",
+]
+
+[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -279,6 +361,16 @@ dependencies = [
]
[[package]]
+name = "web-sys"
+version = "0.3.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
name = "wit-bindgen"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/apps/web/src/components/app/index.ts b/apps/web/src/components/app/index.ts
index a2c0c9d..63fde86 100644
--- a/apps/web/src/components/app/index.ts
+++ b/apps/web/src/components/app/index.ts
@@ -5,16 +5,23 @@ import {
changeSelectedSubdivisions,
getSelectedSubdivisionsCount,
} from "../../grid";
-import { Doc } from "../../types";
+import { Doc as LocalDoc } from "../../types";
import ntvGrid, { NotiveGridElement } from "../grid";
import renderGrid from "../grid/renderGrid";
import { GridSelection } from "../grid/selection";
import ntvToolbar from "../toolbar";
import "./index.css";
+import { State } from "@notive/doc";
+
+const state = new State();
+
+state.create_grid();
+
+console.log(state.to_json());
@customElement("ntv-app")
export class NotiveAppElement extends NotiveElement {
- doc: Doc = defaultDoc();
+ doc: LocalDoc = defaultDoc();
#selectedGridId?: string;
#selection?: GridSelection;
diff --git a/apps/web/src/index.ts b/apps/web/src/index.ts
index 857e76a..7842326 100644
--- a/apps/web/src/index.ts
+++ b/apps/web/src/index.ts
@@ -1,8 +1,3 @@
import ntvApp from "./components/app";
-import { State } from "@notive/doc";
-
-const state = new State();
-state.create_grid();
-console.log(state.to_json());
document.body.append(ntvApp());
diff --git a/packages/doc/Cargo.toml b/packages/doc/Cargo.toml
index 5e5458d..fa73380 100644
--- a/packages/doc/Cargo.toml
+++ b/packages/doc/Cargo.toml
@@ -11,5 +11,6 @@ num-rational = "0.4.2"
serde = { version = "1.0.228", features = ["derive"] }
serde-wasm-bindgen = "0.6.5"
thiserror = "2.0.17"
+tsify = { version = "0.5.6", features = ["js"] }
uuid = { version = "1.18.1", features = ["js", "v7"] }
wasm-bindgen = "0.2.105"
diff --git a/packages/doc/package.json b/packages/doc/package.json
index e251e0d..d5fc437 100644
--- a/packages/doc/package.json
+++ b/packages/doc/package.json
@@ -2,11 +2,14 @@
"name": "@notive/doc",
"private": true,
"exports": {
- ".": "dist/notive_doc.js"
+ ".": {
+ "types": "./dist/notive_doc.d.ts",
+ "default": "./dist/notive_doc.js"
+ }
},
"scripts": {
- "build": "wasm-pack build --target bundler --release --out-dir dist",
- "build:dev": "wasm-pack build --target bundler --dev --out-dir dist",
+ "build": "wasm-pack build --target bundler --release --out-dir dist --no-pack",
+ "build:dev": "wasm-pack build --target bundler --dev --out-dir dist --no-pack",
"clean": "rm -rf dist",
"dev": "cargo watch -i dist -s 'pnpm build:dev'"
},
diff --git a/packages/doc/src/doc.rs b/packages/doc/src/doc.rs
index fcca1d8..22ef703 100644
--- a/packages/doc/src/doc.rs
+++ b/packages/doc/src/doc.rs
@@ -1,14 +1,17 @@
use serde::{Deserialize, Serialize};
use thiserror::Error;
+use tsify::Tsify;
use uuid::Uuid;
use crate::op::{ChangeSubdivisions, CreateGrid, Op, OpKind};
/// An deterministically derived ID, e.g. a grid ID derived from the
/// op ID which creates it.
+#[derive(Tsify)]
+#[tsify(type = "string")]
pub struct DerivedId {
base: String,
- tag: &'static str,
+ tag: String,
index: usize,
}
@@ -19,24 +22,24 @@ impl ToString for DerivedId {
}
trait DerivableId {
- fn derive_id(&self, tag: &'static str, index: usize) -> DerivedId;
+ fn derive_id(&self, tag: &str, index: usize) -> DerivedId;
}
impl DerivableId for Uuid {
- fn derive_id(&self, tag: &'static str, index: usize) -> DerivedId {
+ fn derive_id(&self, tag: &str, index: usize) -> DerivedId {
DerivedId {
base: self.to_string(),
- tag,
+ tag: tag.to_string(),
index,
}
}
}
impl DerivableId for DerivedId {
- fn derive_id(&self, tag: &'static str, index: usize) -> DerivedId {
+ fn derive_id(&self, tag: &str, index: usize) -> DerivedId {
DerivedId {
base: self.to_string(),
- tag,
+ tag: tag.to_string(),
index,
}
}
@@ -51,26 +54,56 @@ impl Serialize for DerivedId {
}
}
-#[derive(Default, Serialize)]
+impl<'de> Deserialize<'de> for DerivedId {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ let s = String::deserialize(deserializer)?;
+ let parts: Vec<&str> = s.split(':').collect();
+ if parts.len() != 2 {
+ return Err(serde::de::Error::custom("Invalid DerivedId format"));
+ }
+
+ let base = parts[0].to_string();
+ let tag_index: Vec<&str> = parts[1].split('=').collect();
+ if tag_index.len() != 2 {
+ return Err(serde::de::Error::custom("Invalid DerivedId format"));
+ }
+
+ let tag = tag_index[0].to_string();
+ let index = tag_index[1]
+ .parse()
+ .map_err(|_| serde::de::Error::custom("Invalid index"))?;
+
+ Ok(DerivedId { base, tag, index })
+ }
+}
+
+#[derive(Default, Serialize, Deserialize, Tsify)]
+#[tsify(into_wasm_abi)]
pub struct Doc {
- pub(crate) grids: Vec<Grid>,
+ pub grids: Vec<Grid>,
}
-#[derive(Serialize)]
+#[derive(Serialize, Deserialize, Tsify)]
+#[tsify(into_wasm_abi)]
pub struct Grid {
- pub(crate) id: DerivedId,
- pub(crate) rows: Vec<Row>,
+ pub id: DerivedId,
+ pub rows: Vec<Row>,
}
-#[derive(Serialize)]
+#[derive(Serialize, Deserialize, Tsify)]
+#[tsify(into_wasm_abi)]
pub struct Row {
- pub(crate) id: DerivedId,
- pub(crate) cells: Vec<Cell>,
+ pub id: DerivedId,
+ pub cells: Vec<Cell>,
}
-#[derive(Serialize)]
+#[derive(Serialize, Deserialize, Tsify)]
+#[tsify(into_wasm_abi)]
pub struct Cell {
- pub(crate) id: DerivedId,
+ pub id: DerivedId,
}
#[derive(Error, Debug)]
@@ -109,6 +142,6 @@ fn apply_create_grid(doc: &mut Doc, op_id: &Uuid, data: &CreateGrid) -> ApplyOpR
Ok(())
}
-fn apply_change_subdivisions(doc: &mut Doc, data: &ChangeSubdivisions) -> ApplyOpResult {
+fn apply_change_subdivisions(_doc: &mut Doc, _data: &ChangeSubdivisions) -> ApplyOpResult {
todo!()
}
diff --git a/packages/doc/src/lib.rs b/packages/doc/src/lib.rs
index a1d7497..93c008a 100644
--- a/packages/doc/src/lib.rs
+++ b/packages/doc/src/lib.rs
@@ -43,9 +43,8 @@ impl State {
}));
}
- pub fn to_json(&self) -> JsValue {
- let doc = self.realize().unwrap();
- serde_wasm_bindgen::to_value(&doc).unwrap()
+ pub fn to_json(&self) -> Doc {
+ self.realize().unwrap()
}
}
diff --git a/packages/doc/src/vector_clock.rs b/packages/doc/src/vector_clock.rs
index f6ded56..5e0b669 100644
--- a/packages/doc/src/vector_clock.rs
+++ b/packages/doc/src/vector_clock.rs
@@ -22,11 +22,6 @@ impl VectorClock {
m.insert(actor_id.clone(), self.get(actor_id) + 1);
VectorClock(m)
}
-
- /// Returns true if this clock is concurrent with another (neither happens before the other)
- pub fn is_concurrent_with(&self, other: &VectorClock) -> bool {
- self.partial_cmp(other).is_none()
- }
}
impl PartialOrd for VectorClock {
@@ -111,46 +106,4 @@ mod tests {
assert!(!(clock_a > clock_b));
assert!(!(clock_a < clock_b));
}
-
- #[test]
- fn concurrent_clocks() {
- let alice_id = Uuid::now_v7();
- let bob_id = Uuid::now_v7();
- let carol_id = Uuid::now_v7();
-
- // Equal clocks are not concurrent
- let clock1 = VectorClock::new();
- let clock2 = VectorClock::new();
- assert!(!clock1.is_concurrent_with(&clock2));
-
- // Causally ordered clocks are not concurrent
- let clock_before = VectorClock::new().inc(&alice_id);
- let clock_after = VectorClock::new().inc(&alice_id).inc(&bob_id);
- assert!(!clock_before.is_concurrent_with(&clock_after));
- assert!(!clock_after.is_concurrent_with(&clock_before));
-
- // Clocks from different actors are concurrent
- let alice_clock = VectorClock::new().inc(&alice_id);
- let bob_clock = VectorClock::new().inc(&bob_id);
- assert!(alice_clock.is_concurrent_with(&bob_clock));
- assert!(bob_clock.is_concurrent_with(&alice_clock));
-
- // Complex concurrent case: diverged branches
- let clock_a = VectorClock::new()
- .inc(&alice_id)
- .inc(&alice_id)
- .inc(&bob_id)
- .inc(&carol_id);
-
- let clock_b = VectorClock::new()
- .inc(&alice_id)
- .inc(&alice_id)
- .inc(&bob_id)
- .inc(&bob_id);
-
- // clock_a: {alice: 2, bob: 1, carol: 1}
- // clock_b: {alice: 2, bob: 2}
- // carol: 1 > 0, but bob: 1 < 2 → concurrent
- assert!(clock_a.is_concurrent_with(&clock_b));
- }
}