diff --git a/Cargo.lock b/Cargo.lock index 3732653a15..ce9b8bc9d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1730,6 +1730,14 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "crdb" +version = "0.1.0" +dependencies = [ + "rope", + "sum_tree", +] + [[package]] name = "crossbeam-channel" version = "0.4.4" diff --git a/Cargo.toml b/Cargo.toml index 640384a792..2a004b199c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "crates/context_menu", "crates/copilot", "crates/copilot_button", + "crates/crdb", "crates/db", "crates/diagnostics", "crates/drag_and_drop", diff --git a/crates/crdb/Cargo.toml b/crates/crdb/Cargo.toml new file mode 100644 index 0000000000..0684a94c8d --- /dev/null +++ b/crates/crdb/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "crdb" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +sum_tree = { path = "../sum_tree" } +rope = { path = "../rope" } diff --git a/crates/crdb/src/document_fragment.rs b/crates/crdb/src/document_fragment.rs new file mode 100644 index 0000000000..9a7391ef92 --- /dev/null +++ b/crates/crdb/src/document_fragment.rs @@ -0,0 +1,25 @@ +use super::DocumentFragment; +use crate::Ordering; +use rope::TextSummary; + +impl sum_tree::Item for DocumentFragment { + type Summary = DocumentFragmentSummary; + + fn summary(&self) -> Self::Summary { + todo!() + } +} + +#[derive(Clone, Default, Debug)] +pub struct DocumentFragmentSummary { + size: TextSummary, + max_id: Ordering, +} + +impl sum_tree::Summary for DocumentFragmentSummary { + type Context = (); + + fn add_summary(&mut self, summary: &Self, cxfg: &Self::Context) { + todo!() + } +} diff --git a/crates/crdb/src/lib.rs b/crates/crdb/src/lib.rs new file mode 100644 index 0000000000..2e34fc4405 --- /dev/null +++ b/crates/crdb/src/lib.rs @@ -0,0 +1,114 @@ +mod document_fragment; + +use std::{cmp::Reverse, ops::Range}; +use sum_tree::{SumTree, TreeMap}; +type OrderedMap = TreeMap; + +/// All the state +pub struct Db { + document_fragments: Sequence, + insertion_fragments: OrderedMap, +} + +#[derive(Eq, PartialEq, Clone, Default, Debug)] +struct InsertionRange { + insertion: InsertionId, + range: Range, +} + +impl Ord for InsertionRange { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.partial_cmp(other).unwrap() + } +} + +impl PartialOrd for InsertionRange { + fn partial_cmp(&self, other: &Self) -> Option { + Some( + self.insertion + .cmp(&other.insertion) + .then_with(|| self.range.start.cmp(&other.range.start)), + ) + } +} + +type Sequence = SumTree; +type DocumentFragmentId = Ordering; + +#[derive(Clone, Debug)] +pub struct DocumentFragment { + id: DocumentFragmentId, + insertion: InsertionId, + text: Rope, +} + +pub struct InsertionFragment {} + +/// A group of documents with a permissions boundary. +/// +/// This type is actually a windowed reference to `Db`. +pub struct Context {} + +/// A coherent body of editable text. +pub struct Document {} + +/// The document is identified with its creation operation. +pub type DocumentId = OperationId; + +/// A sequence of one or more characters inserted into a `Document` +pub struct Insertion { + id: OperationId, + position: Anchor, + text: Rope, +} + +/// An insertion is identified with its occurrence. +type InsertionId = OperationId; + +/// A unique identifier for a change in state applied on a given branch. +#[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq)] +pub struct OperationId { + branch: BranchId, + op_count: OperationCount, + causality: Reverse, +} + +/// Causal ordering between events produced on different branches. +type LamportTime = u64; + +/// How many operations have occurred on a given branch? +struct OperationCount(u32); + +/// Unique to each context on each installation. +struct BranchId { + context: ContextId, + installation: InstallationId, +} + +/// Assigned by our server on first connection. +type InstallationId = u32; + +/// Handed out by our server on context creation. +/// We could potentially make this amenable to distribution, +struct ContextId(UserId, ContextCount); + +/// We'll need a bigger data type before we know it. +type UserId = u32; + +/// The number of contexts created by a given user. +type ContextCount = u32; + +/// A logical "anchor point" into a document. +/// If you create an anchor to a word and its containing document +/// is subsequently edited, the anchor still resolves to the same word. +/// If the word has been deleted, the anchor resolves to the site of its tombstone. +struct Anchor { + insertion_id: InsertionId, +} + +/// A dense, totally-ordered CRDT, such as LSEQ. +#[derive(Clone, Default, Debug)] +struct Ordering {} + +/// An efficiently-editable an cloneable chunk of text. +type Rope = rope::Rope;