### OpLog: Create New OpLog Instance Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.OpLog Constructs a new, empty OpLog. This is the starting point for managing operations and document versions. ```rust pub fn new() -> Self ``` -------------------------------- ### Rust: Initialize and Write Start Branch Data Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/encoding/encode_oplog.rs Initializes and writes data for the start branch, conditionally including local version information and content. It handles the case where the local version is root and optionally stores branch content based on configuration. ```Rust // TODO: Support partial data sets. (from_frontier) let mut start_branch = Vec::new(); // If the local version is root, start_branch is just an empty chunk. if !local_version_is_root(from_version) { // This will skip writing the version if from_version is ROOT. write_local_version(&mut start_branch, from_version, &mut agent_mapping, self); if opts.store_start_branch_content { let branch_here = Branch::new_at_local_version(self, from_version); // dbg!(&branch_here); write_content_rope(&mut start_branch, &branch_here.content, compress_bytes.as_mut()); } } // dbg!(&start_branch); ``` -------------------------------- ### OpLog: Get All Transformed Operations from the Start Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/merge/merge.rs A convenience method to get an iterator over all transformed operations from the beginning of time. It is a shorthand for calling `iter_xf_operations_from` with empty `from` and `merging` slices corresponding to the OpLog's local version. ```rust impl OpLog { pub fn iter_xf_operations(&self) -> impl Iterator)> + '_ { self.iter_xf_operations_from(&[], &self.version) } } ``` -------------------------------- ### Create a New Branch (Rust) Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.Branch Provides methods to create new Branch instances. `new()` creates an empty branch at the start of history. `new_at_local_version()` creates a branch as a checkout from a specified oplog version. `new_at_tip()` creates a branch by merging all changes from the oplog into a single view. ```rust pub fn new() -> Self pub fn new_at_local_version(oplog: &OpLog, version: &[Time]) -> Self pub fn new_at_tip(oplog: &OpLog) -> Self ``` -------------------------------- ### ListCRDT Structure in Rust Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/mod.rs A helper structure that combines an OpLog and a Branch to simplify document editing. It's the recommended API for getting started with diamond types. ```Rust /// This is a simple helper structure which wraps an [`OpLog`](OpLog) and [`Branch`](Branch) /// together into a single structure to make edits easy. /// /// When getting started with diamond types, this is the API you probably want to use. /// /// The times you don't want to use a ListCRDT: /// /// - Nodes often don't care about the current document state. If you're using DT in a context /// where you're mostly just passing patches around and you don't actually need a live copy of the /// document state, just use an OpLog. You can always call [`oplog.checkout()`](OpLog::checkout) /// to figure out what the document looks like at any specified moment in time. /// - If you're interacting with a document with multiple branches, you'll probably want to /// instantiate the oplog (and any visible branches) separately. #[derive(Debug, Clone)] pub struct ListCRDT { pub branch: Branch, pub oplog: OpLog, } ``` -------------------------------- ### OpLog Sequence Number Consumption Example (Rust) Source: https://docs.rs/diamond-types/latest/diamond_types/index Highlights how Diamond types consumes sequence numbers for CRDT operations. It demonstrates that individual inserts/deletes increment sequence numbers, and aggressive run-length encoding is used internally. This example contrasts adding characters one by one versus adding them all at once. ```rust use diamond_types::list::*; let mut oplog = OpLog::new(); let fred = oplog.get_or_create_agent_id("fred"); // Adding characters individually oplog.add_insert(fred, 0, "a"); oplog.add_insert(fred, 1, "b"); oplog.add_insert(fred, 2, "c"); // This produces an identical OpLog to: // let mut oplog = OpLog::new(); // let fred = oplog.get_or_create_agent_id("fred"); // oplog.add_insert(fred, 0, "abc"); ``` -------------------------------- ### Create and Initialize a Branch from OpLog (Rust) Source: https://docs.rs/diamond-types/latest/diamond_types/index Illustrates how to create a new branch from an OpLog at its latest version or a specific local version. It shows the usage of `Branch::new_at_tip` and `Branch::new_at_local_version`. ```rust use diamond_types::list::*; let mut oplog = OpLog::new(); // ... assuming oplog is populated // Create a branch at the tip of the oplog let mut branch = Branch::new_at_tip(&oplog); // Equivalent to creating a branch at a specific local version // let mut branch = Branch::new_at_local_version(&oplog, oplog.get_local_version()); println!("branch content {}", branch.content().to_string()); ``` -------------------------------- ### Get Cursor After Specified Time (Rust) Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/merge/merge.rs Retrieves a cursor positioned after a given time marker. It handles the case where the time is usize::MAX by returning a cursor at the start. Otherwise, it finds a marker and positions the cursor before the item, adjusting it based on the `stick_end` flag. ```rust fn get_cursor_after(&self, time: Time, stick_end: bool) -> Cursor { if time == usize::MAX { self.range_tree.cursor_at_start() } else { let marker = self.marker_at(time); let mut cursor = self.range_tree.cursor_before_item(time, marker); cursor.offset += 1; if !stick_end { cursor.roll_to_next_entry(); } cursor } } ``` -------------------------------- ### Branch Initialization Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.Branch Methods for creating new Branch instances. ```APIDOC ## Branch Initialization ### `new()` Creates a new (empty) branch at the start of history. The branch will be an empty list. #### Method `pub fn new() -> Self` ### `new_at_local_version(oplog: &OpLog, version: &[Time]) -> Self` Creates a new branch as a checkout from the specified oplog, at the specified local time. This method is equivalent to calling `oplog.checkout(version)`. #### Method `pub fn new_at_local_version(oplog: &OpLog, version: &[Time]) -> Self` #### Parameters * `oplog` (&OpLog) - The OpLog to checkout from. * `version` (&[Time]) - The local time version to checkout. ### `new_at_tip(oplog: &OpLog) -> Self` Creates a new branch as a checkout from the specified oplog by merging all changes into a single view of time. This method is equivalent to calling `oplog.checkout_tip()`. #### Method `pub fn new_at_tip(oplog: &OpLog) -> Self` #### Parameters * `oplog` (&OpLog) - The OpLog to checkout from. ``` -------------------------------- ### Get Optimized Transactions Between Time Ranges (Rust) Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/merge/txn_trace.rs Retrieves an iterator for transactions that fall between two specified time ranges. This method first computes the difference between the 'from' and 'to' time slices and then initializes a SpanningTreeWalker with the relevant transactions and the starting time. ```rust pub(crate) fn optimized_txns_between(&self, from: &[Time], to: &[Time]) -> SpanningTreeWalker { let (_a, txns) = self.diff(from, to); // _a might always be empty. SpanningTreeWalker::new(self, &txns, from.into()) } ``` -------------------------------- ### OperationInternal Struct Definition and Methods - Rust Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/internal_op.rs Defines the OperationInternal struct, which holds metadata for an operation like its location, kind (insert/delete), and content position. It includes methods to get the start and end of the operation span, retrieve associated content from an OpLog, and convert to a higher-level Operation struct. This struct is designed for efficient storage and manipulation of change information. ```rust use rle::{HasLength, MergableSpan, SplitableSpan, SplitableSpanCtx}; use crate::list::operation::{OpKind, Operation}; use crate::list::operation::OpKind::*; use crate::list::{OpLog, switch}; use crate::dtrange::DTRange; use crate::rev_range::RangeRev; use crate::unicount::chars_to_bytes; /// This is an internal structure for passing around information about a change. Notably the content /// of the change is not stored here - but is instead stored in a contiguous array in the oplog /// itself. This has 2 benefits: /// /// - Speed / size improvements. The number of items each operation references varies wildly, and /// storing the content itself in a block in the oplog keeps fragmentation down. /// - This makes supporting other data types much easier - because there's a lot of code which /// needs to adapt to the content type itself. /// /// Note that OperationInternal can't directly implement #[derive(Debug, Clone, Eq, PartialEq)] pub(crate) struct OperationInternal { /// The span of content which is inserted or deleted. /// /// For inserts, this describes the resulting location (span) of the new characters. /// For deletes, this names the range of the set of characters deleted. /// /// This span is reversible. The span.rev tag specifies if the span is reversed chronologically. /// That is, characters are inserted or deleted in the reverse order chronologically. pub loc: RangeRev, /// Is this an insert or delete? pub kind: OpKind, /// Byte range in self.ins_content or del_content where our content is being held. This is /// essentially a poor man's pointer. /// /// Note this stores a *byte offset*. pub content_pos: Option, } impl OperationInternal { #[inline] pub fn start(&self) -> usize { self.loc.span.start } #[inline] pub fn end(&self) -> usize { self.loc.span.end } pub(crate) fn get_content<'a>(&self, oplog: &'a OpLog) -> Option<&'a str> { self.content_pos.map(|span| { oplog.operation_ctx.get_str(self.kind, span) }) } pub(crate) fn to_operation(&self, oplog: &OpLog) -> Operation { let content = self.get_content(oplog); (self, content).into() } } impl HasLength for OperationInternal { fn len(&self) -> usize { self.loc.len() } } ``` -------------------------------- ### Branch Creation and Initialization Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/branch.rs Methods for creating new `Branch` instances. `new()` creates an empty branch, while `new_at_local_version` and `new_at_tip` allow checking out specific states from an `OpLog`. ```rust impl Branch { /// Create a new (empty) branch at the start of history. The branch will be an empty list. pub fn new() -> Self { Self { version: smallvec![], content: JumpRope::new(), } } /// Create a new branch as a checkout from the specified oplog, at the specified local time. /// This method equivalent to calling [`oplog.checkout(version)`](OpLog::checkout). pub fn new_at_local_version(oplog: &OpLog, version: &[Time]) -> Self { oplog.checkout(version) } /// Create a new branch as a checkout from the specified oplog by merging all changes into a /// single view of time. This method equivalent to calling /// [`oplog.checkout_tip()`](OpLog::checkout_tip). pub fn new_at_tip(oplog: &OpLog) -> Self { oplog.checkout_tip() } } ``` -------------------------------- ### Create and Initialize a Branch from OpLog (Rust) Source: https://docs.rs/diamond-types/latest/diamond_types Illustrates the creation of a new branch from an existing OpLog. This involves initializing a branch at the current tip of the oplog or a specific local version. The branch's content can then be accessed. ```rust use diamond_types::list::*; let mut oplog = OpLog::new(); // ... operations added to oplog ... let mut branch = Branch::new_at_tip(&oplog); // Equivalent to: let mut branch = Branch::new_at_local_version(&oplog, oplog.get_local_version()); println!("branch content {}", branch.content().to_string()); ``` -------------------------------- ### Format DTRange Time Span in Rust Source: https://docs.rs/diamond-types/latest/src/diamond_types/dtrange.rs Implements the Debug trait for the DTRange struct, formatting it as 'T start..end'. It uses debug_time_raw to format the start and end times. ```rust impl Debug for DTRange { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "T ")?; debug_time_raw(self.start, |v| v.fmt(f) )?; write!(f, "..")?; debug_time_raw(self.end, |v| v.fmt(f) )?; Ok(()) } } ``` -------------------------------- ### OpLog: Create Latest Document Snapshot Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.OpLog Creates a snapshot of the document's state at its most recent version (tip). ```rust pub fn checkout_tip(&self) -> Branch ``` -------------------------------- ### Operation Accessor Methods in diamond-types Source: https://docs.rs/diamond-types/latest/diamond_types/list/operation/struct.Operation These methods provide convenient ways to access information about an 'Operation'. 'range' returns the modified range, 'start' returns the starting position of the modification, 'end' returns the ending position, and 'content_as_str' provides the operation's content as a string slice if available. ```rust pub fn range(&self) -> DTRange ``` ```rust pub fn start(&self) -> usize ``` ```rust pub fn end(&self) -> usize ``` ```rust pub fn content_as_str(&self) -> Option<&str> ``` -------------------------------- ### AgentMapping Initialization and Agent Mapping Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/encoding/encode_oplog.rs Manages the mapping of oplog agent IDs to file-based agent IDs, supporting agent IDs that may jump around. It initializes the mapping structure and provides a method to map an agent ID, assigning new IDs as needed and recording client data names. Dependencies include `OpLog`, `AgentId`, and `ROOT_AGENT`. ```rust struct AgentMapping { /// Map from oplog's agent ID to the agent id in the file. Paired with the last assigned agent /// ID, to support agent IDs bouncing around. map: Vec>, next_mapped_agent: AgentId, output: Vec, } impl AgentMapping { fn new(oplog: &OpLog) -> Self { let client_len = oplog.client_data.len(); let mut result = Self { map: Vec::with_capacity(client_len), next_mapped_agent: 1, // 0 is implicitly assigned to ROOT. output: Vec::new() }; result.map.resize(client_len, None); result } fn map(&mut self, oplog: &OpLog, agent: AgentId) -> AgentId { // 0 is implicitly ROOT. if agent == ROOT_AGENT { return 0; } let agent = agent as usize; self.map[agent].map_or_else(|| { let mapped = self.next_mapped_agent; self.map[agent] = Some((mapped, 0)); push_str(&mut self.output, oplog.client_data[agent].name.as_str()); // println!("Mapped agent {} -> {}", oplog.client_data[agent].name, mapped); self.next_mapped_agent += 1; mapped }, |v| v.0) } fn seq_delta(&mut self, agent: AgentId, span: DTRange) -> isize { let item = self.map[agent as usize].as_mut().unwrap(); let old_seq = item.1; item.1 = span.end; (span.start as isize) - (old_seq as isize) } fn consume(self) -> Vec { self.output } } ``` -------------------------------- ### DTRange Struct Definition and Core Methods (Rust) Source: https://docs.rs/diamond-types/latest/src/diamond_types/dtrange.rs Defines the `DTRange` struct, a `Copy` and `Clone` type representing a range with `start` and `end` usize values. It includes methods for creating ranges, consuming starts, accessing ends, checking containment, emptiness, intersection, and comparison with `Time` objects. ```rust /// This is an internal replacement for Range. The main use for this is that std::Range /// doesn't implement Copy (urgh), and we need that for lots of types. But ultimately, this is just /// a start and end pair. DTRange can be converted to and from std::Range with .from() and .into(). /// It also has some locally useful methods. #[derive(Copy, Clone, Eq, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize)), serde(crate="serde_crate", from = "DTRangeTuple", into = "DTRangeTuple"))] pub struct DTRange { pub start: usize, pub end: usize } implement DTRange { #[inline] pub fn new(start: usize, end: usize) -> DTRange { DTRange { start, end } } #[inline] pub fn new_from_len(start: usize, len: usize) -> DTRange { DTRange { start, end: start + len } } pub fn consume_start(&mut self, amt: usize) { self.start += amt; } pub fn end(&self) -> usize { self.end } pub fn last(&self) -> usize { self.end - 1 } pub fn contains(&self, item: usize) -> bool { self.start <= item && item < self.end } pub fn is_empty(&self) -> bool { debug_assert!(self.start <= self.end); self.start == self.end } pub fn intersect(&self, other: &Self) -> Option { let result = DTRange { start: self.start.max(other.start), end: self.end.min(other.end), }; if result.start <= result.end { Some(result) } else { None } } pub fn partial_cmp_time(&self, time: Time) -> Ordering { if time < self.start { Ordering::Less } else if time >= self.end { Ordering::Greater } else { Ordering::Equal } } pub fn iter(&self) -> impl Iterator { Range::::from(self) } } ``` -------------------------------- ### ListCRDT Initialization Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.ListCRDT Methods for creating and loading ListCRDT instances. ```APIDOC ## ListCRDT Initialization ### `new()` Creates a new, empty `ListCRDT`. #### Method `pub fn new() -> Self` ### `load_from()` Loads a `ListCRDT` from a byte slice. #### Method `pub fn load_from(bytes: &[u8]) -> Result` #### Parameters - **bytes** (`&[u8]`) - The byte slice containing the serialized `ListCRDT` data. #### Returns - `Result` - `Ok(Self)` if the data is successfully parsed. - `Err(ParseError)` if parsing fails. ``` -------------------------------- ### Get Element at Index with Offset in Rust Source: https://docs.rs/diamond-types/latest/src/diamond_types/rle/rle_vec.rs The `get` method allows retrieving an element from the RleVec at a specific index `idx`. It utilizes `find_with_offset` to locate the relevant RLE entry and its offset within that entry. The method then returns the item at the calculated offset within the found entry. It panics if the index is out of bounds. ```rust impl RleVec { pub fn get(&self, idx: usize) -> V::Item { let (v, offset) = self.find_with_offset(idx).unwrap(); v.at_offset(offset) } } ``` -------------------------------- ### OpLog Trait Implementations Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.OpLog Documentation for standard trait implementations for the OpLog struct, including Clone, Debug, Default, and PartialEq. ```APIDOC ## Trait Implementations for OpLog ### impl Clone for OpLog #### fn clone(&self) -> OpLog Returns a duplicate of the value. #### fn clone_from(&mut self, source: &Self) Performs copy-assignment from `source`. ### impl Debug for OpLog #### fn fmt(&self, f: &mut Formatter<'_>) -> Result Formats the value using the given formatter. ### impl Default for OpLog #### fn default() -> Self Returns the “default value” for a type. ### impl PartialEq for OpLog #### fn eq(&self, other: &Self) -> bool Tests for `self` and `other` values to be equal. #### fn ne(&self, other: &Rhs) -> bool Tests for `!=`. ``` -------------------------------- ### OpLog: Get Agent Name Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.OpLog Retrieves the string name associated with a given Agent ID. ```rust pub fn get_agent_name(&self, agent: AgentId) -> &str ``` -------------------------------- ### Initialize Compression and Content Storage Buffers Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/encoding/encode_oplog.rs Initializes buffers for compressed data, inserted content, and deleted content based on provided options and feature flags. Compression is enabled only if `opts.compress_content` is true and the `lz4` feature is enabled. Content storage is conditionally initialized based on `opts.store_inserted_content` and `opts.store_deleted_content`. ```rust let mut compress_bytes = if opts.compress_content && cfg!(feature = "lz4") { Some(Vec::new()) } else { None }; let mut inserted_content = if opts.store_inserted_content { Some(ContentChunk::new(write_bit_run, Ins)) } else { None }; let mut deleted_content = if opts.store_deleted_content { Some(ContentChunk::new(write_bit_run, Del)) } else { None }; ``` -------------------------------- ### OpLog: Get Operation Count Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.OpLog Returns the total number of operations currently stored within the OpLog. ```rust pub fn len(&self) -> usize ``` -------------------------------- ### Process StartBranch and Content Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/encoding/decode_oplog.rs Reads the StartBranch chunk, which may contain the document's initial version and content. It parses the version and handles potential compressed content, although the content itself is not yet utilized. This step is crucial for understanding the document's state at the time of the branch. ```Rust let mut start_branch = reader.expect_chunk(ChunkType::StartBranch)?.chunks(); let start_version = start_branch.read_version(self, &agent_map)?; if !start_branch.is_empty() { let _start_content = start_branch.expect_content_str(compressed_chunk.as_mut())?; } ``` -------------------------------- ### OpLog: Iterate Operations Since Version Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.OpLog Returns an iterator over operations starting from a specified historical point (local version). ```rust pub fn iter_range_since( &self, local_version: &[Time], ) -> impl Iterator + '_ ``` -------------------------------- ### History Struct and Traversal Planning (Rust) Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/merge/txn_trace.rs This snippet shows the beginning of the `History` struct implementation, specifically a method (likely a constructor or helper function) designed for efficiently planning the traversal order of a time-based Directed Acyclic Graph (DAG). This is crucial for optimizing operations like saving changes to disk. ```rust impl History { /// This function is for efficiently finding the order we should traverse the time DAG in order to /// walk all the changes so we can efficiently save everything to disk. This is needed because if /// we simply traverse the txns in the order they're in right now, we can have pathological // ... rest of the implementation ... } ``` -------------------------------- ### OpLog: Create Document Snapshot (Branch) Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.OpLog Creates a snapshot (branch) of the document's state at a specific historical point identified by `local_version`. ```rust pub fn checkout(&self, local_version: &[Time]) -> Branch ``` -------------------------------- ### OpLog: Iterate Transformed Operations From Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.OpLog Returns an iterator over transformed operations starting from a specific historical point. This is useful for applying changes to a local document state. ```rust pub fn iter_xf_operations_from( &self, from: &[Time], merging: &[Time], ) -> impl Iterator)> + '_ ``` -------------------------------- ### SpanningTreeWalker Initialization and Child Processing (Rust) Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/merge/txn_trace.rs This snippet covers the `new` constructor for SpanningTreeWalker and the `push_children` method. The constructor initializes the walker with history, frontier, input, and a list of transactions to process. `push_children` adds new child transaction indices to the processing queue, ensuring they are considered in the traversal. ```rust impl<'a> SpanningTreeWalker<'a> { // ... constructor and other methods ... fn push_children(&mut self, child_txn_idxs: &[usize]) { // self.to_process.extend(... ?) // TODO: Consider removing .rev() here. I think its faster without it. for idx in child_txn_idxs.iter().rev() { let txn = &self.history.entries[*idx]; if let Some(i) = find_entry_idx(&self.input, txn.span.start) { self.to_process.push(i); } } } // ... other methods ... } ``` -------------------------------- ### Get Length of Operations (Rust) Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/oplog.rs Returns the total number of operations currently stored in the CRDT. It checks the last entry in `client_with_localtime` to determine the length. ```rust pub fn len(&self) -> usize { if let Some(last) = self.client_with_localtime.last() { last.end() } else { 0 } } ``` -------------------------------- ### Branch Version and Content Access (Rust) Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.Branch These methods allow access to the branch's version information and its content. `local_version_ref()` returns a reference to the current version, while `local_version()` returns the version. `remote_version()` provides the version in a remote format. `content()` returns the document's content as a JumpRope, and `len()` and `is_empty()` provide information about the content's length. ```rust pub fn local_version_ref(&self) -> &[Time] pub fn local_version(&self) -> LocalVersion pub fn remote_version(&self, oplog: &OpLog) -> SmallVec<[RemoteId; 4]> pub fn content(&self) -> &JumpRope pub fn len(&self) -> usize pub fn is_empty(&self) -> bool ``` -------------------------------- ### Operation Creation and Application Helpers Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/branch.rs Methods for creating delete operations and applying local changes. `make_delete_op` creates a delete operation with content, while `apply_local_operations`, `insert`, `delete_without_content`, and `delete` provide higher-level interfaces for applying operations through the `OpLog`. ```rust impl Branch { pub fn make_delete_op(&self, loc: Range) -> Operation { assert!(loc.end <= self.content.len_chars()); let mut s = SmartString::new(); s.extend(self.content.slice_chars(loc.clone())); Operation::new_delete_with_content_range(loc, s) } pub fn apply_local_operations(&mut self, oplog: &mut OpLog, agent: AgentId, ops: &[Operation]) -> Time { apply_local_operation(oplog, self, agent, ops) } pub fn insert(&mut self, oplog: &mut OpLog, agent: AgentId, pos: usize, ins_content: &str) -> Time { apply_local_operation(oplog, self, agent, &[Operation::new_insert(pos, ins_content)]) } pub fn delete_without_content(&mut self, oplog: &mut OpLog, agent: AgentId, loc: Range) -> Time { apply_local_operation(oplog, self, agent, &[Operation::new_delete(loc)]) } pub fn delete(&mut self, oplog: &mut OpLog, agent: AgentId, del_span: Range) -> Time { apply_local_operation(oplog, self, agent, &[self.make_delete_op(del_span)]) } #[cfg(feature = "wchar_conversion")] ``` -------------------------------- ### ListCRDT Structure Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.ListCRDT The ListCRDT structure is a helper that combines an OpLog and a Branch for easier document editing. It's the recommended starting point for most diamond types use cases. ```APIDOC ## Struct ListCRDT ### Description This is a simple helper structure which wraps an `OpLog` and `Branch` together into a single structure to make edits easy. When getting started with diamond types, this is the API you probably want to use. ### Fields - **branch** (`Branch`) - The branch component of the document. - **oplog** (`OpLog`) - The operation log component of the document. ``` -------------------------------- ### ListCRDT Struct Definition - Rust Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.ListCRDT Defines the ListCRDT structure, which bundles an OpLog and a Branch for simplified document editing. This is the primary API recommended for most users starting with diamond types. ```rust pub struct ListCRDT { pub branch: Branch, pub oplog: OpLog, } ``` -------------------------------- ### Simple Encoding Test in Rust Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/encoding/encode_oplog.rs This test focuses on a simple encoding scenario. It creates an OpLog, adds an agent, inserts text, and then calls the `encode` function. This snippet highlights the basic usage of the library's encoding capabilities. The test is currently commented out. ```rust #[test] fn encode_simple() { let mut oplog = OpLog::new(); oplog.get_or_create_agent_id("x"); // 0 oplog.add_insert(0, 0, "abc\n"); // let data = oplog.encode(EncodeOptions::default()); } ``` -------------------------------- ### Branch Version and Content Access Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/branch.rs Methods to retrieve the current version of the branch and its content. `local_version_ref` provides a reference to the version, `local_version` returns a clone, `remote_version` converts it to a remote format, and `content` returns the document's content as a `JumpRope`. ```rust impl Branch { /// Return the current version of the branch as a `&[usize]`. /// /// This is provided because its slightly faster than calling local_version (since it prevents a /// clone(), and they're weirdly expensive with smallvec!) pub fn local_version_ref(&self) -> &[Time] { &self.version } /// Return the current version of the branch pub fn local_version(&self) -> LocalVersion { clone_smallvec(&self.version) } /// Return the current version of the branch in remote form pub fn remote_version(&self, oplog: &OpLog) -> SmallVec<[RemoteId; 4]> { oplog.local_to_remote_version(&self.version) } /// Return the current document contents. Note there is no mutable variant of this method /// because mutating the document's content directly would violate the constraint that all /// changes must bump the document's version. pub fn content(&self) -> &JumpRope { &self.content } } ``` -------------------------------- ### RangeRev Length and Truncation (Rust) Source: https://docs.rs/diamond-types/latest/src/diamond_types/rev_range.rs Implements the `HasLength` trait for `RangeRev` to get its length. Also provides the `truncate_h` method from `SplitableSpanHelpers`, which correctly truncates the span based on its forward or backward direction. ```rust impl HasLength for RangeRev { fn len(&self) -> usize { self.span.len() } } impl SplitableSpanHelpers for RangeRev { fn truncate_h(&mut self, at: usize) -> Self { RangeRev { span: if self.fwd { self.span.truncate(at) } else { self.span.truncate_keeping_right(self.len() - at) }, fwd: self.fwd, } } } ``` -------------------------------- ### OpLog: Get or Create Agent ID Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.OpLog Retrieves an existing Agent ID for a given name or creates a new one if it doesn't exist. Agent IDs are used to identify the source of operations. ```rust pub fn get_or_create_agent_id(&mut self, name: &str) -> AgentId ``` -------------------------------- ### OpLog Initialization and Branch Checkout in Rust Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/oplog.rs Defines the default implementation for `OpLog` and provides methods to checkout branches based on local versions or the tip of the operation log. It uses `Branch::new()` and `branch.merge()` for these operations. ```rust impl Default for OpLog { fn default() -> Self { Self::new() } } impl OpLog { pub fn new() -> Self { Self { doc_id: None, client_with_localtime: RleVec::new(), client_data: vec![], operation_ctx: OperationCtx::new(), operations: Default::default(), // inserted_content: "".to_string(), history: Default::default(), version: smallvec![] } } pub fn checkout(&self, local_version: &[Time]) -> Branch { let mut branch = Branch::new(); branch.merge(self, local_version); branch } pub fn checkout_tip(&self) -> Branch { let mut branch = Branch::new(); branch.merge(self, &self.version); branch } } ``` -------------------------------- ### HistoryEntry Methods: parent_at_time and with_parents (Rust) Source: https://docs.rs/diamond-types/latest/src/diamond_types/history.rs Implements `parent_at_time` to get the parent transaction at a specific time and `with_parents` to execute a closure with the parent transactions. These methods help navigate the transaction history. ```rust impl HistoryEntry { pub fn parent_at_time(&self, time: usize) -> Option { if time > self.span.start { Some(time - 1) } else { None } // look at .parents field. } pub fn with_parents G, G>(&self, time: usize, f: F) -> G { if time > self.span.start { f(&[time - 1]) } else { f(self.parents.as_slice()) } } // ... other methods omitted for brevity ``` -------------------------------- ### Rust Blanket Implementations: Any, Borrow, and CloneToUninit Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.Branch Demonstrates blanket implementations in Rust for the 'Any', 'Borrow', and 'CloneToUninit' traits. These are applied generically to any type 'T', providing functionalities such as retrieving a type's ID, immutable borrowing, and unsafe raw pointer manipulation for cloning into uninitialized memory. Note that 'clone_to_uninit' is an experimental nightly-only API. ```rust impl Any for T where T: 'static + ?Sized, { fn type_id(&self) -> TypeId } impl Borrow for T where T: ?Sized, { fn borrow(&self) -> &T } impl BorrowMut for T where T: ?Sized, { fn borrow_mut(&mut self) -> &mut T } impl CloneToUninit for T where T: Clone, { unsafe fn clone_to_uninit(&self, dest: *mut u8) } ``` -------------------------------- ### Generic Trait Implementations Source: https://docs.rs/diamond-types/latest/diamond_types/list/struct.OpLog Documentation for generic trait implementations that apply to various types, including OpLog. ```APIDOC ## Blanket Implementations ### impl Any for T #### fn type_id(&self) -> TypeId Gets the `TypeId` of `self`. ### impl Borrow for T #### fn borrow(&self) -> &T Immutably borrows from an owned value. ### impl BorrowMut for T #### fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. ### impl CloneToUninit for T #### unsafe fn clone_to_uninit(&self, dest: *mut u8) Performs copy-assignment from `self` to `dest` (Nightly-only). ### impl From for T #### fn from(t: T) -> T Returns the argument unchanged. ### impl Into for T #### fn into(self) -> U Calls `U::from(self)`. ### impl ToOwned for T #### type Owned = T The resulting type after obtaining ownership. #### fn to_owned(&self) -> T Creates owned data from borrowed data, usually by cloning. #### fn clone_into(&self, target: &mut T) Uses borrowed data to replace owned data, usually by cloning. ### impl TryFrom for T #### type Error = Infallible The type returned in the event of a conversion error. #### fn try_from(value: U) -> Result>::Error> Performs the conversion. ### impl TryInto for T #### type Error = >::Error The type returned in the event of a conversion error. #### fn try_into(self) -> Result>::Error> Performs the conversion. ### impl VZip for T #### fn vzip(self) -> V ``` -------------------------------- ### CRDT List Concurrent Insert Test Setup Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/merge/merge.rs Sets up a scenario for testing concurrent insert operations in the ListCRDT. It involves creating agents and adding insert operations from each agent to the operation log. ```Rust #[test] fn test_concurrent_insert() { let mut list = ListCRDT::new(); list.get_or_create_agent_id("a"); list.get_or_create_agent_id("b"); list.oplog.add_insert_at(0, &[], 0, "aaa"); list.oplog.add_insert_at(1, &[], 0, "bbb"); let mut t = M2Tracker::new(); ``` -------------------------------- ### Rust: Write Initial File Header and Compressed Fields Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/encoding/encode_oplog.rs Writes the initial file header, including magic bytes and protocol version, followed by the CompressedFields chunk if compression is enabled and data exists. This sets up the file for subsequent chunk writing. ```Rust // *** Actually start writing to Result!! YAAAAYYY *** let mut result = Vec::new(); // The file starts with MAGIC_BYTES result.extend_from_slice(&MAGIC_BYTES); push_usize(&mut result, PROTOCOL_VERSION); // We'll write a series of chunks. Each chunk has a chunk header (chunk type, length). // The first chunk is CompressedFields, in case we need compressed content later. #[cfg(not(feature = "lz4"))] { debug_assert!(compress_bytes.is_none()); } #[cfg(feature = "lz4")] { if let Some(compress_bytes) = compress_bytes { if !compress_bytes.is_empty() { let compressed_len = write_compressed_chunk(&mut result, &compress_bytes); if verbose { println!("Compressed {} bytes in the file to {}", compress_bytes.len(), compressed_len); } } } } ``` -------------------------------- ### Initialize M2Tracker in Rust Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/merge/merge.rs This function initializes a new `M2Tracker` instance. It sets up the `range_tree` and `index` structures, initializing the index with an 'underwater' entry. This is the starting point for tracking document changes and merging operations. ```rust pub(super) fn new() -> Self { let mut range_tree = ContentTreeRaw::new(); let mut index = ContentTreeRaw::new(); let underwater = YjsSpan::new_underwater(); pad_index_to(&mut index, underwater.id.end); range_tree.push_notify(underwater, notify_for(&mut index)); Self { range_tree, index, } } ``` -------------------------------- ### Define LocalVersion as a Type Alias in Rust Source: https://docs.rs/diamond-types/latest/diamond_types/type.LocalVersion Defines `LocalVersion` as a type alias for `SmallVec<[Time; 2]>`. This represents a set of local Time values. It's never empty and defaults to `usize::max` at the start of time. ```rust pub type LocalVersion = SmallVec<[Time; 2]>; ``` -------------------------------- ### ClientData Methods in Rust Source: https://docs.rs/diamond-types/latest/src/diamond_types/list/oplog.rs Provides methods for `ClientData` to get the next sequence number, check if the data is empty, and convert between sequence numbers and timestamps. It utilizes `RleVec` for efficient storage and retrieval of item times. ```rust use std::ops::Range; use smallvec::{smallvec, SmallVec}; use smartstring::SmartString; use rle::{HasLength, Searchable}; use crate::{AgentId, ClientData, LocalVersion, ROOT_AGENT, ROOT_TIME, Time}; use crate::list::{Branch, OpLog}; use crate::frontier::{advance_frontier_by_known_run, clone_smallvec}; use crate::history::MinimalHistoryEntry; use crate::list::internal_op::{OperationCtx, OperationInternal}; use crate::list::operation::{Operation, OpKind}; use crate::list::remote_ids::RemoteId; use crate::dtrange::DTRange; use crate::remotespan::*; use crate::rev_range::RangeRev; use crate::rle::{KVPair, RleSpanHelpers, RleVec}; use crate::unicount::count_chars; impl ClientData { pub fn get_next_seq(&self) -> usize { if let Some(last) = self.item_times.last() { last.end() } else { 0 } } pub fn is_empty(&self) -> bool { self.item_times.is_empty() } #[inline] pub(crate) fn try_seq_to_time(&self, seq: usize) -> Option