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
impl OpLog
Sourcepub fn iter_xf_operations_from(
&self,
from: &[Time],
merging: &[Time],
) -> impl Iterator<Item = (DTRange, Option<Operation>)> + '_
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.
Sourcepub fn iter_xf_operations(
&self,
) -> impl Iterator<Item = (DTRange, Option<Operation>)> + '_
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
impl OpLog
pub fn new() -> Self
pub fn checkout(&self, local_version: &[Time]) -> Branch
pub fn checkout_tip(&self) -> Branch
pub fn get_or_create_agent_id(&mut self, name: &str) -> AgentId
pub fn get_agent_name(&self, agent: AgentId) -> &str
pub fn is_empty(&self) -> bool
Sourcepub fn add_operations_at(
&mut self,
agent: AgentId,
parents: &[Time],
ops: &[Operation],
) -> Time
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]).
Sourcepub fn add_insert_at(
&mut self,
agent: AgentId,
parents: &[Time],
pos: usize,
ins_content: &str,
) -> Time
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.
Sourcepub fn add_delete_at(
&mut self,
agent: AgentId,
parents: &[Time],
loc: Range<usize>,
) -> Time
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.
Sourcepub fn add_operations(&mut self, agent: AgentId, ops: &[Operation]) -> Time
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_operationsinstead when pushing to a branch).
Sourcepub fn add_insert(
&mut self,
agent: AgentId,
pos: usize,
ins_content: &str,
) -> Time
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.
Sourcepub unsafe fn add_delete_with_unchecked_content(
&mut self,
agent: AgentId,
pos: usize,
del_content: &str,
) -> Time
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.
Sourcepub fn add_delete_without_content(
&mut self,
agent: AgentId,
loc: Range<usize>,
) -> Time
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)*)
Sourcepub fn iter_history(&self) -> impl Iterator<Item = MinimalHistoryEntry> + '_
pub fn iter_history(&self) -> impl Iterator<Item = MinimalHistoryEntry> + '_
Iterate through history entries
pub fn iter_history_range( &self, range: DTRange, ) -> impl Iterator<Item = MinimalHistoryEntry> + '_
Sourcepub fn local_version_ref(&self) -> &[Time] ⓘ
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.
Sourcepub fn local_version(&self) -> LocalVersion
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.
pub fn remote_version(&self) -> SmallVec<[RemoteId; 4]>
pub fn iter_mappings(&self) -> impl Iterator<Item = CRDTSpan> + '_
pub fn iter_mappings_range( &self, range: DTRange, ) -> impl Iterator<Item = CRDTSpan> + '_
pub fn print_stats(&self, detailed: bool)
Sourcepub fn version_contains_time(
&self,
local_version: &[Time],
target: Time,
) -> bool
pub fn version_contains_time( &self, local_version: &[Time], target: Time, ) -> bool
Check if the specified version contains the specified point in time.
Sourcepub fn version_union(&self, a: &[Time], b: &[Time]) -> LocalVersion
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
impl OpLog
Sourcepub fn encode_from(
&self,
opts: EncodeOptions<'_>,
from_version: &[Time],
) -> Vec<u8> ⓘ
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.
pub fn encode(&self, opts: EncodeOptions<'_>) -> Vec<u8> ⓘ
Sourcepub fn encode_simple(&self, _opts: EncodeOptions<'_>) -> Vec<u8> ⓘ
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
impl OpLog
pub fn load_from(data: &[u8]) -> Result<Self, ParseError>
pub fn load_from_opts( data: &[u8], opts: DecodeOptions, ) -> Result<Self, ParseError>
Sourcepub fn decode_and_add(
&mut self,
data: &[u8],
) -> Result<LocalVersion, ParseError>
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()).
Sourcepub fn decode_and_add_opts(
&mut self,
data: &[u8],
opts: DecodeOptions,
) -> Result<LocalVersion, ParseError>
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
impl OpLog
pub fn try_remote_to_local_time( &self, id: &RemoteId, ) -> Result<Time, ConversionError>
Sourcepub fn remote_to_local_time(&self, id: &RemoteId) -> Time
pub fn remote_to_local_time(&self, id: &RemoteId) -> Time
This panics if the ID isn’t known to the document.
pub fn local_to_remote_time(&self, time: Time) -> RemoteId
pub fn try_remote_to_local_version<'a, I: Iterator<Item = &'a RemoteId> + 'a>( &self, ids_iter: I, ) -> Result<LocalVersion, ConversionError>
pub fn remote_to_local_version<'a, I: Iterator<Item = &'a RemoteId> + 'a>( &self, ids_iter: I, ) -> LocalVersion
pub fn local_to_remote_version( &self, local_version: &[Time], ) -> SmallVec<[RemoteId; 4]>
Source§impl OpLog
impl OpLog
Sourcepub fn add_missing_operations_from(&mut self, other: &Self)
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.