Skip to main content

OpLog

Struct OpLog 

Source
pub struct OpLog { /* private fields */ }
Expand description

An OpLog is a collection of Diamond Types operations, stored in a super fancy compact way. Each operation has a number of fields:

  • Type (insert or delete)
  • ID (unique Agent ID + sequence number pair)
  • Parents - which names the document’s version right before this edit was created.
  • Origin edit position (when the edit was created) + length
  • Content of what was inserted or deleted. Storing this is optional.

The OpLog structure stores all this data in a SoA (Struct Of Arrays) format, which lets us run-length encode each field individually. This makes all operations significantly faster, but it makes the code to read changes significantly more complex.

The OpLog API supports:

  • Reading operations (via a few iterator methods + helpers)
  • Reading transformed operations (This is useful for applying changes to a local document state)
  • Encoding and decoding operation sets to and from binary formats
  • Appending operations which have been created locally or remotely
  • Creating a “checkout” (snapshot) of the document at any requested point in time
  • Interacting with the time DAG, to merge changes or list which operations a peer might be missing.

Well, it should. The public API is still a work in progress. I’m going to be tweaking method names and things a fair bit before we hit 1.0.

Implementations§

Source§

impl OpLog

Source

pub fn dbg_check(&self, deep: bool)

Check the internal state of the diamond types list. This is only exported for integration testing.

You shouldn’t have any reason to call this method.

This method is public, but do not depend on it as part of the DT API. It could be removed at any time.

Source§

impl OpLog

Source

pub fn iter_range_since( &self, local_version: &[Time], ) -> impl Iterator<Item = Operation> + '_

Source

pub fn iter(&self) -> impl Iterator<Item = Operation> + '_

Source§

impl OpLog

Source

pub fn iter_xf_operations_from( &self, from: &[Time], merging: &[Time], ) -> impl Iterator<Item = (DTRange, Option<Operation>)> + '_

Iterate through all the transformed operations from some point in time. Internally, the OpLog stores all changes as they were when they were created. This makes a lot of sense from CRDT academic point of view (and makes signatures and all that easy). But its is rarely useful for a text editor.

get_xf_operations returns an iterator over the transformed changes. That is, the set of changes that could be applied linearly to a document to bring it up to date.

Source

pub fn iter_xf_operations( &self, ) -> impl Iterator<Item = (DTRange, Option<Operation>)> + '_

Get all transformed operations from the start of time.

This is a shorthand for oplog.get_xf_operations(&[], oplog.local_version), but I hope that future optimizations make this method way faster.

See OpLog::iter_xf_operations_from for more information.

Source§

impl OpLog

Source

pub fn new() -> Self

Source

pub fn checkout(&self, local_version: &[Time]) -> Branch

Source

pub fn checkout_tip(&self) -> Branch

Source

pub fn get_or_create_agent_id(&mut self, name: &str) -> AgentId

Source

pub fn get_agent_name(&self, agent: AgentId) -> &str

Source

pub fn len(&self) -> usize

Get the number of operations

Source

pub fn is_empty(&self) -> bool

Source

pub fn add_operations_at( &mut self, agent: AgentId, parents: &[Time], ops: &[Operation], ) -> Time

Push new operations to the opset. Operation parents specified by parents parameter.

Returns the single item version after merging. (The resulting LocalVersion after calling this method will be [time]).

Source

pub fn add_insert_at( &mut self, agent: AgentId, parents: &[Time], pos: usize, ins_content: &str, ) -> Time

Returns the single item localtime after the inserted change.

Source

pub fn add_delete_at( &mut self, agent: AgentId, parents: &[Time], loc: Range<usize>, ) -> Time

Create and add a new operation from the specified agent which deletes the items (characters) in the passed range.

Returns the single item localtime after the inserted change.

Source

pub fn add_operations(&mut self, agent: AgentId, ops: &[Operation]) -> Time

Append local operations to the oplog. This method is used to make local changes to the document. Before calling this, first generate an agent ID using get_or_create_agent_id. This method will:

  • Store the new operations
  • Assign the operations IDs based on the next available sequence numbers from the specified agent
  • Store the operation’s parents as the most recent known version. (Use branch.apply_local_operations instead when pushing to a branch).
Source

pub fn add_insert( &mut self, agent: AgentId, pos: usize, ins_content: &str, ) -> Time

Add an insert operation to the oplog at the current version.

Returns the single item localtime after the inserted change. This is a shorthand for oplog.push(agent, *insert(pos, content)*) TODO: Optimize these functions like push_insert_at / push_delete_at.

Source

pub unsafe fn add_delete_with_unchecked_content( &mut self, agent: AgentId, pos: usize, del_content: &str, ) -> Time

Add a local delete operation to the oplog. This variant of the method allows a user to pass the content of the delete into the oplog. This can be useful for undos and things like that but it is NOT CHECKED. If you don’t have access to the deleted content, use add_delete_without_content instead.

If you have a local branch, its easier, faster, and safer to just call branch.delete(agent, pos, len).

§Safety

The deleted content must match the content in the document at that range, at the current time.

Source

pub fn add_delete_without_content( &mut self, agent: AgentId, loc: Range<usize>, ) -> Time

Add a local delete operation to the oplog. Returns the single item frontier after the inserted change. This is a shorthand for oplog.push(agent, *delete(pos, del_span)*)

Source

pub fn iter_history(&self) -> impl Iterator<Item = MinimalHistoryEntry> + '_

Iterate through history entries

Source

pub fn iter_history_range( &self, range: DTRange, ) -> impl Iterator<Item = MinimalHistoryEntry> + '_

Source

pub fn local_version_ref(&self) -> &[Time]

Returns a &[usize] reference to the tip of the oplog. This version contains all known operations.

This method is provided alongside local_version because its slightly faster.

Source

pub fn local_version(&self) -> LocalVersion

Return the current tip version of the oplog. This is the version which contains all operations in the oplog.

Source

pub fn remote_version(&self) -> SmallVec<[RemoteId; 4]>

Source

pub fn iter_mappings(&self) -> impl Iterator<Item = CRDTSpan> + '_

Source

pub fn iter_mappings_range( &self, range: DTRange, ) -> impl Iterator<Item = CRDTSpan> + '_

Source

pub fn print_stats(&self, detailed: bool)

Source

pub fn version_contains_time( &self, local_version: &[Time], target: Time, ) -> bool

Check if the specified version contains the specified point in time.

Source

pub fn version_union(&self, a: &[Time], b: &[Time]) -> LocalVersion

Take the union of two versions.

One way to think of a version is the name of some subset of operations in the operation log. But a local time array only explicitly names versions at the “tip” of the time DAG. For example, if we have 3 operations: A, B, C with ROOT <- A <- B <- C, then the local version will only name {C}, since A and B are implicit.

version_union takes two versions and figures out the set union for all the contained changes, and returns the version name for that union. version_union(a, b) will often simply return a or b. This happens when one of the versions is a strict subset of the other.

Source§

impl OpLog

Source

pub fn encode_from( &self, opts: EncodeOptions<'_>, from_version: &[Time], ) -> Vec<u8>

Encode the data stored in the OpLog into a (custom) compact binary form suitable for saving to disk, or sending over the network.

Source

pub fn encode(&self, opts: EncodeOptions<'_>) -> Vec<u8>

Source

pub fn encode_simple(&self, _opts: EncodeOptions<'_>) -> Vec<u8>

Encode the data stored in the OpLog into a (custom) compact binary form suitable for saving to disk, or sending over the network.

Source§

impl OpLog

Source

pub fn load_from(data: &[u8]) -> Result<Self, ParseError>

Source

pub fn load_from_opts( data: &[u8], opts: DecodeOptions, ) -> Result<Self, ParseError>

Source

pub fn decode_and_add( &mut self, data: &[u8], ) -> Result<LocalVersion, ParseError>

Add all operations from a binary chunk into this document.

Any duplicate operations are ignored.

This method is a convenience method for calling oplog.decode_and_add_opts(data, DecodeOptions::default()).

Source

pub fn decode_and_add_opts( &mut self, data: &[u8], opts: DecodeOptions, ) -> Result<LocalVersion, ParseError>

Add all operations from a binary chunk into this document.

If successful, returns the version of the loaded data (which could be different from the local version!)

This method takes an options object, which for now doesn’t do much. Most users should just call OpLog::decode_and_add

Source§

impl OpLog

Source

pub fn try_remote_to_local_time( &self, id: &RemoteId, ) -> Result<Time, ConversionError>

Source

pub fn remote_to_local_time(&self, id: &RemoteId) -> Time

This panics if the ID isn’t known to the document.

Source

pub fn local_to_remote_time(&self, time: Time) -> RemoteId

Source

pub fn try_remote_to_local_version<'a, I: Iterator<Item = &'a RemoteId> + 'a>( &self, ids_iter: I, ) -> Result<LocalVersion, ConversionError>

Source

pub fn remote_to_local_version<'a, I: Iterator<Item = &'a RemoteId> + 'a>( &self, ids_iter: I, ) -> LocalVersion

Source

pub fn local_to_remote_version( &self, local_version: &[Time], ) -> SmallVec<[RemoteId; 4]>

Source§

impl OpLog

Source

pub fn add_missing_operations_from(&mut self, other: &Self)

Add all missing operations from the other oplog into this oplog. This method is mostly used by testing code, since you rarely have two local oplogs to merge together.

Trait Implementations§

Source§

impl Clone for OpLog

Source§

fn clone(&self) -> OpLog

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for OpLog

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for OpLog

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl PartialEq for OpLog

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for OpLog

Auto Trait Implementations§

§

impl Freeze for OpLog

§

impl RefUnwindSafe for OpLog

§

impl Send for OpLog

§

impl Sync for OpLog

§

impl Unpin for OpLog

§

impl UnsafeUnpin for OpLog

§

impl UnwindSafe for OpLog

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V