Skip to main content

WorkspaceCrdt

Struct WorkspaceCrdt 

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

A CRDT document representing the workspace file hierarchy.

This wraps a yrs Doc and provides methods for managing file metadata in a conflict-free manner across multiple clients.

Implementations§

Source§

impl WorkspaceCrdt

Source

pub fn new(storage: Arc<dyn CrdtStorage>) -> Self

Create a new empty workspace CRDT with the given storage backend.

Source

pub fn with_name(storage: Arc<dyn CrdtStorage>, doc_name: String) -> Self

Create a new workspace CRDT with a custom document name.

Source

pub fn load(storage: Arc<dyn CrdtStorage>) -> StorageResult<Self>

Load an existing workspace CRDT from storage.

If no document exists in storage, returns a new empty workspace.

Source

pub fn load_with_name( storage: Arc<dyn CrdtStorage>, doc_name: String, ) -> StorageResult<Self>

Load a workspace CRDT with a custom document name from storage.

This loads both the base snapshot (if any) and all incremental updates to reconstruct the current state.

Source

pub fn set_event_callback( &mut self, callback: Arc<dyn Fn(&FileSystemEvent) + Send + Sync>, )

Set the event callback for emitting filesystem events on remote/sync updates.

When set, this callback will be invoked with FileSystemEvents whenever apply_update() is called with a non-Local origin. This enables unified event handling where the UI responds the same way to both local and remote changes.

§Example
let mut crdt = WorkspaceCrdt::load(storage)?;
crdt.set_event_callback(Arc::new(|event| {
    println!("Remote change: {:?}", event);
}));
Source

pub fn doc(&self) -> &Doc

Get the underlying yrs document.

Source

pub fn doc_name(&self) -> &str

Get the document name used for storage.

Source

pub fn storage(&self) -> &Arc<dyn CrdtStorage>

Get a reference to the storage backend.

Source

pub fn get_file(&self, path: &str) -> Option<FileMetadata>

Get metadata for a file at the given path.

Source

pub fn set_file(&self, path: &str, metadata: FileMetadata) -> StorageResult<()>

Set metadata for a file at the given path.

This will create a new entry or update an existing one. The change is automatically recorded in the update history.

§Errors

Returns an error if the update fails to persist to storage.

Source

pub fn delete_file(&self, path: &str) -> StorageResult<()>

Mark a file as deleted (soft delete).

This sets the deleted flag to true rather than removing the entry, which is important for proper CRDT tombstone handling.

§Errors

Returns an error if the update fails to persist to storage.

Source

pub fn remove_file(&self, path: &str) -> StorageResult<()>

Remove a file entry completely from the CRDT.

Warning: This should generally not be used. Prefer [delete_file] for proper tombstone handling. Use this only for garbage collection of very old deleted entries.

§Errors

Returns an error if the update fails to persist to storage.

Source

pub fn list_files(&self) -> Vec<(String, FileMetadata)>

List all files in the workspace.

Returns a vector of (path, metadata) tuples for all files, including deleted ones (check metadata.deleted).

Source

pub fn list_active_files(&self) -> Vec<(String, FileMetadata)>

List all non-deleted files in the workspace.

Source

pub fn file_count(&self) -> usize

Get the number of files in the workspace (including deleted).

Source

pub fn create_file(&self, metadata: FileMetadata) -> StorageResult<String>

Create a new file with a generated UUID as the key.

This is the primary method for creating files in the doc-ID based system. Returns the generated doc_id that can be used to reference this file.

§Arguments
  • metadata - File metadata (must have filename set)
§Returns

The generated doc_id (UUID) for the new file.

Source

pub fn get_path(&self, doc_id: &str) -> Option<PathBuf>

Derive the filesystem path from a doc_id by walking the parent chain.

This reconstructs the full path by traversing the part_of references up to the root and then joining the filenames.

§Arguments
  • doc_id - The document ID to get the path for
§Returns

The derived path, or None if the doc_id doesn’t exist or the chain is broken.

Source

pub fn find_by_path(&self, path: &Path) -> Option<String>

Find a doc_id by filesystem path.

This walks the tree to find a file with the matching path. The path is matched by traversing from root files down through the contents hierarchy.

§Arguments
  • path - The path to search for
§Returns

The doc_id if found, or None.

Source

pub fn rename_file(&self, doc_id: &str, new_filename: &str) -> StorageResult<()>

Rename a file by updating its filename.

In the doc-ID system, renames are trivial - just update the filename property. The doc_id remains stable.

§Arguments
  • doc_id - The document ID of the file to rename
  • new_filename - The new filename (e.g., “new-name.md”)
Source

pub fn move_file( &self, doc_id: &str, new_parent_id: Option<&str>, ) -> StorageResult<()>

Move a file by updating its parent reference.

In the doc-ID system, moves are trivial - just update the part_of property. The doc_id remains stable.

§Arguments
  • doc_id - The document ID of the file to move
  • new_parent_id - The doc_id of the new parent, or None for root
Source

pub fn needs_migration(&self) -> bool

Check if the workspace needs migration from path-based to doc-ID-based format.

Returns true if any file key contains a path separator (‘/’).

Source

pub fn migrate_to_doc_ids(&self) -> StorageResult<usize>

Migrate the workspace from path-based to doc-ID-based format.

This performs the following steps:

  1. Generate UUIDs for all existing files
  2. Extract filename from each path
  3. Convert part_of paths to doc_ids
  4. Convert contents paths to doc_ids
  5. Delete old path-based entries
  6. Create new UUID-based entries
§Returns

Number of files migrated, or an error.

Source

pub fn encode_state_vector(&self) -> Vec<u8>

Encode the current state vector for sync handshake.

Send this to a remote peer to initiate synchronization. The remote peer will use it to compute what updates you’re missing.

Source

pub fn encode_state_as_update(&self) -> Vec<u8>

Encode the full document state as an update.

This returns a binary blob that can be applied to another document to bring it up to date with this one.

Source

pub fn encode_diff(&self, remote_state_vector: &[u8]) -> StorageResult<Vec<u8>>

Encode only the updates that the remote peer is missing.

Given the remote peer’s state vector, this computes and returns only the updates they don’t have yet.

Source

pub fn apply_update( &self, update: &[u8], origin: UpdateOrigin, ) -> StorageResult<Option<i64>>

Apply an update from a remote peer.

Returns the update ID if the update was persisted to storage.

For non-Local origins (Remote, Sync), this method will detect what changed and emit corresponding FileSystemEvents via the event callback. This enables unified event handling where the UI responds the same way to both local and remote changes.

Source

pub fn replace_state( &mut self, full_state: &[u8], origin: UpdateOrigin, ) -> StorageResult<Option<i64>>

Replace the entire CRDT state with the given state.

This is used during initial sync when a new client receives the full state from the server. Instead of merging (which can cause tombstoning), this completely replaces the local state.

Important: This method discards all local state and replaces it with the provided state. Any local changes not synced will be lost.

§Arguments
  • full_state - The full CRDT state as a Y-update encoded in v1 format
  • origin - The origin of the update (typically UpdateOrigin::Sync)
§Returns

The update ID if the state was persisted to storage.

Source

pub fn apply_update_tracking_changes( &self, update: &[u8], origin: UpdateOrigin, ) -> StorageResult<(Option<i64>, Vec<String>, Vec<(String, String)>)>

Apply an update from a remote peer and return the list of changed file paths.

This is like apply_update but returns the paths of files that changed, allowing callers to selectively write those files to disk.

Returns (update_id, changed_paths, renames) where:

  • changed_paths includes newly created, deleted, and modified files
  • renames is a list of (old_path, new_path) pairs for detected renames
Source

pub fn save(&self) -> StorageResult<()>

Save the current document state to storage.

Source

pub fn reload(&mut self) -> StorageResult<()>

Reload the document state from storage, discarding local changes.

Source

pub fn get_history(&self) -> StorageResult<Vec<CrdtUpdate>>

Get all updates from storage for this document.

Source

pub fn get_updates_since(&self, since_id: i64) -> StorageResult<Vec<CrdtUpdate>>

Get updates since a specific update ID.

Source

pub fn get_latest_update_id(&self) -> StorageResult<i64>

Get the latest update ID.

Source

pub fn observe_updates<F>(&self, callback: F) -> Subscription
where F: Fn(&[u8]) + Send + Sync + 'static,

Subscribe to document updates.

The callback receives the binary update data whenever the document changes. Returns a subscription that will unsubscribe when dropped.

§Panics

Panics if unable to acquire transaction for observing.

Source

pub fn observe_files<F>(&self, callback: F) -> Subscription
where F: Fn(Vec<(String, Option<FileMetadata>)>) + Send + Sync + 'static,

Subscribe to changes in the files map.

The callback receives the path and new metadata (or None if removed) for each changed file.

Trait Implementations§

Source§

impl Debug for WorkspaceCrdt

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

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> 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, 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.