From 385ff95deaa173bc0ba064762da7e3080ea2192c Mon Sep 17 00:00:00 2001 From: leeeon233 Date: Thu, 26 Sep 2024 20:51:09 +0800 Subject: [PATCH 01/12] feat: all LoroDoc func --- loro-rs/Cargo.lock | 145 +++++++++++++-- loro-rs/Cargo.toml | 4 +- loro-rs/src/json_bk.udl | 77 ++++++++ loro-rs/src/loro.udl | 378 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 548 insertions(+), 56 deletions(-) create mode 100644 loro-rs/src/json_bk.udl diff --git a/loro-rs/Cargo.lock b/loro-rs/Cargo.lock index 8831aca..ffaa9de 100644 --- a/loro-rs/Cargo.lock +++ b/loro-rs/Cargo.lock @@ -2,6 +2,19 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy 0.7.35", +] + [[package]] name = "anstream" version = "0.6.15" @@ -345,6 +358,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" +[[package]] +name = "ensure-cov" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33753185802e107b8fa907192af1f0eca13b1fb33327a59266d650fef29b2b4e" + [[package]] name = "enum-as-inner" version = "0.5.1" @@ -381,6 +400,12 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fnv" version = "1.0.7" @@ -465,6 +490,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "heapless" version = "0.7.17" @@ -516,6 +547,7 @@ dependencies = [ "bitmaps 2.1.0", "rand_core", "rand_xoshiro", + "serde", "sized-chunks", "typenum", "version_check", @@ -603,36 +635,37 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "loro" -version = "0.16.2" -source = "git+https://github.com/loro-dev/loro.git?rev=a9f669d173807b80dde7ffef7f467c8a57fc5b1f#a9f669d173807b80dde7ffef7f467c8a57fc5b1f" +version = "0.16.12" dependencies = [ "enum-as-inner 0.6.0", "generic-btree", + "loro-common", "loro-delta", "loro-internal", + "loro-kv-store", "tracing", ] [[package]] name = "loro-common" -version = "0.16.2" -source = "git+https://github.com/loro-dev/loro.git?rev=a9f669d173807b80dde7ffef7f467c8a57fc5b1f#a9f669d173807b80dde7ffef7f467c8a57fc5b1f" +version = "0.16.12" dependencies = [ "arbitrary", "enum-as-inner 0.6.0", "fxhash", + "leb128", "loro-rle", "nonmax", "serde", "serde_columnar", + "serde_json", "string_cache", "thiserror", ] [[package]] name = "loro-delta" -version = "0.16.2" -source = "git+https://github.com/loro-dev/loro.git?rev=a9f669d173807b80dde7ffef7f467c8a57fc5b1f#a9f669d173807b80dde7ffef7f467c8a57fc5b1f" +version = "0.16.12" dependencies = [ "arrayvec", "enum-as-inner 0.5.1", @@ -644,19 +677,20 @@ dependencies = [ [[package]] name = "loro-ffi" version = "0.16.2" -source = "git+https://github.com/loro-dev/loro.git?rev=a9f669d173807b80dde7ffef7f467c8a57fc5b1f#a9f669d173807b80dde7ffef7f467c8a57fc5b1f" dependencies = [ "loro", + "serde_json", ] [[package]] name = "loro-internal" -version = "0.16.2" -source = "git+https://github.com/loro-dev/loro.git?rev=a9f669d173807b80dde7ffef7f467c8a57fc5b1f#a9f669d173807b80dde7ffef7f467c8a57fc5b1f" +version = "0.16.12" dependencies = [ "append-only-bytes", "arref", + "bytes", "either", + "ensure-cov", "enum-as-inner 0.6.0", "enum_dispatch", "fxhash", @@ -667,9 +701,11 @@ dependencies = [ "leb128", "loro-common", "loro-delta", + "loro-kv-store", "loro-rle", "loro_fractional_index", "md5", + "nonmax", "num", "num-derive", "num-traits", @@ -682,12 +718,26 @@ dependencies = [ "smallvec", "thiserror", "tracing", + "xxhash-rust", ] [[package]] -name = "loro-rle" +name = "loro-kv-store" version = "0.16.2" -source = "git+https://github.com/loro-dev/loro.git?rev=a9f669d173807b80dde7ffef7f467c8a57fc5b1f#a9f669d173807b80dde7ffef7f467c8a57fc5b1f" +dependencies = [ + "bytes", + "ensure-cov", + "fxhash", + "loro-common", + "lz4_flex", + "once_cell", + "quick_cache", + "xxhash-rust", +] + +[[package]] +name = "loro-rle" +version = "0.16.12" dependencies = [ "append-only-bytes", "arref", @@ -713,15 +763,24 @@ checksum = "3f3d053a135388e6b1df14e8af1212af5064746e9b87a06a345a7a779ee9695a" [[package]] name = "loro_fractional_index" -version = "0.16.2" -source = "git+https://github.com/loro-dev/loro.git?rev=a9f669d173807b80dde7ffef7f467c8a57fc5b1f#a9f669d173807b80dde7ffef7f467c8a57fc5b1f" +version = "0.16.12" dependencies = [ "imbl", + "once_cell", "rand", "serde", "smallvec", ] +[[package]] +name = "lz4_flex" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" +dependencies = [ + "twox-hash", +] + [[package]] name = "md5" version = "0.7.0" @@ -936,7 +995,7 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f" dependencies = [ - "zerocopy", + "zerocopy 0.6.6", ] [[package]] @@ -954,6 +1013,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick_cache" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d7c94f8935a9df96bb6380e8592c70edf497a643f94bd23b2f76b399385dbf4" +dependencies = [ + "ahash", + "equivalent", + "hashbrown", + "parking_lot", +] + [[package]] name = "quote" version = "1.0.36" @@ -1072,9 +1143,9 @@ dependencies = [ [[package]] name = "serde_columnar" -version = "0.3.6" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7947238638e841d935a1dadff54b74575ae60d51b977be75dab16e7638ea6e7d" +checksum = "6d4e3c0e46450edf7da174b610b9143eb8ca22059ace5016741fc9e20b88d1e7" dependencies = [ "itertools 0.11.0", "postcard", @@ -1085,9 +1156,9 @@ dependencies = [ [[package]] name = "serde_columnar_derive" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5eaacabbc55a397ffbb1ee32523f40f86fdefea8a8d9db19630d8b7c00edd1" +checksum = "42c5d47942b2a7e76118b697fc0f94516a5d8366a3c0fee8d0e2b713e952e306" dependencies = [ "darling", "proc-macro2", @@ -1281,6 +1352,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + [[package]] name = "typenum" version = "1.17.0" @@ -1533,6 +1614,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "xxhash-rust" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" + [[package]] name = "zerocopy" version = "0.6.6" @@ -1540,7 +1627,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.6.6", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive 0.7.35", ] [[package]] @@ -1553,3 +1649,14 @@ dependencies = [ "quote", "syn 2.0.72", ] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] diff --git a/loro-rs/Cargo.toml b/loro-rs/Cargo.toml index e806db7..fa6755b 100644 --- a/loro-rs/Cargo.toml +++ b/loro-rs/Cargo.toml @@ -14,8 +14,8 @@ path = "src/uniffi-bindgen.rs" [dependencies] -# loro-ffi = { path = "../../loro/crates/loro-ffi" } -loro-ffi = { git = "https://github.com/loro-dev/loro.git", rev = "a9f669d173807b80dde7ffef7f467c8a57fc5b1f" } +loro-ffi = { path = "../../loro/crates/loro-ffi" } +# loro-ffi = { git = "https://github.com/loro-dev/loro.git", rev = "a9f669d173807b80dde7ffef7f467c8a57fc5b1f" } uniffi = { version = "0.28" } [build-dependencies] diff --git a/loro-rs/src/json_bk.udl b/loro-rs/src/json_bk.udl new file mode 100644 index 0000000..6d63f1f --- /dev/null +++ b/loro-rs/src/json_bk.udl @@ -0,0 +1,77 @@ +dictionary JsonSchema{ + u8 schema_version; + Frontiers start_version; + sequence peers; + sequence changes; +}; + +dictionary JsonChange{ + ID id; + i64 timestamp; + sequence deps; + u32 Lamport; + string? msg; + sequence ops; +}; + +dictionary JsonOp{ + JsonOpContent content; + ContainerID container; + i32 counter; +}; + +[Enum] +interface JsonOpContent{ + List(JsonListOp); + MovableList(JsonMovableListOp); + Map(JsonMapOp); + Text(JsonTextOp); + Tree(JsonTreeOp); + Future(JsonFutureOpWrapper); +}; + +dictionary JsonFutureOpWrapper{ + JsonFutureOp value; + i32 prop; +}; + +[Enum] +interface JsonListOp{ + Insert(u32 pos, LoroValue value); + Delete(i32 pos, i32 len, ID start_id); +}; + +[Enum] +interface JsonMovableListOp{ + Insert(u32 pos, LoroValue value); + Delete(i32 pos, i32 len, ID start_id); + Move(u32 from, u32 to, IdLp elem_id); + Set(IdLp elem_id, LoroValue value); +}; + +[Enum] +interface JsonMapOp{ + Insert(string key, LoroValue value); + Delete(string key); +}; + +[Enum] +interface JsonTextOp{ + Insert(u32 pos, string text); + Delete(i32 pos, i32 len, ID start_id); + Mark(u32 start, u32 end, string style_key, LoroValue style_value, u8 info); + MarkEnd(); +}; + +[Enum] +interface JsonTreeOp{ + Create(TreeID target, TreeID? parent, FractionalIndex fractional_index); + Move(TreeID target, TreeID? parent, FractionalIndex fractional_index); + Delete(TreeID target); +}; + +[Enum] +interface JsonFutureOp{ + Counter(OwnedValue value); + Unknown(OwnedValue value); +}; \ No newline at end of file diff --git a/loro-rs/src/loro.udl b/loro-rs/src/loro.udl index f04f0da..cf5ad3a 100644 --- a/loro-rs/src/loro.udl +++ b/loro-rs/src/loro.udl @@ -33,6 +33,16 @@ interface Subscriber{ void on_diff(DiffEvent diff); }; +[Trait, WithForeign] +interface LocalUpdateCallback{ + void on_local_update(bytes update); +}; + +[Trait, WithForeign] +interface Unsubscriber{ + void on_unsubscribe(); +}; + [Trait, WithForeign] interface OnPush{ UndoItemMeta on_push(UndoOrRedo undo_or_redo, CounterSpan span); @@ -43,6 +53,12 @@ interface OnPop{ void on_pop(UndoOrRedo undo_or_redo, CounterSpan span, UndoItemMeta undo_meta); }; +// [Trait, WithForeign] +// interface JsonSchemaLike{ +// [Throws=LoroError] +// JsonSchema into_json_schema(); +// }; + // ============= LORO DOC ============= interface LoroDoc{ @@ -54,9 +70,27 @@ interface LoroDoc{ /// The time complexity and space complexity of this operation are both O(n), LoroDoc fork(); - // Config config(); - // [Throws=LoroError] - // ImportBlobMetadata decode_import_blob_meta([ByRef] bytes); + /// Get the configurations of the document. + Configure config(); + + /// Get `Change` at the given id. + /// + /// `Change` is a grouped continuous operations that share the same id, timestamp, commit message. + /// + /// - The id of the `Change` is the id of its first op. + /// - The second op's id is `{ peer: change.id.peer, counter: change.id.counter + 1 }` + /// + /// The same applies on `Lamport`: + /// + /// - The lamport of the `Change` is the lamport of its first op. + /// - The second op's lamport is `change.lamport + 1` + /// + /// The length of the `Change` is how many operations it contains + ChangeMeta? get_change(ID id); + + /// Decodes the metadata for an imported blob from the provided bytes. + [Throws=LoroError] + ImportBlobMetadata decode_import_blob_meta([ByRef] bytes bytes); /// Set whether to record the timestamp of each change. Default is `false`. /// @@ -75,14 +109,14 @@ interface LoroDoc{ /// The default value is 1000 seconds. void set_change_merge_interval(i64 interval); - /// Set the jitter of the tree position(Fractional Index). + /// Set the rich text format configuration of the document. /// - /// The jitter is used to avoid conflicts when multiple users are creating the node at the same position. - /// value 0 is default, which means no jitter, any value larger than 0 will enable jitter. - /// Generally speaking, jitter will affect the growth rate of document size. - void set_fractional_index_jitter(u8 jitter); - - // void config_text_style(StyleConfigMap text_style); + /// You need to config it if you use rich text `mark` method. + /// Specifically, you need to config the `expand` property of each style. + /// + /// Expand is used to specify the behavior of expanding when new text is inserted at the + /// beginning or end of the style. + void config_text_style(StyleConfigMap text_style); /// Attach the document state to the latest known version. /// @@ -113,7 +147,12 @@ interface LoroDoc{ /// This has the same effect as `attach`. void checkout_to_latest(); - // Ordering cmp_with_frontiers([ByRef] Frontiers other); + /// Compare the frontiers with the current OpLog's version. + /// + /// If `other` contains any version that's not contained in the current OpLog, return [Ordering::Less]. + Ordering cmp_with_frontiers([ByRef] Frontiers other); + + // cmp_frontiers(); /// Force the document enter the detached mode. @@ -129,7 +168,6 @@ interface LoroDoc{ [Throws=LoroError] void import_batch([ByRef] sequence bytes); - // TODO: id type /// Get a [LoroMovableList] by container id. /// /// If the provided id is string, it will be converted into a root container id with the name of the string. @@ -167,7 +205,9 @@ interface LoroDoc{ /// The event will be sent after a transaction is committed void commit(); - // void commit_with(CommitOptions options); + void commit_with(CommitOptions options); + + void set_next_commit_message([ByRef] string msg); /// Whether the document is in detached mode, where the [loro_internal::DocState] is not /// synchronized with the latest version of the [loro_internal::OpLog]. @@ -183,10 +223,12 @@ interface LoroDoc{ /// in the generated events. [Throws=LoroError] void import_with([ByRef] bytes bytes, [ByRef] string origin); - - // [Throws=LoroError] - // void import_json_updates(JsonSchema json); - // JsonSchema export_json_updates([ByRef]VersionVector start_vv, [ByRef]VersionVector end_vv); + + [Throws=LoroError] + void import_json_updates([ByRef]string json); + + /// Export the current state with json-string format of the document. + string export_json_updates([ByRef]VersionVector start_vv, [ByRef]VersionVector end_vv); /// Export all the ops not included in the given `VersionVector` bytes export_from([ByRef] VersionVector vv); @@ -207,15 +249,26 @@ interface LoroDoc{ /// Get the `VersionVector` version of `OpLog` VersionVector state_vv(); + /// Get the `VersionVector` of trimmed history + /// + /// The ops included by the trimmed history are not in the doc. + VersionVector trimmed_vv(); + /// Get the total number of operations in the `OpLog` u64 len_ops(); /// Get the total number of changes in the `OpLog` u64 len_changes(); + /// Get the shallow value of the document. + LoroValue get_value(); + /// Get the current state of the document. LoroValue get_deep_value(); + /// Get the current state with container id of the doc + LoroValue get_deep_value_with_id(); + /// Get the `Frontiers` version of `OpLog` Frontiers oplog_frontiers(); @@ -249,19 +302,94 @@ interface LoroDoc{ /// Remove a subscription. void unsubscribe(SubID sub_id); - // /// Estimate the size of the document states in memory. - // void log_estimate_size(); + /// Subscribe the local update of the document. + Subscription subscribe_local_update(LocalUpdateCallback callback); + /// Estimate the size of the document states in memory. + void log_estimate_size(); - // void check_state_correctness_slow(); + /// Check the correctness of the document state by comparing it with the state + /// calculated by applying all the history. + void check_state_correctness_slow(); /// Get the handler by the path. ValueOrContainer? get_by_path([ByRef] sequence path); /// Get the handler by the string path. ValueOrContainer? get_by_str_path([ByRef] string path); - // [Throws=LoroError] - // PosQueryResult get_cursor_pos(Cursor cursor); + + [Throws=CannotFindRelativePosition] + PosQueryResult get_cursor_pos([ByRef]Cursor cursor); + + boolean has_history_cache(); + + /// Free the history cache that is used for making checkout faster. + /// + /// If you use checkout that switching to an old/concurrent version, the history cache will be built. + /// You can free it by calling this method. + void free_history_cache(); + + /// Free the cached diff calculator that is used for checkout. + void free_diff_calculator(); + + /// Encoded all ops and history cache to bytes and store them in the kv store. + /// + /// The parsed ops will be dropped + void compact_change_store(); + + // /// Export the document in the given mode. + // bytes export(ExportMode mode); + + bytes export_updates_in_range([ByRef]sequence spans); + + bytes export_gc_snapshot([ByRef]Frontiers frontiers); + + bytes export_state_only(Frontiers? frontiers); + + // /// Analyze the container info of the doc + // /// + // /// This is used for development and debugging. It can be slow. + // DocAnalysis analyze(); + + /// Get the path from the root to the container + sequence? get_path_to_container([ByRef] ContainerID id); + + /// Evaluate a JSONPath expression on the document and return matching values or handlers. + /// + /// This method allows querying the document structure using JSONPath syntax. + /// It returns a vector of `ValueOrHandler` which can represent either primitive values + /// or container handlers, depending on what the JSONPath expression matches. + /// + /// # Arguments + /// + /// * `path` - A string slice containing the JSONPath expression to evaluate. + /// + /// # Returns + /// + /// A `Result` containing either: + /// - `Ok(Vec)`: A vector of matching values or handlers. + /// - `Err(String)`: An error message if the JSONPath expression is invalid or evaluation fails. + /// + /// # Example + /// + /// ``` + /// # use loro::LoroDoc; + /// let doc = LoroDoc::new(); + /// let map = doc.get_map("users"); + /// map.insert("alice", 30).unwrap(); + /// map.insert("bob", 25).unwrap(); + /// + /// let result = doc.jsonpath("$.users.alice").unwrap(); + /// assert_eq!(result.len(), 1); + /// assert_eq!(result[0].to_json_value(), serde_json::json!(30)); + /// ``` + [Throws=JsonPathError] + sequence jsonpath([ByRef] string path); +}; + +dictionary ContainerPath{ + ContainerID id; + Index path; }; // ============= CONTAINERS ============= @@ -519,25 +647,25 @@ interface LoroTree{ /// If the `parent` is `None`, the created node is the root of a tree. /// Otherwise, the created node is a child of the parent tree node. [Throws=LoroError] - TreeID create(TreeID? parent); + TreeID create(TreeParentId parent); /// Create a new tree node at the given index and return the [`TreeID`]. /// /// If the `parent` is `None`, the created node is the root of a tree. /// If the `index` is greater than the number of children of the parent, error will be returned. [Throws=LoroError] - TreeID create_at(TreeID? parent, u32 index); + TreeID create_at(TreeParentId parent, u32 index); /// Move the `target` node to be a child of the `parent` node. /// /// If the `parent` is `None`, the `target` node will be a root. [Throws=LoroError] - void mov(TreeID target, TreeID? parent); + void mov(TreeID target, TreeParentId parent); /// Move the `target` node to be a child of the `parent` node at the given index. /// If the `parent` is `None`, the `target` node will be a root. [Throws=LoroError] - void mov_to(TreeID target, TreeID? parent, u32 to); + void mov_to(TreeID target, TreeParentId parent, u32 to); /// Move the `target` node to be a child after the `after` node with the same parent. [Throws=LoroError] @@ -563,10 +691,17 @@ interface LoroTree{ /// - If the target node does not exist, throws Error. /// - If the target node is a root node, return nil. [Throws=LoroError] - TreeID? parent(TreeID target); + TreeParentId parent(TreeID target); /// Return whether target node exists. boolean contains(TreeID target); + + /// Return whether target node is deleted. + /// + /// # Errors + /// - If the target node does not exist, return `LoroTreeError::TreeNodeNotExist`. + [Throws=LoroError] + boolean is_node_deleted(TreeID target); /// Return all nodes sequence nodes(); @@ -574,10 +709,10 @@ interface LoroTree{ /// Return all children of the target node. /// /// If the parent node does not exist, return `None`. - sequence? children(TreeID? parent); + sequence? children(TreeParentId parent); /// Return the number of children of the target node. - u32? children_num(TreeID? parent); + u32? children_num(TreeParentId parent); /// Return container id of the tree. ContainerID id(); @@ -593,6 +728,22 @@ interface LoroTree{ /// Return the flat array of the forest, each node is with metadata. LoroValue get_value_with_meta(); + + /// Whether the fractional index is enabled. + boolean is_fractional_index_enabled(); + + /// Enable fractional index for Tree Position. + /// + /// The jitter is used to avoid conflicts when multiple users are creating the node at the same position. + /// value 0 is default, which means no jitter, any value larger than 0 will enable jitter. + /// + /// Generally speaking, jitter will affect the growth rate of document size. + /// [Read more about it](https://www.loro.dev/blog/movable-tree#implementation-and-encoding-size) + void enable_fractional_index(u8 jitter); + + /// Disable the fractional index generation for Tree Position when + /// you don't need the Tree's siblings to be sorted. The fractional index will be always default. + void disable_fractional_index(); }; interface LoroMovableList{ @@ -719,6 +870,96 @@ interface LoroUnknown{ ContainerID id(); }; +// ============= TYPES ============= + +// TODO: https://github.com/mozilla/uniffi-rs/issues/1372 +// [Enum] +// interface ExportMode{ +// Snapshot(); +// Updates(VersionVector from); +// UpdatesInRange(sequence spans); +// GcSnapshot(Frontiers frontiers); +// StateOnly(Frontiers? frontiers); +// }; + +dictionary ChangeMeta{ + /// Lamport timestamp of the Change + u32 lamport; + /// The first Op id of the Change + ID id; + /// [Unix time](https://en.wikipedia.org/wiki/Unix_time) + /// It is the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970. + i64 timestamp; + /// The commit message of the change + string? message; + /// The dependencies of the first op of the change + Frontiers deps; + /// The total op num inside this change + u32 len; +}; + +dictionary ImportBlobMetadata{ + /// The partial start version vector. + /// + /// Import blob includes all the ops from `partial_start_vv` to `partial_end_vv`. + /// However, it does not constitute a complete version vector, as it only contains counters + /// from peers included within the import blob. + VersionVector partial_start_vv; + /// The partial end version vector. + /// + /// Import blob includes all the ops from `partial_start_vv` to `partial_end_vv`. + /// However, it does not constitute a complete version vector, as it only contains counters + /// from peers included within the import blob. + VersionVector partial_end_vv; + i64 start_timestamp; + Frontiers start_frontiers; + i64 end_timestamp; + u32 change_num; + boolean is_snapshot; +}; + +enum Ordering{ + "Less", "Equal", "Greater" +}; + + +// ============= CONFIG ============= + +interface Configure{ + Configure fork(); + boolean record_timestamp(); + void set_record_timestamp(boolean record); + i64 merge_interval(); + void set_merge_interval(i64 interval); + StyleConfigMap text_style_config(); +}; + +interface StyleConfigMap{ + constructor(); + [Name=default_rich_text_config] + constructor(); + void insert([ByRef] string key, StyleConfig value); + StyleConfig? get([ByRef] string key); +}; + +dictionary StyleConfig{ + ExpandType expand; +}; + +enum ExpandType{ + "Before", + "After", + "Both", + "None", +}; + +dictionary CommitOptions{ + string? origin; + boolean immediate_renew; + i64? timestamp; + string? commit_msg; +}; + // ============= CURSOR ============= @@ -732,6 +973,16 @@ interface Cursor{ constructor(ID? id, ContainerID container, Side side, u32 origin_pos); }; +dictionary PosQueryResult{ + Cursor? update; + AbsolutePosition current; +}; + +dictionary AbsolutePosition{ + u32 pos; + Side side; +}; + // ============= VERSIONS ============= interface VersionVector{ @@ -889,9 +1140,9 @@ dictionary TreeDiffItem{ [Enum] interface TreeExternalDiff{ - Create(TreeID? parent, u32 index, string fractional_index); - Move(TreeID? parent, u32 index, string fractional_index); - Delete(); + Create(TreeParentId parent, u32 index, string fractional_index); + Move(TreeParentId parent, u32 index, string fractional_index, TreeParentId old_parent, u32 old_index); + Delete(TreeParentId old_parent, u32 old_index); }; dictionary PathItem{ @@ -916,20 +1167,61 @@ interface Index{ Node(TreeID target); }; +/// A handle to a subscription created by GPUI. When dropped, the subscription +/// is cancelled and the callback will no longer be invoked. +interface Subscription{ + /// Creates a new subscription with a callback that gets invoked when + /// this subscription is dropped. + constructor(Unsubscriber unsubscribe); + + /// Detaches the subscription from this handle. The callback will + /// continue to be invoked until the views or models it has been + /// subscribed to are dropped + [Self=ByArc] + void detach(); +}; + // ============= TYPES ============= dictionary TreeID{ u64 peer; i32 counter; }; +[Enum] +interface TreeParentId{ + Node(TreeID id); + Root(); + Deleted(); + Unexist(); +}; + +interface FractionalIndex{ + [Name=from_bytes] + constructor(bytes bytes); + [Name=from_hex_string] + constructor([ByRef] string str); + string to_string(); +}; + dictionary ID{ u64 peer; i32 counter; }; -interface IdSpan{ +dictionary IdLp{ + u32 lamport; + u64 peer; +}; +dictionary IdSpan{ + u64 peer; + CounterSpan counter; +}; + +dictionary CounterSpan{ + i32 start; + i32 end; }; [Custom] @@ -958,7 +1250,7 @@ interface LoroValue{ Bool(boolean value); Double(f64 value); I64(i64 value); - Binary(sequence value); + Binary(bytes value); String(string value); List(sequence value); Map(record value); @@ -967,7 +1259,7 @@ interface LoroValue{ [Error] enum LoroError { - "UnmatchedContext", + "UnmatchedContext", "DecodeVersionVectorError", "DecodeError", "DecodeDataCorruptionError", @@ -998,4 +1290,20 @@ enum LoroError { "UTF16InUnicodeCodePoint", "EndIndexLessThanStartIndex", "InvalidRootContainerName", + "ImportUpdatesThatDependsOnOutdatedVersion", + "SwitchToTrimmedVersion", + "ContainerDeleted" }; + +[Error] +enum CannotFindRelativePosition{ + "ContainerDeleted", + "HistoryCleared", + "IdNotFound" +}; + +[Error] +enum JsonPathError{ + "InvalidJsonPath", + "EvaluationError" +}; \ No newline at end of file From 11225f7bdf294d06a1c1f153247b0f5f07d2a38b Mon Sep 17 00:00:00 2001 From: leeeon233 Date: Thu, 26 Sep 2024 21:36:33 +0800 Subject: [PATCH 02/12] feat: refine vv --- loro-rs/src/loro.udl | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/loro-rs/src/loro.udl b/loro-rs/src/loro.udl index cf5ad3a..bdf489b 100644 --- a/loro-rs/src/loro.udl +++ b/loro-rs/src/loro.udl @@ -987,22 +987,34 @@ dictionary AbsolutePosition{ // ============= VERSIONS ============= interface VersionVector{ constructor(); - // void set_last(ID id); + void set_last(ID id); i32? get_last(u64 peer); - // void set_end(ID id); + void set_end(ID id); // boolean try_update_last(ID id); - // sequence get_missing_span([ByRef] VersionVector target); - // void merge([ByRef] VersionVector other); + sequence get_missing_span([ByRef] VersionVector target); + void merge([ByRef] VersionVector other); boolean includes_vv([ByRef] VersionVector other); boolean includes_id(ID id); - // i32Span? intersect_span(IdSpan target); - // extend_to_include_vv(); + CounterSpan? intersect_span(IdSpan target); + void extend_to_include_vv([ByRef]VersionVector other); + VersionVectorDiff diff([ByRef]VersionVector rhs); + bytes encode(); + [Name=decode] + constructor([ByRef]bytes bytes); + Ordering? partial_cmp([ByRef]VersionVector other); }; interface Frontiers{ }; +dictionary VersionVectorDiff{ + /// need to add these spans to move from right to left + record left; + /// need to add these spans to move from left to right + record right; +}; + // ============= UNDO MANAGER ============= interface UndoManager{ From e27ec59a53b2a6e35cc175b12a4344ce14be6c55 Mon Sep 17 00:00:00 2001 From: leeeon233 Date: Fri, 27 Sep 2024 15:02:58 +0800 Subject: [PATCH 03/12] feat: ffi frontiers --- loro-rs/src/loro.udl | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/loro-rs/src/loro.udl b/loro-rs/src/loro.udl index bdf489b..5192514 100644 --- a/loro-rs/src/loro.udl +++ b/loro-rs/src/loro.udl @@ -703,9 +703,12 @@ interface LoroTree{ [Throws=LoroError] boolean is_node_deleted(TreeID target); - /// Return all nodes + /// Return all nodes, including deleted nodes sequence nodes(); - + + /// Get the root nodes of the forest. + sequence roots(); + /// Return all children of the target node. /// /// If the parent node does not exist, return `None`. @@ -999,13 +1002,22 @@ interface VersionVector{ void extend_to_include_vv([ByRef]VersionVector other); VersionVectorDiff diff([ByRef]VersionVector rhs); bytes encode(); - [Name=decode] + [Name=decode, Throws=LoroError] constructor([ByRef]bytes bytes); Ordering? partial_cmp([ByRef]VersionVector other); + boolean eq([ByRef]VersionVector other); }; interface Frontiers{ - + constructor(); + [Name=from_id] + constructor(ID id); + [Name=from_ids] + constructor(sequence ids); + bytes encode(); + [Name=decode, Throws=LoroError] + constructor([ByRef]bytes bytes); + boolean eq([ByRef]Frontiers other); }; dictionary VersionVectorDiff{ From e39a8ea69ba09dd0dc26da39a9bd34aaac7437b2 Mon Sep 17 00:00:00 2001 From: leeeon233 Date: Fri, 27 Sep 2024 15:35:06 +0800 Subject: [PATCH 04/12] feat: ffi awareness --- loro-rs/src/loro.udl | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/loro-rs/src/loro.udl b/loro-rs/src/loro.udl index 5192514..16d1182 100644 --- a/loro-rs/src/loro.udl +++ b/loro-rs/src/loro.udl @@ -986,6 +986,28 @@ dictionary AbsolutePosition{ Side side; }; +interface Awareness{ + constructor(u64 peer, i64 timeout); + bytes encode([ByRef]sequence peers); + bytes encode_all(); + AwarenessPeerUpdate apply([ByRef]bytes encoded_peers_info); + void set_local_state(LoroValueLike value); + LoroValue? get_local_state(); + sequence remove_outdated(); + record get_all_states(); + u64 peer(); +}; + +dictionary AwarenessPeerUpdate{ + sequence updated; + sequence added; +}; + +dictionary PeerInfo{ + LoroValue state; + i32 counter; + i64 timestamp; +}; // ============= VERSIONS ============= interface VersionVector{ From 7517cbc118ddf78099d2fa188f0e3b531c0adcd1 Mon Sep 17 00:00:00 2001 From: leeeon233 Date: Fri, 27 Sep 2024 16:04:34 +0800 Subject: [PATCH 05/12] fix: merge dev --- loro-rs/Cargo.lock | 23 +++++++++++++++++++++++ loro-rs/src/loro.udl | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/loro-rs/Cargo.lock b/loro-rs/Cargo.lock index ffaa9de..44007df 100644 --- a/loro-rs/Cargo.lock +++ b/loro-rs/Cargo.lock @@ -346,6 +346,12 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "either" version = "1.13.0" @@ -711,6 +717,7 @@ dependencies = [ "num-traits", "once_cell", "postcard", + "pretty_assertions", "rand", "serde", "serde_columnar", @@ -1004,6 +1011,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -1620,6 +1637,12 @@ version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "zerocopy" version = "0.6.6" diff --git a/loro-rs/src/loro.udl b/loro-rs/src/loro.udl index 16d1182..202a381 100644 --- a/loro-rs/src/loro.udl +++ b/loro-rs/src/loro.udl @@ -1338,7 +1338,8 @@ enum LoroError { "InvalidRootContainerName", "ImportUpdatesThatDependsOnOutdatedVersion", "SwitchToTrimmedVersion", - "ContainerDeleted" + "ContainerDeleted", + "ConcurrentOpsWithSamePeerID", }; [Error] From 1be951a90cbcc423302bb5d61f86567e2a49f9eb Mon Sep 17 00:00:00 2001 From: Leon Zhao Date: Sat, 5 Oct 2024 11:56:19 +0800 Subject: [PATCH 06/12] fix: add import status --- loro-rs/src/impl_udl.rs | 64 ----------------------------------------- loro-rs/src/lib.rs | 1 - loro-rs/src/loro.udl | 31 +++++++++++++------- 3 files changed, 20 insertions(+), 76 deletions(-) delete mode 100644 loro-rs/src/impl_udl.rs diff --git a/loro-rs/src/impl_udl.rs b/loro-rs/src/impl_udl.rs deleted file mode 100644 index dbc6ade..0000000 --- a/loro-rs/src/impl_udl.rs +++ /dev/null @@ -1,64 +0,0 @@ -use loro_ffi::SubID; -// use loro_ffi::{Counter, Lamport, PeerID}; - -use crate::UniffiCustomTypeConverter; - -// impl UniffiCustomTypeConverter for PeerID { -// type Builtin = u64; - -// fn into_custom(val: Self::Builtin) -> uniffi::Result -// where -// Self: Sized, -// { -// Ok(PeerID(val)) -// } - -// fn from_custom(obj: Self) -> Self::Builtin { -// obj.0 -// } -// } - -// impl UniffiCustomTypeConverter for Lamport { -// type Builtin = u32; - -// fn into_custom(val: Self::Builtin) -> uniffi::Result -// where -// Self: Sized, -// { -// Ok(Lamport(val)) -// } - -// fn from_custom(obj: Self) -> Self::Builtin { -// obj.0 -// } -// } - -// impl UniffiCustomTypeConverter for Counter { -// type Builtin = i32; - -// fn into_custom(val: Self::Builtin) -> uniffi::Result -// where -// Self: Sized, -// { -// Ok(Counter(val)) -// } - -// fn from_custom(obj: Self) -> Self::Builtin { -// obj.0 -// } -// } - -impl UniffiCustomTypeConverter for SubID { - type Builtin = u32; - - fn into_custom(val: Self::Builtin) -> uniffi::Result - where - Self: Sized, - { - Ok(SubID::from_u32(val)) - } - - fn from_custom(obj: Self) -> Self::Builtin { - SubID::into_u32(obj) - } -} diff --git a/loro-rs/src/lib.rs b/loro-rs/src/lib.rs index 4b904f9..83cb291 100644 --- a/loro-rs/src/lib.rs +++ b/loro-rs/src/lib.rs @@ -1,3 +1,2 @@ -mod impl_udl; use loro_ffi::*; uniffi::include_scaffolding!("loro"); diff --git a/loro-rs/src/loro.udl b/loro-rs/src/loro.udl index 202a381..a9d79c6 100644 --- a/loro-rs/src/loro.udl +++ b/loro-rs/src/loro.udl @@ -215,17 +215,17 @@ interface LoroDoc{ /// Import updates/snapshot exported by [`LoroDoc::export_snapshot`] or [`LoroDoc::export_from`]. [Throws=LoroError] - void import([ByRef]bytes bytes); + ImportStatus import([ByRef]bytes bytes); /// Import updates/snapshot exported by [`LoroDoc::export_snapshot`] or [`LoroDoc::export_from`]. /// /// It marks the import with a custom `origin` string. It can be used to track the import source /// in the generated events. [Throws=LoroError] - void import_with([ByRef] bytes bytes, [ByRef] string origin); + ImportStatus import_with([ByRef] bytes bytes, [ByRef] string origin); [Throws=LoroError] - void import_json_updates([ByRef]string json); + ImportStatus import_json_updates([ByRef]string json); /// Export the current state with json-string format of the document. string export_json_updates([ByRef]VersionVector start_vv, [ByRef]VersionVector end_vv); @@ -291,16 +291,13 @@ interface LoroDoc{ /// /// The callback will be invoked when the container is changed. /// Returns a subscription id that can be used to unsubscribe. - SubID subscribe([ByRef] ContainerID container_id, Subscriber subscriber); + Subscription subscribe([ByRef] ContainerID container_id, Subscriber subscriber); /// Subscribe all the events. /// /// The callback will be invoked when any part of the [loro_internal::DocState] is changed. /// Returns a subscription id that can be used to unsubscribe. - SubID subscribe_root(Subscriber subscriber); - - /// Remove a subscription. - void unsubscribe(SubID sub_id); + Subscription subscribe_root(Subscriber subscriber); /// Subscribe the local update of the document. Subscription subscribe_local_update(LocalUpdateCallback callback); @@ -342,8 +339,9 @@ interface LoroDoc{ bytes export_updates_in_range([ByRef]sequence spans); - bytes export_gc_snapshot([ByRef]Frontiers frontiers); + bytes export_trimmed_snapshot([ByRef]Frontiers frontiers); + [Throws=LoroEncodeError] bytes export_state_only(Frontiers? frontiers); // /// Analyze the container info of the doc @@ -921,6 +919,11 @@ dictionary ImportBlobMetadata{ boolean is_snapshot; }; +dictionary ImportStatus{ + record success; + record? pending; +}; + enum Ordering{ "Less", "Equal", "Greater" }; @@ -1270,8 +1273,6 @@ dictionary CounterSpan{ i32 end; }; -[Custom] -typedef u32 SubID; [Enum] interface ContainerType{ @@ -1340,6 +1341,7 @@ enum LoroError { "SwitchToTrimmedVersion", "ContainerDeleted", "ConcurrentOpsWithSamePeerID", + "InvalidPeerID", }; [Error] @@ -1353,4 +1355,11 @@ enum CannotFindRelativePosition{ enum JsonPathError{ "InvalidJsonPath", "EvaluationError" +}; + +[Error, NonExhaustive] +enum LoroEncodeError{ + "FrontiersNotFound", + "TrimmedSnapshotIncompatibleWithOldFormat", + "UnknownContainer", }; \ No newline at end of file From efe984a96f604e820479b3447e0da89d27fc8053 Mon Sep 17 00:00:00 2001 From: Leon Zhao Date: Sat, 5 Oct 2024 20:21:54 +0800 Subject: [PATCH 07/12] fix: import status dev --- Package.swift | 16 +- Sources/Loro/Event.swift | 34 +- Sources/Loro/LoroFFI.swift | 3745 ++++++++++++++++++++++++++++--- Sources/Loro/Value.swift | 9 +- Sources/Loro/Version.swift | 11 + Tests/LoroTests/LoroTests.swift | 5 +- 6 files changed, 3535 insertions(+), 285 deletions(-) create mode 100644 Sources/Loro/Version.swift diff --git a/Package.swift b/Package.swift index 3752229..e0efd5d 100644 --- a/Package.swift +++ b/Package.swift @@ -6,15 +6,15 @@ import PackageDescription let FFIbinaryTarget: PackageDescription.Target -if ProcessInfo.processInfo.environment["LOCAL_BUILD"] != nil { +// if ProcessInfo.processInfo.environment["LOCAL_BUILD"] != nil { FFIbinaryTarget = .binaryTarget(name: "LoroFFI", path: "./loroFFI.xcframework.zip") -}else { - FFIbinaryTarget = .binaryTarget( - name: "LoroFFI", - url: "https://github.com/loro-dev/loro-swift/releases/download/0.16.2-alpha.2/loroFFI.xcframework.zip", - checksum: "002f5343f0088f05ac90183e5dc1545e6b1f53f39b547ec7d3c2aa07d0f643c8" - ) -} +// }else { +// FFIbinaryTarget = .binaryTarget( +// name: "LoroFFI", +// url: "https://github.com/loro-dev/loro-swift/releases/download/0.16.2-alpha.2/loroFFI.xcframework.zip", +// checksum: "002f5343f0088f05ac90183e5dc1545e6b1f53f39b547ec7d3c2aa07d0f643c8" +// ) +// } let package = Package( name: "Loro", diff --git a/Sources/Loro/Event.swift b/Sources/Loro/Event.swift index deb0176..284427f 100644 --- a/Sources/Loro/Event.swift +++ b/Sources/Loro/Event.swift @@ -1,4 +1,4 @@ - +import Foundation class ClosureSubscriber: Subscriber { private let closure: (DiffEvent) -> Void @@ -12,13 +12,25 @@ class ClosureSubscriber: Subscriber { } } +class ClosureLocalUpdate: LocalUpdateCallback{ + private let closure: (Data) -> Void + + public init(closure: @escaping (Data) -> Void) { + self.closure = closure + } + + public func onLocalUpdate(update: Data) { + closure(update) + } +} + extension LoroDoc{ /** Subscribe all the events. * - * The callback will be invoked when any part of the [loro_internal::DocState] is changed. + * The callback will be invoked when any part of the [DocState] is changed. * Returns a subscription id that can be used to unsubscribe. */ - public func subscribeRoot(callback: @escaping (DiffEvent)->Void) -> SubId { + public func subscribeRoot(callback: @escaping (DiffEvent)->Void) -> Subscription { let closureSubscriber = ClosureSubscriber(closure: callback) return self.subscribeRoot(subscriber: closureSubscriber) } @@ -27,9 +39,23 @@ extension LoroDoc{ * * The callback will be invoked when the container is changed. * Returns a subscription id that can be used to unsubscribe. + * + * The events will be emitted after a transaction is committed. A transaction is committed when: + * - `doc.commit()` is called. + * - `doc.exportFrom(version)` is called. + * - `doc.import(data)` is called. + * - `doc.checkout(version)` is called. */ - public func subscribe(containerId: ContainerId, callback: @escaping (DiffEvent)->Void) -> SubId { + public func subscribe(containerId: ContainerId, callback: @escaping (DiffEvent)->Void) -> Subscription { let closureSubscriber = ClosureSubscriber(closure: callback) return self.subscribe(containerId: containerId, subscriber: closureSubscriber) } + + /** + * Subscribe the local update of the document. + */ + public func subscribeLocalUpdate(callback: @escaping (Data)->Void)->Subscription{ + let closureLocalUpdate = ClosureLocalUpdate(closure: callback) + return self.subscribeLocalUpdate(callback: closureLocalUpdate) + } } diff --git a/Sources/Loro/LoroFFI.swift b/Sources/Loro/LoroFFI.swift index ba95e3b..f259c75 100644 --- a/Sources/Loro/LoroFFI.swift +++ b/Sources/Loro/LoroFFI.swift @@ -537,6 +537,329 @@ fileprivate struct FfiConverterData: FfiConverterRustBuffer { +public protocol AwarenessProtocol : AnyObject { + + func apply(encodedPeersInfo: Data) -> AwarenessPeerUpdate + + func encode(peers: [UInt64]) -> Data + + func encodeAll() -> Data + + func getAllStates() -> [UInt64: PeerInfo] + + func getLocalState() -> LoroValue? + + func peer() -> UInt64 + + func removeOutdated() -> [UInt64] + + func setLocalState(value: LoroValueLike) + +} + +open class Awareness: + AwarenessProtocol { + fileprivate let pointer: UnsafeMutableRawPointer! + + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + /// This constructor can be used to instantiate a fake object. + /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + /// + /// - Warning: + /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + public init(noPointer: NoPointer) { + self.pointer = nil + } + + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_loro_fn_clone_awareness(self.pointer, $0) } + } +public convenience init(peer: UInt64, timeout: Int64) { + let pointer = + try! rustCall() { + uniffi_loro_fn_constructor_awareness_new( + FfiConverterUInt64.lower(peer), + FfiConverterInt64.lower(timeout),$0 + ) +} + self.init(unsafeFromRawPointer: pointer) +} + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_loro_fn_free_awareness(pointer, $0) } + } + + + + +open func apply(encodedPeersInfo: Data) -> AwarenessPeerUpdate { + return try! FfiConverterTypeAwarenessPeerUpdate.lift(try! rustCall() { + uniffi_loro_fn_method_awareness_apply(self.uniffiClonePointer(), + FfiConverterData.lower(encodedPeersInfo),$0 + ) +}) +} + +open func encode(peers: [UInt64]) -> Data { + return try! FfiConverterData.lift(try! rustCall() { + uniffi_loro_fn_method_awareness_encode(self.uniffiClonePointer(), + FfiConverterSequenceUInt64.lower(peers),$0 + ) +}) +} + +open func encodeAll() -> Data { + return try! FfiConverterData.lift(try! rustCall() { + uniffi_loro_fn_method_awareness_encode_all(self.uniffiClonePointer(),$0 + ) +}) +} + +open func getAllStates() -> [UInt64: PeerInfo] { + return try! FfiConverterDictionaryUInt64TypePeerInfo.lift(try! rustCall() { + uniffi_loro_fn_method_awareness_get_all_states(self.uniffiClonePointer(),$0 + ) +}) +} + +open func getLocalState() -> LoroValue? { + return try! FfiConverterOptionTypeLoroValue.lift(try! rustCall() { + uniffi_loro_fn_method_awareness_get_local_state(self.uniffiClonePointer(),$0 + ) +}) +} + +open func peer() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall() { + uniffi_loro_fn_method_awareness_peer(self.uniffiClonePointer(),$0 + ) +}) +} + +open func removeOutdated() -> [UInt64] { + return try! FfiConverterSequenceUInt64.lift(try! rustCall() { + uniffi_loro_fn_method_awareness_remove_outdated(self.uniffiClonePointer(),$0 + ) +}) +} + +open func setLocalState(value: LoroValueLike) {try! rustCall() { + uniffi_loro_fn_method_awareness_set_local_state(self.uniffiClonePointer(), + FfiConverterTypeLoroValueLike.lower(value),$0 + ) +} +} + + +} + +public struct FfiConverterTypeAwareness: FfiConverter { + + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Awareness + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Awareness { + return Awareness(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: Awareness) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Awareness { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: Awareness, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + + + + +public func FfiConverterTypeAwareness_lift(_ pointer: UnsafeMutableRawPointer) throws -> Awareness { + return try FfiConverterTypeAwareness.lift(pointer) +} + +public func FfiConverterTypeAwareness_lower(_ value: Awareness) -> UnsafeMutableRawPointer { + return FfiConverterTypeAwareness.lower(value) +} + + + + +public protocol ConfigureProtocol : AnyObject { + + func fork() -> Configure + + func mergeInterval() -> Int64 + + func recordTimestamp() -> Bool + + func setMergeInterval(interval: Int64) + + func setRecordTimestamp(record: Bool) + + func textStyleConfig() -> StyleConfigMap + +} + +open class Configure: + ConfigureProtocol { + fileprivate let pointer: UnsafeMutableRawPointer! + + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + /// This constructor can be used to instantiate a fake object. + /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + /// + /// - Warning: + /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + public init(noPointer: NoPointer) { + self.pointer = nil + } + + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_loro_fn_clone_configure(self.pointer, $0) } + } + // No primary constructor declared for this class. + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_loro_fn_free_configure(pointer, $0) } + } + + + + +open func fork() -> Configure { + return try! FfiConverterTypeConfigure.lift(try! rustCall() { + uniffi_loro_fn_method_configure_fork(self.uniffiClonePointer(),$0 + ) +}) +} + +open func mergeInterval() -> Int64 { + return try! FfiConverterInt64.lift(try! rustCall() { + uniffi_loro_fn_method_configure_merge_interval(self.uniffiClonePointer(),$0 + ) +}) +} + +open func recordTimestamp() -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_configure_record_timestamp(self.uniffiClonePointer(),$0 + ) +}) +} + +open func setMergeInterval(interval: Int64) {try! rustCall() { + uniffi_loro_fn_method_configure_set_merge_interval(self.uniffiClonePointer(), + FfiConverterInt64.lower(interval),$0 + ) +} +} + +open func setRecordTimestamp(record: Bool) {try! rustCall() { + uniffi_loro_fn_method_configure_set_record_timestamp(self.uniffiClonePointer(), + FfiConverterBool.lower(record),$0 + ) +} +} + +open func textStyleConfig() -> StyleConfigMap { + return try! FfiConverterTypeStyleConfigMap.lift(try! rustCall() { + uniffi_loro_fn_method_configure_text_style_config(self.uniffiClonePointer(),$0 + ) +}) +} + + +} + +public struct FfiConverterTypeConfigure: FfiConverter { + + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Configure + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Configure { + return Configure(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: Configure) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Configure { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: Configure, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + + + + +public func FfiConverterTypeConfigure_lift(_ pointer: UnsafeMutableRawPointer) throws -> Configure { + return try FfiConverterTypeConfigure.lift(pointer) +} + +public func FfiConverterTypeConfigure_lower(_ value: Configure) -> UnsafeMutableRawPointer { + return FfiConverterTypeConfigure.lower(value) +} + + + + public protocol ContainerIdLike: Any { func asContainerId(ty: ContainerType) -> ContainerId @@ -798,12 +1121,14 @@ public func FfiConverterTypeCursor_lower(_ value: Cursor) -> UnsafeMutableRawPoi -public protocol FrontiersProtocol : AnyObject { +public protocol FractionalIndexProtocol : AnyObject { + + func toString() -> String } -open class Frontiers: - FrontiersProtocol { +open class FractionalIndex: + FractionalIndexProtocol { fileprivate let pointer: UnsafeMutableRawPointer! /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. @@ -828,7 +1153,7 @@ open class Frontiers: } public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_loro_fn_clone_frontiers(self.pointer, $0) } + return try! rustCall { uniffi_loro_fn_clone_fractionalindex(self.pointer, $0) } } // No primary constructor declared for this class. @@ -837,13 +1162,179 @@ open class Frontiers: return } - try! rustCall { uniffi_loro_fn_free_frontiers(pointer, $0) } + try! rustCall { uniffi_loro_fn_free_fractionalindex(pointer, $0) } } - +public static func fromBytes(bytes: Data) -> FractionalIndex { + return try! FfiConverterTypeFractionalIndex.lift(try! rustCall() { + uniffi_loro_fn_constructor_fractionalindex_from_bytes( + FfiConverterData.lower(bytes),$0 + ) +}) +} - +public static func fromHexString(str: String) -> FractionalIndex { + return try! FfiConverterTypeFractionalIndex.lift(try! rustCall() { + uniffi_loro_fn_constructor_fractionalindex_from_hex_string( + FfiConverterString.lower(str),$0 + ) +}) +} + + + +open func toString() -> String { + return try! FfiConverterString.lift(try! rustCall() { + uniffi_loro_fn_method_fractionalindex_to_string(self.uniffiClonePointer(),$0 + ) +}) +} + + +} + +public struct FfiConverterTypeFractionalIndex: FfiConverter { + + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = FractionalIndex + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> FractionalIndex { + return FractionalIndex(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: FractionalIndex) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FractionalIndex { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: FractionalIndex, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + + + + +public func FfiConverterTypeFractionalIndex_lift(_ pointer: UnsafeMutableRawPointer) throws -> FractionalIndex { + return try FfiConverterTypeFractionalIndex.lift(pointer) +} + +public func FfiConverterTypeFractionalIndex_lower(_ value: FractionalIndex) -> UnsafeMutableRawPointer { + return FfiConverterTypeFractionalIndex.lower(value) +} + + + + +public protocol FrontiersProtocol : AnyObject { + + func encode() -> Data + + func eq(other: Frontiers) -> Bool + +} + +open class Frontiers: + FrontiersProtocol { + fileprivate let pointer: UnsafeMutableRawPointer! + + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + /// This constructor can be used to instantiate a fake object. + /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + /// + /// - Warning: + /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + public init(noPointer: NoPointer) { + self.pointer = nil + } + + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_loro_fn_clone_frontiers(self.pointer, $0) } + } +public convenience init() { + let pointer = + try! rustCall() { + uniffi_loro_fn_constructor_frontiers_new($0 + ) +} + self.init(unsafeFromRawPointer: pointer) +} + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_loro_fn_free_frontiers(pointer, $0) } + } + + +public static func decode(bytes: Data)throws -> Frontiers { + return try FfiConverterTypeFrontiers.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { + uniffi_loro_fn_constructor_frontiers_decode( + FfiConverterData.lower(bytes),$0 + ) +}) +} + +public static func fromId(id: Id) -> Frontiers { + return try! FfiConverterTypeFrontiers.lift(try! rustCall() { + uniffi_loro_fn_constructor_frontiers_from_id( + FfiConverterTypeID.lower(id),$0 + ) +}) +} + +public static func fromIds(ids: [Id]) -> Frontiers { + return try! FfiConverterTypeFrontiers.lift(try! rustCall() { + uniffi_loro_fn_constructor_frontiers_from_ids( + FfiConverterSequenceTypeID.lower(ids),$0 + ) +}) +} + + + +open func encode() -> Data { + return try! FfiConverterData.lift(try! rustCall() { + uniffi_loro_fn_method_frontiers_encode(self.uniffiClonePointer(),$0 + ) +}) +} + +open func eq(other: Frontiers) -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_frontiers_eq(self.uniffiClonePointer(), + FfiConverterTypeFrontiers.lower(other),$0 + ) +}) +} + + } public struct FfiConverterTypeFrontiers: FfiConverter { @@ -891,12 +1382,14 @@ public func FfiConverterTypeFrontiers_lower(_ value: Frontiers) -> UnsafeMutable -public protocol IdSpanProtocol : AnyObject { +public protocol LocalUpdateCallback : AnyObject { + + func onLocalUpdate(update: Data) } -open class IdSpan: - IdSpanProtocol { +open class LocalUpdateCallbackImpl: + LocalUpdateCallback { fileprivate let pointer: UnsafeMutableRawPointer! /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. @@ -921,7 +1414,7 @@ open class IdSpan: } public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_loro_fn_clone_idspan(self.pointer, $0) } + return try! rustCall { uniffi_loro_fn_clone_localupdatecallback(self.pointer, $0) } } // No primary constructor declared for this class. @@ -930,29 +1423,84 @@ open class IdSpan: return } - try! rustCall { uniffi_loro_fn_free_idspan(pointer, $0) } + try! rustCall { uniffi_loro_fn_free_localupdatecallback(pointer, $0) } } +open func onLocalUpdate(update: Data) {try! rustCall() { + uniffi_loro_fn_method_localupdatecallback_on_local_update(self.uniffiClonePointer(), + FfiConverterData.lower(update),$0 + ) +} +} + + +} + + +// Put the implementation in a struct so we don't pollute the top-level namespace +fileprivate struct UniffiCallbackInterfaceLocalUpdateCallback { + + // Create the VTable using a series of closures. + // Swift automatically converts these into C callback functions. + static var vtable: UniffiVTableCallbackInterfaceLocalUpdateCallback = UniffiVTableCallbackInterfaceLocalUpdateCallback( + onLocalUpdate: { ( + uniffiHandle: UInt64, + update: RustBuffer, + uniffiOutReturn: UnsafeMutableRawPointer, + uniffiCallStatus: UnsafeMutablePointer + ) in + let makeCall = { + () throws -> () in + guard let uniffiObj = try? FfiConverterTypeLocalUpdateCallback.handleMap.get(handle: uniffiHandle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return uniffiObj.onLocalUpdate( + update: try FfiConverterData.lift(update) + ) + } + + + let writeReturn = { () } + uniffiTraitInterfaceCall( + callStatus: uniffiCallStatus, + makeCall: makeCall, + writeReturn: writeReturn + ) + }, + uniffiFree: { (uniffiHandle: UInt64) -> () in + let result = try? FfiConverterTypeLocalUpdateCallback.handleMap.remove(handle: uniffiHandle) + if result == nil { + print("Uniffi callback interface LocalUpdateCallback: handle missing in uniffiFree") + } + } + ) +} +private func uniffiCallbackInitLocalUpdateCallback() { + uniffi_loro_fn_init_callback_vtable_localupdatecallback(&UniffiCallbackInterfaceLocalUpdateCallback.vtable) } -public struct FfiConverterTypeIdSpan: FfiConverter { +public struct FfiConverterTypeLocalUpdateCallback: FfiConverter { + fileprivate static var handleMap = UniffiHandleMap() typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = IdSpan + typealias SwiftType = LocalUpdateCallback - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> IdSpan { - return IdSpan(unsafeFromRawPointer: pointer) + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> LocalUpdateCallback { + return LocalUpdateCallbackImpl(unsafeFromRawPointer: pointer) } - public static func lower(_ value: IdSpan) -> UnsafeMutableRawPointer { - return value.uniffiClonePointer() + public static func lower(_ value: LocalUpdateCallback) -> UnsafeMutableRawPointer { + guard let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: handleMap.insert(obj: value))) else { + fatalError("Cast to UnsafeMutableRawPointer failed") + } + return ptr } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> IdSpan { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LocalUpdateCallback { let v: UInt64 = try readInt(&buf) // The Rust code won't compile if a pointer won't fit in a UInt64. // We have to go via `UInt` because that's the thing that's the size of a pointer. @@ -963,7 +1511,7 @@ public struct FfiConverterTypeIdSpan: FfiConverter { return try lift(ptr!) } - public static func write(_ value: IdSpan, into buf: inout [UInt8]) { + public static func write(_ value: LocalUpdateCallback, into buf: inout [UInt8]) { // This fiddling is because `Int` is the thing that's the same size as a pointer. // The Rust code won't compile if a pointer won't fit in a `UInt64`. writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) @@ -973,12 +1521,12 @@ public struct FfiConverterTypeIdSpan: FfiConverter { -public func FfiConverterTypeIdSpan_lift(_ pointer: UnsafeMutableRawPointer) throws -> IdSpan { - return try FfiConverterTypeIdSpan.lift(pointer) +public func FfiConverterTypeLocalUpdateCallback_lift(_ pointer: UnsafeMutableRawPointer) throws -> LocalUpdateCallback { + return try FfiConverterTypeLocalUpdateCallback.lift(pointer) } -public func FfiConverterTypeIdSpan_lower(_ value: IdSpan) -> UnsafeMutableRawPointer { - return FfiConverterTypeIdSpan.lower(value) +public func FfiConverterTypeLocalUpdateCallback_lower(_ value: LocalUpdateCallback) -> UnsafeMutableRawPointer { + return FfiConverterTypeLocalUpdateCallback.lower(value) } @@ -1159,6 +1707,12 @@ public protocol LoroDocProtocol : AnyObject { */ func attach() + /** + * Check the correctness of the document state by comparing it with the state + * calculated by applying all the history. + */ + func checkStateCorrectnessSlow() + /** * Checkout the `DocState` to a specific version. * @@ -1183,6 +1737,13 @@ public protocol LoroDocProtocol : AnyObject { */ func checkoutToLatest() + /** + * Compare the frontiers with the current OpLog's version. + * + * If `other` contains any version that's not contained in the current OpLog, return [Ordering::Less]. + */ + func cmpWithFrontiers(other: Frontiers) -> Ordering + /** * Commit the cumulative auto commit transaction. * @@ -1192,6 +1753,36 @@ public protocol LoroDocProtocol : AnyObject { */ func commit() + func commitWith(options: CommitOptions) + + /** + * Encoded all ops and history cache to bytes and store them in the kv store. + * + * The parsed ops will be dropped + */ + func compactChangeStore() + + /** + * Get the configurations of the document. + */ + func config() -> Configure + + /** + * Set the rich text format configuration of the document. + * + * You need to config it if you use rich text `mark` method. + * Specifically, you need to config the `expand` property of each style. + * + * Expand is used to specify the behavior of expanding when new text is inserted at the + * beginning or end of the style. + */ + func configTextStyle(textStyle: StyleConfigMap) + + /** + * Decodes the metadata for an imported blob from the provided bytes. + */ + func decodeImportBlobMeta(bytes: Data) throws -> ImportBlobMetadata + /** * Force the document enter the detached mode. * @@ -1206,11 +1797,22 @@ public protocol LoroDocProtocol : AnyObject { */ func exportFrom(vv: VersionVector) -> Data + /** + * Export the current state with json-string format of the document. + */ + func exportJsonUpdates(startVv: VersionVector, endVv: VersionVector) -> String + /** * Export the current state and history of the document. */ func exportSnapshot() -> Data + func exportStateOnly(frontiers: Frontiers?) throws -> Data + + func exportTrimmedSnapshot(frontiers: Frontiers) -> Data + + func exportUpdatesInRange(spans: [IdSpan]) -> Data + /** * Duplicate the document with a different PeerID * @@ -1218,6 +1820,19 @@ public protocol LoroDocProtocol : AnyObject { */ func fork() -> LoroDoc + /** + * Free the cached diff calculator that is used for checkout. + */ + func freeDiffCalculator() + + /** + * Free the history cache that is used for making checkout faster. + * + * If you use checkout that switching to an old/concurrent version, the history cache will be built. + * You can free it by calling this method. + */ + func freeHistoryCache() + /** * Convert `Frontiers` into `VersionVector` */ @@ -1233,6 +1848,23 @@ public protocol LoroDocProtocol : AnyObject { */ func getByStrPath(path: String) -> ValueOrContainer? + /** + * Get `Change` at the given id. + * + * `Change` is a grouped continuous operations that share the same id, timestamp, commit message. + * + * - The id of the `Change` is the id of its first op. + * - The second op's id is `{ peer: change.id.peer, counter: change.id.counter + 1 }` + * + * The same applies on `Lamport`: + * + * - The lamport of the `Change` is the lamport of its first op. + * - The second op's lamport is `change.lamport + 1` + * + * The length of the `Change` is how many operations it contains + */ + func getChange(id: Id) -> ChangeMeta? + /** * Get a [LoroCounter] by container id. * @@ -1240,11 +1872,18 @@ public protocol LoroDocProtocol : AnyObject { */ func getCounter(id: ContainerIdLike) -> LoroCounter + func getCursorPos(cursor: Cursor) throws -> PosQueryResult + /** * Get the current state of the document. */ func getDeepValue() -> LoroValue + /** + * Get the current state with container id of the doc + */ + func getDeepValueWithId() -> LoroValue + /** * Get a [LoroList] by container id. * @@ -1266,6 +1905,11 @@ public protocol LoroDocProtocol : AnyObject { */ func getMovableList(id: ContainerIdLike) -> LoroMovableList + /** + * Get the path from the root to the container + */ + func getPathToContainer(id: ContainerId) -> [ContainerPath]? + /** * Get a [LoroText] by container id. * @@ -1280,10 +1924,17 @@ public protocol LoroDocProtocol : AnyObject { */ func getTree(id: ContainerIdLike) -> LoroTree + /** + * Get the shallow value of the document. + */ + func getValue() -> LoroValue + + func hasHistoryCache() -> Bool + /** * Import updates/snapshot exported by [`LoroDoc::export_snapshot`] or [`LoroDoc::export_from`]. */ - func `import`(bytes: Data) throws + func `import`(bytes: Data) throws -> ImportStatus /** * Import a batch of updates/snapshot. @@ -1292,13 +1943,15 @@ public protocol LoroDocProtocol : AnyObject { */ func importBatch(bytes: [Data]) throws + func importJsonUpdates(json: String) throws -> ImportStatus + /** * Import updates/snapshot exported by [`LoroDoc::export_snapshot`] or [`LoroDoc::export_from`]. * * It marks the import with a custom `origin` string. It can be used to track the import source * in the generated events. */ - func importWith(bytes: Data, origin: String) throws + func importWith(bytes: Data, origin: String) throws -> ImportStatus /** * Whether the document is in detached mode, where the [loro_internal::DocState] is not @@ -1306,6 +1959,39 @@ public protocol LoroDocProtocol : AnyObject { */ func isDetached() -> Bool + /** + * Evaluate a JSONPath expression on the document and return matching values or handlers. + * + * This method allows querying the document structure using JSONPath syntax. + * It returns a vector of `ValueOrHandler` which can represent either primitive values + * or container handlers, depending on what the JSONPath expression matches. + * + * # Arguments + * + * * `path` - A string slice containing the JSONPath expression to evaluate. + * + * # Returns + * + * A `Result` containing either: + * - `Ok(Vec)`: A vector of matching values or handlers. + * - `Err(String)`: An error message if the JSONPath expression is invalid or evaluation fails. + * + * # Example + * + * ``` + * # use loro::LoroDoc; + * let doc = LoroDoc::new(); + * let map = doc.get_map("users"); + * map.insert("alice", 30).unwrap(); + * map.insert("bob", 25).unwrap(); + * + * let result = doc.jsonpath("$.users.alice").unwrap(); + * assert_eq!(result.len(), 1); + * assert_eq!(result[0].to_json_value(), serde_json::json!(30)); + * ``` + */ + func jsonpath(path: String) throws -> [ValueOrContainer] + /** * Get the total number of changes in the `OpLog` */ @@ -1316,6 +2002,11 @@ public protocol LoroDocProtocol : AnyObject { */ func lenOps() -> UInt64 + /** + * Estimate the size of the document states in memory. + */ + func logEstimateSize() + /** * Get the `Frontiers` version of `OpLog` */ @@ -1339,14 +2030,7 @@ public protocol LoroDocProtocol : AnyObject { */ func setChangeMergeInterval(interval: Int64) - /** - * Set the jitter of the tree position(Fractional Index). - * - * The jitter is used to avoid conflicts when multiple users are creating the node at the same position. - * value 0 is default, which means no jitter, any value larger than 0 will enable jitter. - * Generally speaking, jitter will affect the growth rate of document size. - */ - func setFractionalIndexJitter(jitter: UInt8) + func setNextCommitMessage(msg: String) /** * Change the PeerID @@ -1387,7 +2071,12 @@ public protocol LoroDocProtocol : AnyObject { * The callback will be invoked when the container is changed. * Returns a subscription id that can be used to unsubscribe. */ - func subscribe(containerId: ContainerId, subscriber: Subscriber) -> SubId + func subscribe(containerId: ContainerId, subscriber: Subscriber) -> Subscription + + /** + * Subscribe the local update of the document. + */ + func subscribeLocalUpdate(callback: LocalUpdateCallback) -> Subscription /** * Subscribe all the events. @@ -1395,12 +2084,14 @@ public protocol LoroDocProtocol : AnyObject { * The callback will be invoked when any part of the [loro_internal::DocState] is changed. * Returns a subscription id that can be used to unsubscribe. */ - func subscribeRoot(subscriber: Subscriber) -> SubId + func subscribeRoot(subscriber: Subscriber) -> Subscription /** - * Remove a subscription. + * Get the `VersionVector` of trimmed history + * + * The ops included by the trimmed history are not in the doc. */ - func unsubscribe(subId: SubId) + func trimmedVv() -> VersionVector /** * Convert `VersionVector` into `Frontiers` @@ -1475,8 +2166,18 @@ open func attach() {try! rustCall() { } /** - * Checkout the `DocState` to a specific version. - * + * Check the correctness of the document state by comparing it with the state + * calculated by applying all the history. + */ +open func checkStateCorrectnessSlow() {try! rustCall() { + uniffi_loro_fn_method_lorodoc_check_state_correctness_slow(self.uniffiClonePointer(),$0 + ) +} +} + + /** + * Checkout the `DocState` to a specific version. + * * > The document becomes detached during a `checkout` operation. * > Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`. * > In a detached state, the document is not editable, and any `import` operations will be @@ -1505,6 +2206,19 @@ open func checkoutToLatest() {try! rustCall() { uniffi_loro_fn_method_lorodoc_checkout_to_latest(self.uniffiClonePointer(),$0 ) } +} + + /** + * Compare the frontiers with the current OpLog's version. + * + * If `other` contains any version that's not contained in the current OpLog, return [Ordering::Less]. + */ +open func cmpWithFrontiers(other: Frontiers) -> Ordering { + return try! FfiConverterTypeOrdering.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_cmp_with_frontiers(self.uniffiClonePointer(), + FfiConverterTypeFrontiers.lower(other),$0 + ) +}) } /** @@ -1518,6 +2232,61 @@ open func commit() {try! rustCall() { uniffi_loro_fn_method_lorodoc_commit(self.uniffiClonePointer(),$0 ) } +} + +open func commitWith(options: CommitOptions) {try! rustCall() { + uniffi_loro_fn_method_lorodoc_commit_with(self.uniffiClonePointer(), + FfiConverterTypeCommitOptions.lower(options),$0 + ) +} +} + + /** + * Encoded all ops and history cache to bytes and store them in the kv store. + * + * The parsed ops will be dropped + */ +open func compactChangeStore() {try! rustCall() { + uniffi_loro_fn_method_lorodoc_compact_change_store(self.uniffiClonePointer(),$0 + ) +} +} + + /** + * Get the configurations of the document. + */ +open func config() -> Configure { + return try! FfiConverterTypeConfigure.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_config(self.uniffiClonePointer(),$0 + ) +}) +} + + /** + * Set the rich text format configuration of the document. + * + * You need to config it if you use rich text `mark` method. + * Specifically, you need to config the `expand` property of each style. + * + * Expand is used to specify the behavior of expanding when new text is inserted at the + * beginning or end of the style. + */ +open func configTextStyle(textStyle: StyleConfigMap) {try! rustCall() { + uniffi_loro_fn_method_lorodoc_config_text_style(self.uniffiClonePointer(), + FfiConverterTypeStyleConfigMap.lower(textStyle),$0 + ) +} +} + + /** + * Decodes the metadata for an imported blob from the provided bytes. + */ +open func decodeImportBlobMeta(bytes: Data)throws -> ImportBlobMetadata { + return try FfiConverterTypeImportBlobMetadata.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { + uniffi_loro_fn_method_lorodoc_decode_import_blob_meta(self.uniffiClonePointer(), + FfiConverterData.lower(bytes),$0 + ) +}) } /** @@ -1542,6 +2311,18 @@ open func exportFrom(vv: VersionVector) -> Data { FfiConverterTypeVersionVector.lower(vv),$0 ) }) +} + + /** + * Export the current state with json-string format of the document. + */ +open func exportJsonUpdates(startVv: VersionVector, endVv: VersionVector) -> String { + return try! FfiConverterString.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_export_json_updates(self.uniffiClonePointer(), + FfiConverterTypeVersionVector.lower(startVv), + FfiConverterTypeVersionVector.lower(endVv),$0 + ) +}) } /** @@ -1552,6 +2333,30 @@ open func exportSnapshot() -> Data { uniffi_loro_fn_method_lorodoc_export_snapshot(self.uniffiClonePointer(),$0 ) }) +} + +open func exportStateOnly(frontiers: Frontiers?)throws -> Data { + return try FfiConverterData.lift(try rustCallWithError(FfiConverterTypeLoroEncodeError.lift) { + uniffi_loro_fn_method_lorodoc_export_state_only(self.uniffiClonePointer(), + FfiConverterOptionTypeFrontiers.lower(frontiers),$0 + ) +}) +} + +open func exportTrimmedSnapshot(frontiers: Frontiers) -> Data { + return try! FfiConverterData.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_export_trimmed_snapshot(self.uniffiClonePointer(), + FfiConverterTypeFrontiers.lower(frontiers),$0 + ) +}) +} + +open func exportUpdatesInRange(spans: [IdSpan]) -> Data { + return try! FfiConverterData.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_export_updates_in_range(self.uniffiClonePointer(), + FfiConverterSequenceTypeIdSpan.lower(spans),$0 + ) +}) } /** @@ -1564,6 +2369,27 @@ open func fork() -> LoroDoc { uniffi_loro_fn_method_lorodoc_fork(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Free the cached diff calculator that is used for checkout. + */ +open func freeDiffCalculator() {try! rustCall() { + uniffi_loro_fn_method_lorodoc_free_diff_calculator(self.uniffiClonePointer(),$0 + ) +} +} + + /** + * Free the history cache that is used for making checkout faster. + * + * If you use checkout that switching to an old/concurrent version, the history cache will be built. + * You can free it by calling this method. + */ +open func freeHistoryCache() {try! rustCall() { + uniffi_loro_fn_method_lorodoc_free_history_cache(self.uniffiClonePointer(),$0 + ) +} } /** @@ -1597,6 +2423,29 @@ open func getByStrPath(path: String) -> ValueOrContainer? { FfiConverterString.lower(path),$0 ) }) +} + + /** + * Get `Change` at the given id. + * + * `Change` is a grouped continuous operations that share the same id, timestamp, commit message. + * + * - The id of the `Change` is the id of its first op. + * - The second op's id is `{ peer: change.id.peer, counter: change.id.counter + 1 }` + * + * The same applies on `Lamport`: + * + * - The lamport of the `Change` is the lamport of its first op. + * - The second op's lamport is `change.lamport + 1` + * + * The length of the `Change` is how many operations it contains + */ +open func getChange(id: Id) -> ChangeMeta? { + return try! FfiConverterOptionTypeChangeMeta.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_get_change(self.uniffiClonePointer(), + FfiConverterTypeID.lower(id),$0 + ) +}) } /** @@ -1610,6 +2459,14 @@ open func getCounter(id: ContainerIdLike) -> LoroCounter { FfiConverterTypeContainerIdLike.lower(id),$0 ) }) +} + +open func getCursorPos(cursor: Cursor)throws -> PosQueryResult { + return try FfiConverterTypePosQueryResult.lift(try rustCallWithError(FfiConverterTypeCannotFindRelativePosition.lift) { + uniffi_loro_fn_method_lorodoc_get_cursor_pos(self.uniffiClonePointer(), + FfiConverterTypeCursor.lower(cursor),$0 + ) +}) } /** @@ -1620,6 +2477,16 @@ open func getDeepValue() -> LoroValue { uniffi_loro_fn_method_lorodoc_get_deep_value(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Get the current state with container id of the doc + */ +open func getDeepValueWithId() -> LoroValue { + return try! FfiConverterTypeLoroValue.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_get_deep_value_with_id(self.uniffiClonePointer(),$0 + ) +}) } /** @@ -1659,6 +2526,17 @@ open func getMovableList(id: ContainerIdLike) -> LoroMovableList { FfiConverterTypeContainerIdLike.lower(id),$0 ) }) +} + + /** + * Get the path from the root to the container + */ +open func getPathToContainer(id: ContainerId) -> [ContainerPath]? { + return try! FfiConverterOptionSequenceTypeContainerPath.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_get_path_to_container(self.uniffiClonePointer(), + FfiConverterTypeContainerID.lower(id),$0 + ) +}) } /** @@ -1685,16 +2563,34 @@ open func getTree(id: ContainerIdLike) -> LoroTree { FfiConverterTypeContainerIdLike.lower(id),$0 ) }) +} + + /** + * Get the shallow value of the document. + */ +open func getValue() -> LoroValue { + return try! FfiConverterTypeLoroValue.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_get_value(self.uniffiClonePointer(),$0 + ) +}) +} + +open func hasHistoryCache() -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_has_history_cache(self.uniffiClonePointer(),$0 + ) +}) } /** * Import updates/snapshot exported by [`LoroDoc::export_snapshot`] or [`LoroDoc::export_from`]. */ -open func `import`(bytes: Data)throws {try rustCallWithError(FfiConverterTypeLoroError.lift) { +open func `import`(bytes: Data)throws -> ImportStatus { + return try FfiConverterTypeImportStatus.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { uniffi_loro_fn_method_lorodoc_import(self.uniffiClonePointer(), FfiConverterData.lower(bytes),$0 ) -} +}) } /** @@ -1707,6 +2603,14 @@ open func importBatch(bytes: [Data])throws {try rustCallWithError(FfiConverterT FfiConverterSequenceData.lower(bytes),$0 ) } +} + +open func importJsonUpdates(json: String)throws -> ImportStatus { + return try FfiConverterTypeImportStatus.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { + uniffi_loro_fn_method_lorodoc_import_json_updates(self.uniffiClonePointer(), + FfiConverterString.lower(json),$0 + ) +}) } /** @@ -1715,12 +2619,13 @@ open func importBatch(bytes: [Data])throws {try rustCallWithError(FfiConverterT * It marks the import with a custom `origin` string. It can be used to track the import source * in the generated events. */ -open func importWith(bytes: Data, origin: String)throws {try rustCallWithError(FfiConverterTypeLoroError.lift) { +open func importWith(bytes: Data, origin: String)throws -> ImportStatus { + return try FfiConverterTypeImportStatus.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { uniffi_loro_fn_method_lorodoc_import_with(self.uniffiClonePointer(), FfiConverterData.lower(bytes), FfiConverterString.lower(origin),$0 ) -} +}) } /** @@ -1732,6 +2637,45 @@ open func isDetached() -> Bool { uniffi_loro_fn_method_lorodoc_is_detached(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Evaluate a JSONPath expression on the document and return matching values or handlers. + * + * This method allows querying the document structure using JSONPath syntax. + * It returns a vector of `ValueOrHandler` which can represent either primitive values + * or container handlers, depending on what the JSONPath expression matches. + * + * # Arguments + * + * * `path` - A string slice containing the JSONPath expression to evaluate. + * + * # Returns + * + * A `Result` containing either: + * - `Ok(Vec)`: A vector of matching values or handlers. + * - `Err(String)`: An error message if the JSONPath expression is invalid or evaluation fails. + * + * # Example + * + * ``` + * # use loro::LoroDoc; + * let doc = LoroDoc::new(); + * let map = doc.get_map("users"); + * map.insert("alice", 30).unwrap(); + * map.insert("bob", 25).unwrap(); + * + * let result = doc.jsonpath("$.users.alice").unwrap(); + * assert_eq!(result.len(), 1); + * assert_eq!(result[0].to_json_value(), serde_json::json!(30)); + * ``` + */ +open func jsonpath(path: String)throws -> [ValueOrContainer] { + return try FfiConverterSequenceTypeValueOrContainer.lift(try rustCallWithError(FfiConverterTypeJsonPathError.lift) { + uniffi_loro_fn_method_lorodoc_jsonpath(self.uniffiClonePointer(), + FfiConverterString.lower(path),$0 + ) +}) } /** @@ -1752,6 +2696,15 @@ open func lenOps() -> UInt64 { uniffi_loro_fn_method_lorodoc_len_ops(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Estimate the size of the document states in memory. + */ +open func logEstimateSize() {try! rustCall() { + uniffi_loro_fn_method_lorodoc_log_estimate_size(self.uniffiClonePointer(),$0 + ) +} } /** @@ -1797,16 +2750,9 @@ open func setChangeMergeInterval(interval: Int64) {try! rustCall() { } } - /** - * Set the jitter of the tree position(Fractional Index). - * - * The jitter is used to avoid conflicts when multiple users are creating the node at the same position. - * value 0 is default, which means no jitter, any value larger than 0 will enable jitter. - * Generally speaking, jitter will affect the growth rate of document size. - */ -open func setFractionalIndexJitter(jitter: UInt8) {try! rustCall() { - uniffi_loro_fn_method_lorodoc_set_fractional_index_jitter(self.uniffiClonePointer(), - FfiConverterUInt8.lower(jitter),$0 +open func setNextCommitMessage(msg: String) {try! rustCall() { + uniffi_loro_fn_method_lorodoc_set_next_commit_message(self.uniffiClonePointer(), + FfiConverterString.lower(msg),$0 ) } } @@ -1870,13 +2816,24 @@ open func stateVv() -> VersionVector { * The callback will be invoked when the container is changed. * Returns a subscription id that can be used to unsubscribe. */ -open func subscribe(containerId: ContainerId, subscriber: Subscriber) -> SubId { - return try! FfiConverterTypeSubID.lift(try! rustCall() { +open func subscribe(containerId: ContainerId, subscriber: Subscriber) -> Subscription { + return try! FfiConverterTypeSubscription.lift(try! rustCall() { uniffi_loro_fn_method_lorodoc_subscribe(self.uniffiClonePointer(), FfiConverterTypeContainerID.lower(containerId), FfiConverterTypeSubscriber.lower(subscriber),$0 ) }) +} + + /** + * Subscribe the local update of the document. + */ +open func subscribeLocalUpdate(callback: LocalUpdateCallback) -> Subscription { + return try! FfiConverterTypeSubscription.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_subscribe_local_update(self.uniffiClonePointer(), + FfiConverterTypeLocalUpdateCallback.lower(callback),$0 + ) +}) } /** @@ -1885,8 +2842,8 @@ open func subscribe(containerId: ContainerId, subscriber: Subscriber) -> SubId { * The callback will be invoked when any part of the [loro_internal::DocState] is changed. * Returns a subscription id that can be used to unsubscribe. */ -open func subscribeRoot(subscriber: Subscriber) -> SubId { - return try! FfiConverterTypeSubID.lift(try! rustCall() { +open func subscribeRoot(subscriber: Subscriber) -> Subscription { + return try! FfiConverterTypeSubscription.lift(try! rustCall() { uniffi_loro_fn_method_lorodoc_subscribe_root(self.uniffiClonePointer(), FfiConverterTypeSubscriber.lower(subscriber),$0 ) @@ -1894,13 +2851,15 @@ open func subscribeRoot(subscriber: Subscriber) -> SubId { } /** - * Remove a subscription. + * Get the `VersionVector` of trimmed history + * + * The ops included by the trimmed history are not in the doc. */ -open func unsubscribe(subId: SubId) {try! rustCall() { - uniffi_loro_fn_method_lorodoc_unsubscribe(self.uniffiClonePointer(), - FfiConverterTypeSubID.lower(subId),$0 +open func trimmedVv() -> VersionVector { + return try! FfiConverterTypeVersionVector.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_trimmed_vv(self.uniffiClonePointer(),$0 ) -} +}) } /** @@ -3557,12 +4516,12 @@ public protocol LoroTreeProtocol : AnyObject { * * If the parent node does not exist, return `None`. */ - func children(parent: TreeId?) -> [TreeId]? + func children(parent: TreeParentId) -> [TreeId]? /** * Return the number of children of the target node. */ - func childrenNum(parent: TreeId?) -> UInt32? + func childrenNum(parent: TreeParentId) -> UInt32? /** * Return whether target node exists. @@ -3575,7 +4534,7 @@ public protocol LoroTreeProtocol : AnyObject { * If the `parent` is `None`, the created node is the root of a tree. * Otherwise, the created node is a child of the parent tree node. */ - func create(parent: TreeId?) throws -> TreeId + func create(parent: TreeParentId) throws -> TreeId /** * Create a new tree node at the given index and return the [`TreeID`]. @@ -3583,7 +4542,7 @@ public protocol LoroTreeProtocol : AnyObject { * If the `parent` is `None`, the created node is the root of a tree. * If the `index` is greater than the number of children of the parent, error will be returned. */ - func createAt(parent: TreeId?, index: UInt32) throws -> TreeId + func createAt(parent: TreeParentId, index: UInt32) throws -> TreeId /** * Delete a tree node. @@ -3593,6 +4552,23 @@ public protocol LoroTreeProtocol : AnyObject { */ func delete(target: TreeId) throws + /** + * Disable the fractional index generation for Tree Position when + * you don't need the Tree's siblings to be sorted. The fractional index will be always default. + */ + func disableFractionalIndex() + + /** + * Enable fractional index for Tree Position. + * + * The jitter is used to avoid conflicts when multiple users are creating the node at the same position. + * value 0 is default, which means no jitter, any value larger than 0 will enable jitter. + * + * Generally speaking, jitter will affect the growth rate of document size. + * [Read more about it](https://www.loro.dev/blog/movable-tree#implementation-and-encoding-size) + */ + func enableFractionalIndex(jitter: UInt8) + /** * Return the fractional index of the target node with hex format. */ @@ -3629,12 +4605,25 @@ public protocol LoroTreeProtocol : AnyObject { */ func isAttached() -> Bool + /** + * Whether the fractional index is enabled. + */ + func isFractionalIndexEnabled() -> Bool + + /** + * Return whether target node is deleted. + * + * # Errors + * - If the target node does not exist, return `LoroTreeError::TreeNodeNotExist`. + */ + func isNodeDeleted(target: TreeId) throws -> Bool + /** * Move the `target` node to be a child of the `parent` node. * * If the `parent` is `None`, the `target` node will be a root. */ - func mov(target: TreeId, parent: TreeId?) throws + func mov(target: TreeId, parent: TreeParentId) throws /** * Move the `target` node to be a child after the `after` node with the same parent. @@ -3650,10 +4639,10 @@ public protocol LoroTreeProtocol : AnyObject { * Move the `target` node to be a child of the `parent` node at the given index. * If the `parent` is `None`, the `target` node will be a root. */ - func movTo(target: TreeId, parent: TreeId?, to: UInt32) throws + func movTo(target: TreeId, parent: TreeParentId, to: UInt32) throws /** - * Return all nodes + * Return all nodes, including deleted nodes */ func nodes() -> [TreeId] @@ -3663,7 +4652,12 @@ public protocol LoroTreeProtocol : AnyObject { * - If the target node does not exist, throws Error. * - If the target node is a root node, return nil. */ - func parent(target: TreeId) throws -> TreeId? + func parent(target: TreeId) throws -> TreeParentId + + /** + * Get the root nodes of the forest. + */ + func roots() -> [TreeId] } @@ -3726,10 +4720,10 @@ public convenience init() { * * If the parent node does not exist, return `None`. */ -open func children(parent: TreeId?) -> [TreeId]? { +open func children(parent: TreeParentId) -> [TreeId]? { return try! FfiConverterOptionSequenceTypeTreeID.lift(try! rustCall() { uniffi_loro_fn_method_lorotree_children(self.uniffiClonePointer(), - FfiConverterOptionTypeTreeID.lower(parent),$0 + FfiConverterTypeTreeParentId.lower(parent),$0 ) }) } @@ -3737,10 +4731,10 @@ open func children(parent: TreeId?) -> [TreeId]? { /** * Return the number of children of the target node. */ -open func childrenNum(parent: TreeId?) -> UInt32? { +open func childrenNum(parent: TreeParentId) -> UInt32? { return try! FfiConverterOptionUInt32.lift(try! rustCall() { uniffi_loro_fn_method_lorotree_children_num(self.uniffiClonePointer(), - FfiConverterOptionTypeTreeID.lower(parent),$0 + FfiConverterTypeTreeParentId.lower(parent),$0 ) }) } @@ -3762,10 +4756,10 @@ open func contains(target: TreeId) -> Bool { * If the `parent` is `None`, the created node is the root of a tree. * Otherwise, the created node is a child of the parent tree node. */ -open func create(parent: TreeId?)throws -> TreeId { +open func create(parent: TreeParentId)throws -> TreeId { return try FfiConverterTypeTreeID.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { uniffi_loro_fn_method_lorotree_create(self.uniffiClonePointer(), - FfiConverterOptionTypeTreeID.lower(parent),$0 + FfiConverterTypeTreeParentId.lower(parent),$0 ) }) } @@ -3776,10 +4770,10 @@ open func create(parent: TreeId?)throws -> TreeId { * If the `parent` is `None`, the created node is the root of a tree. * If the `index` is greater than the number of children of the parent, error will be returned. */ -open func createAt(parent: TreeId?, index: UInt32)throws -> TreeId { +open func createAt(parent: TreeParentId, index: UInt32)throws -> TreeId { return try FfiConverterTypeTreeID.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { uniffi_loro_fn_method_lorotree_create_at(self.uniffiClonePointer(), - FfiConverterOptionTypeTreeID.lower(parent), + FfiConverterTypeTreeParentId.lower(parent), FfiConverterUInt32.lower(index),$0 ) }) @@ -3796,6 +4790,32 @@ open func delete(target: TreeId)throws {try rustCallWithError(FfiConverterTypeL FfiConverterTypeTreeID.lower(target),$0 ) } +} + + /** + * Disable the fractional index generation for Tree Position when + * you don't need the Tree's siblings to be sorted. The fractional index will be always default. + */ +open func disableFractionalIndex() {try! rustCall() { + uniffi_loro_fn_method_lorotree_disable_fractional_index(self.uniffiClonePointer(),$0 + ) +} +} + + /** + * Enable fractional index for Tree Position. + * + * The jitter is used to avoid conflicts when multiple users are creating the node at the same position. + * value 0 is default, which means no jitter, any value larger than 0 will enable jitter. + * + * Generally speaking, jitter will affect the growth rate of document size. + * [Read more about it](https://www.loro.dev/blog/movable-tree#implementation-and-encoding-size) + */ +open func enableFractionalIndex(jitter: UInt8) {try! rustCall() { + uniffi_loro_fn_method_lorotree_enable_fractional_index(self.uniffiClonePointer(), + FfiConverterUInt8.lower(jitter),$0 + ) +} } /** @@ -3864,6 +4884,30 @@ open func isAttached() -> Bool { uniffi_loro_fn_method_lorotree_is_attached(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Whether the fractional index is enabled. + */ +open func isFractionalIndexEnabled() -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_lorotree_is_fractional_index_enabled(self.uniffiClonePointer(),$0 + ) +}) +} + + /** + * Return whether target node is deleted. + * + * # Errors + * - If the target node does not exist, return `LoroTreeError::TreeNodeNotExist`. + */ +open func isNodeDeleted(target: TreeId)throws -> Bool { + return try FfiConverterBool.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { + uniffi_loro_fn_method_lorotree_is_node_deleted(self.uniffiClonePointer(), + FfiConverterTypeTreeID.lower(target),$0 + ) +}) } /** @@ -3871,10 +4915,10 @@ open func isAttached() -> Bool { * * If the `parent` is `None`, the `target` node will be a root. */ -open func mov(target: TreeId, parent: TreeId?)throws {try rustCallWithError(FfiConverterTypeLoroError.lift) { +open func mov(target: TreeId, parent: TreeParentId)throws {try rustCallWithError(FfiConverterTypeLoroError.lift) { uniffi_loro_fn_method_lorotree_mov(self.uniffiClonePointer(), FfiConverterTypeTreeID.lower(target), - FfiConverterOptionTypeTreeID.lower(parent),$0 + FfiConverterTypeTreeParentId.lower(parent),$0 ) } } @@ -3905,17 +4949,17 @@ open func movBefore(target: TreeId, before: TreeId)throws {try rustCallWithErro * Move the `target` node to be a child of the `parent` node at the given index. * If the `parent` is `None`, the `target` node will be a root. */ -open func movTo(target: TreeId, parent: TreeId?, to: UInt32)throws {try rustCallWithError(FfiConverterTypeLoroError.lift) { +open func movTo(target: TreeId, parent: TreeParentId, to: UInt32)throws {try rustCallWithError(FfiConverterTypeLoroError.lift) { uniffi_loro_fn_method_lorotree_mov_to(self.uniffiClonePointer(), FfiConverterTypeTreeID.lower(target), - FfiConverterOptionTypeTreeID.lower(parent), + FfiConverterTypeTreeParentId.lower(parent), FfiConverterUInt32.lower(to),$0 ) } } /** - * Return all nodes + * Return all nodes, including deleted nodes */ open func nodes() -> [TreeId] { return try! FfiConverterSequenceTypeTreeID.lift(try! rustCall() { @@ -3930,14 +4974,24 @@ open func nodes() -> [TreeId] { * - If the target node does not exist, throws Error. * - If the target node is a root node, return nil. */ -open func parent(target: TreeId)throws -> TreeId? { - return try FfiConverterOptionTypeTreeID.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { +open func parent(target: TreeId)throws -> TreeParentId { + return try FfiConverterTypeTreeParentId.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { uniffi_loro_fn_method_lorotree_parent(self.uniffiClonePointer(), FfiConverterTypeTreeID.lower(target),$0 ) }) } + /** + * Get the root nodes of the forest. + */ +open func roots() -> [TreeId] { + return try! FfiConverterSequenceTypeTreeID.lift(try! rustCall() { + uniffi_loro_fn_method_lorotree_roots(self.uniffiClonePointer(),$0 + ) +}) +} + } @@ -4552,14 +5606,16 @@ public func FfiConverterTypeOnPush_lower(_ value: OnPush) -> UnsafeMutableRawPoi -public protocol Subscriber : AnyObject { +public protocol StyleConfigMapProtocol : AnyObject { - func onDiff(diff: DiffEvent) + func get(key: String) -> StyleConfig? + + func insert(key: String, value: StyleConfig) } -open class SubscriberImpl: - Subscriber { +open class StyleConfigMap: + StyleConfigMapProtocol { fileprivate let pointer: UnsafeMutableRawPointer! /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. @@ -4584,26 +5640,151 @@ open class SubscriberImpl: } public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_loro_fn_clone_subscriber(self.pointer, $0) } + return try! rustCall { uniffi_loro_fn_clone_styleconfigmap(self.pointer, $0) } } - // No primary constructor declared for this class. +public convenience init() { + let pointer = + try! rustCall() { + uniffi_loro_fn_constructor_styleconfigmap_new($0 + ) +} + self.init(unsafeFromRawPointer: pointer) +} deinit { guard let pointer = pointer else { return } - try! rustCall { uniffi_loro_fn_free_subscriber(pointer, $0) } + try! rustCall { uniffi_loro_fn_free_styleconfigmap(pointer, $0) } } +public static func defaultRichTextConfig() -> StyleConfigMap { + return try! FfiConverterTypeStyleConfigMap.lift(try! rustCall() { + uniffi_loro_fn_constructor_styleconfigmap_default_rich_text_config($0 + ) +}) +} + -open func onDiff(diff: DiffEvent) {try! rustCall() { - uniffi_loro_fn_method_subscriber_on_diff(self.uniffiClonePointer(), - FfiConverterTypeDiffEvent.lower(diff),$0 +open func get(key: String) -> StyleConfig? { + return try! FfiConverterOptionTypeStyleConfig.lift(try! rustCall() { + uniffi_loro_fn_method_styleconfigmap_get(self.uniffiClonePointer(), + FfiConverterString.lower(key),$0 ) -} +}) +} + +open func insert(key: String, value: StyleConfig) {try! rustCall() { + uniffi_loro_fn_method_styleconfigmap_insert(self.uniffiClonePointer(), + FfiConverterString.lower(key), + FfiConverterTypeStyleConfig.lower(value),$0 + ) +} +} + + +} + +public struct FfiConverterTypeStyleConfigMap: FfiConverter { + + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = StyleConfigMap + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> StyleConfigMap { + return StyleConfigMap(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: StyleConfigMap) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> StyleConfigMap { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: StyleConfigMap, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + + + + +public func FfiConverterTypeStyleConfigMap_lift(_ pointer: UnsafeMutableRawPointer) throws -> StyleConfigMap { + return try FfiConverterTypeStyleConfigMap.lift(pointer) +} + +public func FfiConverterTypeStyleConfigMap_lower(_ value: StyleConfigMap) -> UnsafeMutableRawPointer { + return FfiConverterTypeStyleConfigMap.lower(value) +} + + + + +public protocol Subscriber : AnyObject { + + func onDiff(diff: DiffEvent) + +} + +open class SubscriberImpl: + Subscriber { + fileprivate let pointer: UnsafeMutableRawPointer! + + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + /// This constructor can be used to instantiate a fake object. + /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + /// + /// - Warning: + /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + public init(noPointer: NoPointer) { + self.pointer = nil + } + + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_loro_fn_clone_subscriber(self.pointer, $0) } + } + // No primary constructor declared for this class. + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_loro_fn_free_subscriber(pointer, $0) } + } + + + + +open func onDiff(diff: DiffEvent) {try! rustCall() { + uniffi_loro_fn_method_subscriber_on_diff(self.uniffiClonePointer(), + FfiConverterTypeDiffEvent.lower(diff),$0 + ) +} } @@ -4702,6 +5883,137 @@ public func FfiConverterTypeSubscriber_lower(_ value: Subscriber) -> UnsafeMutab +/** + * A handle to a subscription created by GPUI. When dropped, the subscription + * is cancelled and the callback will no longer be invoked. + */ +public protocol SubscriptionProtocol : AnyObject { + + /** + * Detaches the subscription from this handle. The callback will + * continue to be invoked until the views or models it has been + * subscribed to are dropped + */ + func detach() + +} + +/** + * A handle to a subscription created by GPUI. When dropped, the subscription + * is cancelled and the callback will no longer be invoked. + */ +open class Subscription: + SubscriptionProtocol { + fileprivate let pointer: UnsafeMutableRawPointer! + + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + /// This constructor can be used to instantiate a fake object. + /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + /// + /// - Warning: + /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + public init(noPointer: NoPointer) { + self.pointer = nil + } + + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_loro_fn_clone_subscription(self.pointer, $0) } + } + /** + * Creates a new subscription with a callback that gets invoked when + * this subscription is dropped. + */ +public convenience init(unsubscribe: Unsubscriber) { + let pointer = + try! rustCall() { + uniffi_loro_fn_constructor_subscription_new( + FfiConverterTypeUnsubscriber.lower(unsubscribe),$0 + ) +} + self.init(unsafeFromRawPointer: pointer) +} + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_loro_fn_free_subscription(pointer, $0) } + } + + + + + /** + * Detaches the subscription from this handle. The callback will + * continue to be invoked until the views or models it has been + * subscribed to are dropped + */ +open func detach() {try! rustCall() { + uniffi_loro_fn_method_subscription_detach(self.uniffiClonePointer(),$0 + ) +} +} + + +} + +public struct FfiConverterTypeSubscription: FfiConverter { + + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Subscription + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Subscription { + return Subscription(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: Subscription) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Subscription { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: Subscription, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + + + + +public func FfiConverterTypeSubscription_lift(_ pointer: UnsafeMutableRawPointer) throws -> Subscription { + return try FfiConverterTypeSubscription.lift(pointer) +} + +public func FfiConverterTypeSubscription_lower(_ value: Subscription) -> UnsafeMutableRawPointer { + return FfiConverterTypeSubscription.lower(value) +} + + + + public protocol UndoManagerProtocol : AnyObject { /** @@ -4964,32 +6276,14 @@ public func FfiConverterTypeUndoManager_lower(_ value: UndoManager) -> UnsafeMut -public protocol ValueOrContainerProtocol : AnyObject { - - func asContainer() -> ContainerId? - - func asLoroCounter() -> LoroCounter? - - func asLoroList() -> LoroList? - - func asLoroMap() -> LoroMap? - - func asLoroMovableList() -> LoroMovableList? - - func asLoroText() -> LoroText? +public protocol Unsubscriber : AnyObject { - func asLoroTree() -> LoroTree? - - func asValue() -> LoroValue? - - func isContainer() -> Bool - - func isValue() -> Bool + func onUnsubscribe() } -open class ValueOrContainer: - ValueOrContainerProtocol { +open class UnsubscriberImpl: + Unsubscriber { fileprivate let pointer: UnsafeMutableRawPointer! /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. @@ -5014,7 +6308,7 @@ open class ValueOrContainer: } public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_loro_fn_clone_valueorcontainer(self.pointer, $0) } + return try! rustCall { uniffi_loro_fn_clone_unsubscriber(self.pointer, $0) } } // No primary constructor declared for this class. @@ -5023,52 +6317,217 @@ open class ValueOrContainer: return } - try! rustCall { uniffi_loro_fn_free_valueorcontainer(pointer, $0) } + try! rustCall { uniffi_loro_fn_free_unsubscriber(pointer, $0) } } -open func asContainer() -> ContainerId? { - return try! FfiConverterOptionTypeContainerID.lift(try! rustCall() { - uniffi_loro_fn_method_valueorcontainer_as_container(self.uniffiClonePointer(),$0 - ) -}) -} - -open func asLoroCounter() -> LoroCounter? { - return try! FfiConverterOptionTypeLoroCounter.lift(try! rustCall() { - uniffi_loro_fn_method_valueorcontainer_as_loro_counter(self.uniffiClonePointer(),$0 - ) -}) -} - -open func asLoroList() -> LoroList? { - return try! FfiConverterOptionTypeLoroList.lift(try! rustCall() { - uniffi_loro_fn_method_valueorcontainer_as_loro_list(self.uniffiClonePointer(),$0 - ) -}) -} - -open func asLoroMap() -> LoroMap? { - return try! FfiConverterOptionTypeLoroMap.lift(try! rustCall() { - uniffi_loro_fn_method_valueorcontainer_as_loro_map(self.uniffiClonePointer(),$0 +open func onUnsubscribe() {try! rustCall() { + uniffi_loro_fn_method_unsubscriber_on_unsubscribe(self.uniffiClonePointer(),$0 ) -}) } - -open func asLoroMovableList() -> LoroMovableList? { - return try! FfiConverterOptionTypeLoroMovableList.lift(try! rustCall() { - uniffi_loro_fn_method_valueorcontainer_as_loro_movable_list(self.uniffiClonePointer(),$0 - ) -}) } -open func asLoroText() -> LoroText? { - return try! FfiConverterOptionTypeLoroText.lift(try! rustCall() { - uniffi_loro_fn_method_valueorcontainer_as_loro_text(self.uniffiClonePointer(),$0 - ) -}) + +} + + +// Put the implementation in a struct so we don't pollute the top-level namespace +fileprivate struct UniffiCallbackInterfaceUnsubscriber { + + // Create the VTable using a series of closures. + // Swift automatically converts these into C callback functions. + static var vtable: UniffiVTableCallbackInterfaceUnsubscriber = UniffiVTableCallbackInterfaceUnsubscriber( + onUnsubscribe: { ( + uniffiHandle: UInt64, + uniffiOutReturn: UnsafeMutableRawPointer, + uniffiCallStatus: UnsafeMutablePointer + ) in + let makeCall = { + () throws -> () in + guard let uniffiObj = try? FfiConverterTypeUnsubscriber.handleMap.get(handle: uniffiHandle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return uniffiObj.onUnsubscribe( + ) + } + + + let writeReturn = { () } + uniffiTraitInterfaceCall( + callStatus: uniffiCallStatus, + makeCall: makeCall, + writeReturn: writeReturn + ) + }, + uniffiFree: { (uniffiHandle: UInt64) -> () in + let result = try? FfiConverterTypeUnsubscriber.handleMap.remove(handle: uniffiHandle) + if result == nil { + print("Uniffi callback interface Unsubscriber: handle missing in uniffiFree") + } + } + ) +} + +private func uniffiCallbackInitUnsubscriber() { + uniffi_loro_fn_init_callback_vtable_unsubscriber(&UniffiCallbackInterfaceUnsubscriber.vtable) +} + +public struct FfiConverterTypeUnsubscriber: FfiConverter { + fileprivate static var handleMap = UniffiHandleMap() + + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Unsubscriber + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Unsubscriber { + return UnsubscriberImpl(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: Unsubscriber) -> UnsafeMutableRawPointer { + guard let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: handleMap.insert(obj: value))) else { + fatalError("Cast to UnsafeMutableRawPointer failed") + } + return ptr + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Unsubscriber { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: Unsubscriber, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + + + + +public func FfiConverterTypeUnsubscriber_lift(_ pointer: UnsafeMutableRawPointer) throws -> Unsubscriber { + return try FfiConverterTypeUnsubscriber.lift(pointer) +} + +public func FfiConverterTypeUnsubscriber_lower(_ value: Unsubscriber) -> UnsafeMutableRawPointer { + return FfiConverterTypeUnsubscriber.lower(value) +} + + + + +public protocol ValueOrContainerProtocol : AnyObject { + + func asContainer() -> ContainerId? + + func asLoroCounter() -> LoroCounter? + + func asLoroList() -> LoroList? + + func asLoroMap() -> LoroMap? + + func asLoroMovableList() -> LoroMovableList? + + func asLoroText() -> LoroText? + + func asLoroTree() -> LoroTree? + + func asValue() -> LoroValue? + + func isContainer() -> Bool + + func isValue() -> Bool + +} + +open class ValueOrContainer: + ValueOrContainerProtocol { + fileprivate let pointer: UnsafeMutableRawPointer! + + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + /// This constructor can be used to instantiate a fake object. + /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + /// + /// - Warning: + /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + public init(noPointer: NoPointer) { + self.pointer = nil + } + + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_loro_fn_clone_valueorcontainer(self.pointer, $0) } + } + // No primary constructor declared for this class. + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_loro_fn_free_valueorcontainer(pointer, $0) } + } + + + + +open func asContainer() -> ContainerId? { + return try! FfiConverterOptionTypeContainerID.lift(try! rustCall() { + uniffi_loro_fn_method_valueorcontainer_as_container(self.uniffiClonePointer(),$0 + ) +}) +} + +open func asLoroCounter() -> LoroCounter? { + return try! FfiConverterOptionTypeLoroCounter.lift(try! rustCall() { + uniffi_loro_fn_method_valueorcontainer_as_loro_counter(self.uniffiClonePointer(),$0 + ) +}) +} + +open func asLoroList() -> LoroList? { + return try! FfiConverterOptionTypeLoroList.lift(try! rustCall() { + uniffi_loro_fn_method_valueorcontainer_as_loro_list(self.uniffiClonePointer(),$0 + ) +}) +} + +open func asLoroMap() -> LoroMap? { + return try! FfiConverterOptionTypeLoroMap.lift(try! rustCall() { + uniffi_loro_fn_method_valueorcontainer_as_loro_map(self.uniffiClonePointer(),$0 + ) +}) +} + +open func asLoroMovableList() -> LoroMovableList? { + return try! FfiConverterOptionTypeLoroMovableList.lift(try! rustCall() { + uniffi_loro_fn_method_valueorcontainer_as_loro_movable_list(self.uniffiClonePointer(),$0 + ) +}) +} + +open func asLoroText() -> LoroText? { + return try! FfiConverterOptionTypeLoroText.lift(try! rustCall() { + uniffi_loro_fn_method_valueorcontainer_as_loro_text(self.uniffiClonePointer(),$0 + ) +}) } open func asLoroTree() -> LoroTree? { @@ -5149,12 +6608,32 @@ public func FfiConverterTypeValueOrContainer_lower(_ value: ValueOrContainer) -> public protocol VersionVectorProtocol : AnyObject { + func diff(rhs: VersionVector) -> VersionVectorDiff + + func encode() -> Data + + func eq(other: VersionVector) -> Bool + + func extendToIncludeVv(other: VersionVector) + func getLast(peer: UInt64) -> Int32? + func getMissingSpan(target: VersionVector) -> [IdSpan] + func includesId(id: Id) -> Bool func includesVv(other: VersionVector) -> Bool + func intersectSpan(target: IdSpan) -> CounterSpan? + + func merge(other: VersionVector) + + func partialCmp(other: VersionVector) -> Ordering? + + func setEnd(id: Id) + + func setLast(id: Id) + } open class VersionVector: @@ -5203,8 +6682,46 @@ public convenience init() { } +public static func decode(bytes: Data)throws -> VersionVector { + return try FfiConverterTypeVersionVector.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { + uniffi_loro_fn_constructor_versionvector_decode( + FfiConverterData.lower(bytes),$0 + ) +}) +} + +open func diff(rhs: VersionVector) -> VersionVectorDiff { + return try! FfiConverterTypeVersionVectorDiff.lift(try! rustCall() { + uniffi_loro_fn_method_versionvector_diff(self.uniffiClonePointer(), + FfiConverterTypeVersionVector.lower(rhs),$0 + ) +}) +} + +open func encode() -> Data { + return try! FfiConverterData.lift(try! rustCall() { + uniffi_loro_fn_method_versionvector_encode(self.uniffiClonePointer(),$0 + ) +}) +} + +open func eq(other: VersionVector) -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_versionvector_eq(self.uniffiClonePointer(), + FfiConverterTypeVersionVector.lower(other),$0 + ) +}) +} + +open func extendToIncludeVv(other: VersionVector) {try! rustCall() { + uniffi_loro_fn_method_versionvector_extend_to_include_vv(self.uniffiClonePointer(), + FfiConverterTypeVersionVector.lower(other),$0 + ) +} +} + open func getLast(peer: UInt64) -> Int32? { return try! FfiConverterOptionInt32.lift(try! rustCall() { uniffi_loro_fn_method_versionvector_get_last(self.uniffiClonePointer(), @@ -5213,6 +6730,14 @@ open func getLast(peer: UInt64) -> Int32? { }) } +open func getMissingSpan(target: VersionVector) -> [IdSpan] { + return try! FfiConverterSequenceTypeIdSpan.lift(try! rustCall() { + uniffi_loro_fn_method_versionvector_get_missing_span(self.uniffiClonePointer(), + FfiConverterTypeVersionVector.lower(target),$0 + ) +}) +} + open func includesId(id: Id) -> Bool { return try! FfiConverterBool.lift(try! rustCall() { uniffi_loro_fn_method_versionvector_includes_id(self.uniffiClonePointer(), @@ -5229,6 +6754,43 @@ open func includesVv(other: VersionVector) -> Bool { }) } +open func intersectSpan(target: IdSpan) -> CounterSpan? { + return try! FfiConverterOptionTypeCounterSpan.lift(try! rustCall() { + uniffi_loro_fn_method_versionvector_intersect_span(self.uniffiClonePointer(), + FfiConverterTypeIdSpan.lower(target),$0 + ) +}) +} + +open func merge(other: VersionVector) {try! rustCall() { + uniffi_loro_fn_method_versionvector_merge(self.uniffiClonePointer(), + FfiConverterTypeVersionVector.lower(other),$0 + ) +} +} + +open func partialCmp(other: VersionVector) -> Ordering? { + return try! FfiConverterOptionTypeOrdering.lift(try! rustCall() { + uniffi_loro_fn_method_versionvector_partial_cmp(self.uniffiClonePointer(), + FfiConverterTypeVersionVector.lower(other),$0 + ) +}) +} + +open func setEnd(id: Id) {try! rustCall() { + uniffi_loro_fn_method_versionvector_set_end(self.uniffiClonePointer(), + FfiConverterTypeID.lower(id),$0 + ) +} +} + +open func setLast(id: Id) {try! rustCall() { + uniffi_loro_fn_method_versionvector_set_last(self.uniffiClonePointer(), + FfiConverterTypeID.lower(id),$0 + ) +} +} + } @@ -5332,6 +6894,229 @@ public func FfiConverterTypeAbsolutePosition_lower(_ value: AbsolutePosition) -> } +public struct AwarenessPeerUpdate { + public var updated: [UInt64] + public var added: [UInt64] + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(updated: [UInt64], added: [UInt64]) { + self.updated = updated + self.added = added + } +} + + + +extension AwarenessPeerUpdate: Equatable, Hashable { + public static func ==(lhs: AwarenessPeerUpdate, rhs: AwarenessPeerUpdate) -> Bool { + if lhs.updated != rhs.updated { + return false + } + if lhs.added != rhs.added { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(updated) + hasher.combine(added) + } +} + + +public struct FfiConverterTypeAwarenessPeerUpdate: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AwarenessPeerUpdate { + return + try AwarenessPeerUpdate( + updated: FfiConverterSequenceUInt64.read(from: &buf), + added: FfiConverterSequenceUInt64.read(from: &buf) + ) + } + + public static func write(_ value: AwarenessPeerUpdate, into buf: inout [UInt8]) { + FfiConverterSequenceUInt64.write(value.updated, into: &buf) + FfiConverterSequenceUInt64.write(value.added, into: &buf) + } +} + + +public func FfiConverterTypeAwarenessPeerUpdate_lift(_ buf: RustBuffer) throws -> AwarenessPeerUpdate { + return try FfiConverterTypeAwarenessPeerUpdate.lift(buf) +} + +public func FfiConverterTypeAwarenessPeerUpdate_lower(_ value: AwarenessPeerUpdate) -> RustBuffer { + return FfiConverterTypeAwarenessPeerUpdate.lower(value) +} + + +public struct ChangeMeta { + /** + * Lamport timestamp of the Change + */ + public var lamport: UInt32 + /** + * The first Op id of the Change + */ + public var id: Id + /** + * [Unix time](https://en.wikipedia.org/wiki/Unix_time) + * It is the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970. + */ + public var timestamp: Int64 + /** + * The commit message of the change + */ + public var message: String? + /** + * The dependencies of the first op of the change + */ + public var deps: Frontiers + /** + * The total op num inside this change + */ + public var len: UInt32 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init( + /** + * Lamport timestamp of the Change + */lamport: UInt32, + /** + * The first Op id of the Change + */id: Id, + /** + * [Unix time](https://en.wikipedia.org/wiki/Unix_time) + * It is the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970. + */timestamp: Int64, + /** + * The commit message of the change + */message: String?, + /** + * The dependencies of the first op of the change + */deps: Frontiers, + /** + * The total op num inside this change + */len: UInt32) { + self.lamport = lamport + self.id = id + self.timestamp = timestamp + self.message = message + self.deps = deps + self.len = len + } +} + + + +public struct FfiConverterTypeChangeMeta: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChangeMeta { + return + try ChangeMeta( + lamport: FfiConverterUInt32.read(from: &buf), + id: FfiConverterTypeID.read(from: &buf), + timestamp: FfiConverterInt64.read(from: &buf), + message: FfiConverterOptionString.read(from: &buf), + deps: FfiConverterTypeFrontiers.read(from: &buf), + len: FfiConverterUInt32.read(from: &buf) + ) + } + + public static func write(_ value: ChangeMeta, into buf: inout [UInt8]) { + FfiConverterUInt32.write(value.lamport, into: &buf) + FfiConverterTypeID.write(value.id, into: &buf) + FfiConverterInt64.write(value.timestamp, into: &buf) + FfiConverterOptionString.write(value.message, into: &buf) + FfiConverterTypeFrontiers.write(value.deps, into: &buf) + FfiConverterUInt32.write(value.len, into: &buf) + } +} + + +public func FfiConverterTypeChangeMeta_lift(_ buf: RustBuffer) throws -> ChangeMeta { + return try FfiConverterTypeChangeMeta.lift(buf) +} + +public func FfiConverterTypeChangeMeta_lower(_ value: ChangeMeta) -> RustBuffer { + return FfiConverterTypeChangeMeta.lower(value) +} + + +public struct CommitOptions { + public var origin: String? + public var immediateRenew: Bool + public var timestamp: Int64? + public var commitMsg: String? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(origin: String?, immediateRenew: Bool, timestamp: Int64?, commitMsg: String?) { + self.origin = origin + self.immediateRenew = immediateRenew + self.timestamp = timestamp + self.commitMsg = commitMsg + } +} + + + +extension CommitOptions: Equatable, Hashable { + public static func ==(lhs: CommitOptions, rhs: CommitOptions) -> Bool { + if lhs.origin != rhs.origin { + return false + } + if lhs.immediateRenew != rhs.immediateRenew { + return false + } + if lhs.timestamp != rhs.timestamp { + return false + } + if lhs.commitMsg != rhs.commitMsg { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(origin) + hasher.combine(immediateRenew) + hasher.combine(timestamp) + hasher.combine(commitMsg) + } +} + + +public struct FfiConverterTypeCommitOptions: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CommitOptions { + return + try CommitOptions( + origin: FfiConverterOptionString.read(from: &buf), + immediateRenew: FfiConverterBool.read(from: &buf), + timestamp: FfiConverterOptionInt64.read(from: &buf), + commitMsg: FfiConverterOptionString.read(from: &buf) + ) + } + + public static func write(_ value: CommitOptions, into buf: inout [UInt8]) { + FfiConverterOptionString.write(value.origin, into: &buf) + FfiConverterBool.write(value.immediateRenew, into: &buf) + FfiConverterOptionInt64.write(value.timestamp, into: &buf) + FfiConverterOptionString.write(value.commitMsg, into: &buf) + } +} + + +public func FfiConverterTypeCommitOptions_lift(_ buf: RustBuffer) throws -> CommitOptions { + return try FfiConverterTypeCommitOptions.lift(buf) +} + +public func FfiConverterTypeCommitOptions_lower(_ value: CommitOptions) -> RustBuffer { + return FfiConverterTypeCommitOptions.lower(value) +} + + /** * A diff of a container. */ @@ -5397,12 +7182,69 @@ public struct FfiConverterTypeContainerDiff: FfiConverterRustBuffer { } -public func FfiConverterTypeContainerDiff_lift(_ buf: RustBuffer) throws -> ContainerDiff { - return try FfiConverterTypeContainerDiff.lift(buf) +public func FfiConverterTypeContainerDiff_lift(_ buf: RustBuffer) throws -> ContainerDiff { + return try FfiConverterTypeContainerDiff.lift(buf) +} + +public func FfiConverterTypeContainerDiff_lower(_ value: ContainerDiff) -> RustBuffer { + return FfiConverterTypeContainerDiff.lower(value) +} + + +public struct ContainerPath { + public var id: ContainerId + public var path: Index + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(id: ContainerId, path: Index) { + self.id = id + self.path = path + } +} + + + +extension ContainerPath: Equatable, Hashable { + public static func ==(lhs: ContainerPath, rhs: ContainerPath) -> Bool { + if lhs.id != rhs.id { + return false + } + if lhs.path != rhs.path { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(id) + hasher.combine(path) + } +} + + +public struct FfiConverterTypeContainerPath: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ContainerPath { + return + try ContainerPath( + id: FfiConverterTypeContainerID.read(from: &buf), + path: FfiConverterTypeIndex.read(from: &buf) + ) + } + + public static func write(_ value: ContainerPath, into buf: inout [UInt8]) { + FfiConverterTypeContainerID.write(value.id, into: &buf) + FfiConverterTypeIndex.write(value.path, into: &buf) + } +} + + +public func FfiConverterTypeContainerPath_lift(_ buf: RustBuffer) throws -> ContainerPath { + return try FfiConverterTypeContainerPath.lift(buf) } -public func FfiConverterTypeContainerDiff_lower(_ value: ContainerDiff) -> RustBuffer { - return FfiConverterTypeContainerDiff.lower(value) +public func FfiConverterTypeContainerPath_lower(_ value: ContainerPath) -> RustBuffer { + return FfiConverterTypeContainerPath.lower(value) } @@ -5630,6 +7472,264 @@ public func FfiConverterTypeID_lower(_ value: Id) -> RustBuffer { } +public struct IdLp { + public var lamport: UInt32 + public var peer: UInt64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(lamport: UInt32, peer: UInt64) { + self.lamport = lamport + self.peer = peer + } +} + + + +extension IdLp: Equatable, Hashable { + public static func ==(lhs: IdLp, rhs: IdLp) -> Bool { + if lhs.lamport != rhs.lamport { + return false + } + if lhs.peer != rhs.peer { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(lamport) + hasher.combine(peer) + } +} + + +public struct FfiConverterTypeIdLp: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> IdLp { + return + try IdLp( + lamport: FfiConverterUInt32.read(from: &buf), + peer: FfiConverterUInt64.read(from: &buf) + ) + } + + public static func write(_ value: IdLp, into buf: inout [UInt8]) { + FfiConverterUInt32.write(value.lamport, into: &buf) + FfiConverterUInt64.write(value.peer, into: &buf) + } +} + + +public func FfiConverterTypeIdLp_lift(_ buf: RustBuffer) throws -> IdLp { + return try FfiConverterTypeIdLp.lift(buf) +} + +public func FfiConverterTypeIdLp_lower(_ value: IdLp) -> RustBuffer { + return FfiConverterTypeIdLp.lower(value) +} + + +public struct IdSpan { + public var peer: UInt64 + public var counter: CounterSpan + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(peer: UInt64, counter: CounterSpan) { + self.peer = peer + self.counter = counter + } +} + + + +extension IdSpan: Equatable, Hashable { + public static func ==(lhs: IdSpan, rhs: IdSpan) -> Bool { + if lhs.peer != rhs.peer { + return false + } + if lhs.counter != rhs.counter { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(peer) + hasher.combine(counter) + } +} + + +public struct FfiConverterTypeIdSpan: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> IdSpan { + return + try IdSpan( + peer: FfiConverterUInt64.read(from: &buf), + counter: FfiConverterTypeCounterSpan.read(from: &buf) + ) + } + + public static func write(_ value: IdSpan, into buf: inout [UInt8]) { + FfiConverterUInt64.write(value.peer, into: &buf) + FfiConverterTypeCounterSpan.write(value.counter, into: &buf) + } +} + + +public func FfiConverterTypeIdSpan_lift(_ buf: RustBuffer) throws -> IdSpan { + return try FfiConverterTypeIdSpan.lift(buf) +} + +public func FfiConverterTypeIdSpan_lower(_ value: IdSpan) -> RustBuffer { + return FfiConverterTypeIdSpan.lower(value) +} + + +public struct ImportBlobMetadata { + /** + * The partial start version vector. + * + * Import blob includes all the ops from `partial_start_vv` to `partial_end_vv`. + * However, it does not constitute a complete version vector, as it only contains counters + * from peers included within the import blob. + */ + public var partialStartVv: VersionVector + /** + * The partial end version vector. + * + * Import blob includes all the ops from `partial_start_vv` to `partial_end_vv`. + * However, it does not constitute a complete version vector, as it only contains counters + * from peers included within the import blob. + */ + public var partialEndVv: VersionVector + public var startTimestamp: Int64 + public var startFrontiers: Frontiers + public var endTimestamp: Int64 + public var changeNum: UInt32 + public var isSnapshot: Bool + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init( + /** + * The partial start version vector. + * + * Import blob includes all the ops from `partial_start_vv` to `partial_end_vv`. + * However, it does not constitute a complete version vector, as it only contains counters + * from peers included within the import blob. + */partialStartVv: VersionVector, + /** + * The partial end version vector. + * + * Import blob includes all the ops from `partial_start_vv` to `partial_end_vv`. + * However, it does not constitute a complete version vector, as it only contains counters + * from peers included within the import blob. + */partialEndVv: VersionVector, startTimestamp: Int64, startFrontiers: Frontiers, endTimestamp: Int64, changeNum: UInt32, isSnapshot: Bool) { + self.partialStartVv = partialStartVv + self.partialEndVv = partialEndVv + self.startTimestamp = startTimestamp + self.startFrontiers = startFrontiers + self.endTimestamp = endTimestamp + self.changeNum = changeNum + self.isSnapshot = isSnapshot + } +} + + + +public struct FfiConverterTypeImportBlobMetadata: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ImportBlobMetadata { + return + try ImportBlobMetadata( + partialStartVv: FfiConverterTypeVersionVector.read(from: &buf), + partialEndVv: FfiConverterTypeVersionVector.read(from: &buf), + startTimestamp: FfiConverterInt64.read(from: &buf), + startFrontiers: FfiConverterTypeFrontiers.read(from: &buf), + endTimestamp: FfiConverterInt64.read(from: &buf), + changeNum: FfiConverterUInt32.read(from: &buf), + isSnapshot: FfiConverterBool.read(from: &buf) + ) + } + + public static func write(_ value: ImportBlobMetadata, into buf: inout [UInt8]) { + FfiConverterTypeVersionVector.write(value.partialStartVv, into: &buf) + FfiConverterTypeVersionVector.write(value.partialEndVv, into: &buf) + FfiConverterInt64.write(value.startTimestamp, into: &buf) + FfiConverterTypeFrontiers.write(value.startFrontiers, into: &buf) + FfiConverterInt64.write(value.endTimestamp, into: &buf) + FfiConverterUInt32.write(value.changeNum, into: &buf) + FfiConverterBool.write(value.isSnapshot, into: &buf) + } +} + + +public func FfiConverterTypeImportBlobMetadata_lift(_ buf: RustBuffer) throws -> ImportBlobMetadata { + return try FfiConverterTypeImportBlobMetadata.lift(buf) +} + +public func FfiConverterTypeImportBlobMetadata_lower(_ value: ImportBlobMetadata) -> RustBuffer { + return FfiConverterTypeImportBlobMetadata.lower(value) +} + + +public struct ImportStatus { + public var success: [UInt64: CounterSpan] + public var pending: [UInt64: CounterSpan]? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(success: [UInt64: CounterSpan], pending: [UInt64: CounterSpan]?) { + self.success = success + self.pending = pending + } +} + + + +extension ImportStatus: Equatable, Hashable { + public static func ==(lhs: ImportStatus, rhs: ImportStatus) -> Bool { + if lhs.success != rhs.success { + return false + } + if lhs.pending != rhs.pending { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(success) + hasher.combine(pending) + } +} + + +public struct FfiConverterTypeImportStatus: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ImportStatus { + return + try ImportStatus( + success: FfiConverterDictionaryUInt64TypeCounterSpan.read(from: &buf), + pending: FfiConverterOptionDictionaryUInt64TypeCounterSpan.read(from: &buf) + ) + } + + public static func write(_ value: ImportStatus, into buf: inout [UInt8]) { + FfiConverterDictionaryUInt64TypeCounterSpan.write(value.success, into: &buf) + FfiConverterOptionDictionaryUInt64TypeCounterSpan.write(value.pending, into: &buf) + } +} + + +public func FfiConverterTypeImportStatus_lift(_ buf: RustBuffer) throws -> ImportStatus { + return try FfiConverterTypeImportStatus.lift(buf) +} + +public func FfiConverterTypeImportStatus_lower(_ value: ImportStatus) -> RustBuffer { + return FfiConverterTypeImportStatus.lower(value) +} + + public struct MapDelta { public var updated: [String: ValueOrContainer?] @@ -5691,34 +7791,187 @@ extension PathItem: Equatable, Hashable { } public func hash(into hasher: inout Hasher) { - hasher.combine(container) - hasher.combine(index) + hasher.combine(container) + hasher.combine(index) + } +} + + +public struct FfiConverterTypePathItem: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PathItem { + return + try PathItem( + container: FfiConverterTypeContainerID.read(from: &buf), + index: FfiConverterTypeIndex.read(from: &buf) + ) + } + + public static func write(_ value: PathItem, into buf: inout [UInt8]) { + FfiConverterTypeContainerID.write(value.container, into: &buf) + FfiConverterTypeIndex.write(value.index, into: &buf) + } +} + + +public func FfiConverterTypePathItem_lift(_ buf: RustBuffer) throws -> PathItem { + return try FfiConverterTypePathItem.lift(buf) +} + +public func FfiConverterTypePathItem_lower(_ value: PathItem) -> RustBuffer { + return FfiConverterTypePathItem.lower(value) +} + + +public struct PeerInfo { + public var state: LoroValue + public var counter: Int32 + public var timestamp: Int64 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(state: LoroValue, counter: Int32, timestamp: Int64) { + self.state = state + self.counter = counter + self.timestamp = timestamp + } +} + + + +extension PeerInfo: Equatable, Hashable { + public static func ==(lhs: PeerInfo, rhs: PeerInfo) -> Bool { + if lhs.state != rhs.state { + return false + } + if lhs.counter != rhs.counter { + return false + } + if lhs.timestamp != rhs.timestamp { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(state) + hasher.combine(counter) + hasher.combine(timestamp) + } +} + + +public struct FfiConverterTypePeerInfo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PeerInfo { + return + try PeerInfo( + state: FfiConverterTypeLoroValue.read(from: &buf), + counter: FfiConverterInt32.read(from: &buf), + timestamp: FfiConverterInt64.read(from: &buf) + ) + } + + public static func write(_ value: PeerInfo, into buf: inout [UInt8]) { + FfiConverterTypeLoroValue.write(value.state, into: &buf) + FfiConverterInt32.write(value.counter, into: &buf) + FfiConverterInt64.write(value.timestamp, into: &buf) + } +} + + +public func FfiConverterTypePeerInfo_lift(_ buf: RustBuffer) throws -> PeerInfo { + return try FfiConverterTypePeerInfo.lift(buf) +} + +public func FfiConverterTypePeerInfo_lower(_ value: PeerInfo) -> RustBuffer { + return FfiConverterTypePeerInfo.lower(value) +} + + +public struct PosQueryResult { + public var update: Cursor? + public var current: AbsolutePosition + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(update: Cursor?, current: AbsolutePosition) { + self.update = update + self.current = current + } +} + + + +public struct FfiConverterTypePosQueryResult: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PosQueryResult { + return + try PosQueryResult( + update: FfiConverterOptionTypeCursor.read(from: &buf), + current: FfiConverterTypeAbsolutePosition.read(from: &buf) + ) + } + + public static func write(_ value: PosQueryResult, into buf: inout [UInt8]) { + FfiConverterOptionTypeCursor.write(value.update, into: &buf) + FfiConverterTypeAbsolutePosition.write(value.current, into: &buf) + } +} + + +public func FfiConverterTypePosQueryResult_lift(_ buf: RustBuffer) throws -> PosQueryResult { + return try FfiConverterTypePosQueryResult.lift(buf) +} + +public func FfiConverterTypePosQueryResult_lower(_ value: PosQueryResult) -> RustBuffer { + return FfiConverterTypePosQueryResult.lower(value) +} + + +public struct StyleConfig { + public var expand: ExpandType + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(expand: ExpandType) { + self.expand = expand + } +} + + + +extension StyleConfig: Equatable, Hashable { + public static func ==(lhs: StyleConfig, rhs: StyleConfig) -> Bool { + if lhs.expand != rhs.expand { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(expand) } } -public struct FfiConverterTypePathItem: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PathItem { +public struct FfiConverterTypeStyleConfig: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> StyleConfig { return - try PathItem( - container: FfiConverterTypeContainerID.read(from: &buf), - index: FfiConverterTypeIndex.read(from: &buf) + try StyleConfig( + expand: FfiConverterTypeExpandType.read(from: &buf) ) } - public static func write(_ value: PathItem, into buf: inout [UInt8]) { - FfiConverterTypeContainerID.write(value.container, into: &buf) - FfiConverterTypeIndex.write(value.index, into: &buf) + public static func write(_ value: StyleConfig, into buf: inout [UInt8]) { + FfiConverterTypeExpandType.write(value.expand, into: &buf) } } -public func FfiConverterTypePathItem_lift(_ buf: RustBuffer) throws -> PathItem { - return try FfiConverterTypePathItem.lift(buf) +public func FfiConverterTypeStyleConfig_lift(_ buf: RustBuffer) throws -> StyleConfig { + return try FfiConverterTypeStyleConfig.lift(buf) } -public func FfiConverterTypePathItem_lower(_ value: PathItem) -> RustBuffer { - return FfiConverterTypePathItem.lower(value) +public func FfiConverterTypeStyleConfig_lower(_ value: StyleConfig) -> RustBuffer { + return FfiConverterTypeStyleConfig.lower(value) } @@ -5923,6 +8176,143 @@ public func FfiConverterTypeUndoItemMeta_lower(_ value: UndoItemMeta) -> RustBuf return FfiConverterTypeUndoItemMeta.lower(value) } + +public struct VersionVectorDiff { + /** + * need to add these spans to move from right to left + */ + public var left: [UInt64: CounterSpan] + /** + * need to add these spans to move from left to right + */ + public var right: [UInt64: CounterSpan] + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init( + /** + * need to add these spans to move from right to left + */left: [UInt64: CounterSpan], + /** + * need to add these spans to move from left to right + */right: [UInt64: CounterSpan]) { + self.left = left + self.right = right + } +} + + + +extension VersionVectorDiff: Equatable, Hashable { + public static func ==(lhs: VersionVectorDiff, rhs: VersionVectorDiff) -> Bool { + if lhs.left != rhs.left { + return false + } + if lhs.right != rhs.right { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(left) + hasher.combine(right) + } +} + + +public struct FfiConverterTypeVersionVectorDiff: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> VersionVectorDiff { + return + try VersionVectorDiff( + left: FfiConverterDictionaryUInt64TypeCounterSpan.read(from: &buf), + right: FfiConverterDictionaryUInt64TypeCounterSpan.read(from: &buf) + ) + } + + public static func write(_ value: VersionVectorDiff, into buf: inout [UInt8]) { + FfiConverterDictionaryUInt64TypeCounterSpan.write(value.left, into: &buf) + FfiConverterDictionaryUInt64TypeCounterSpan.write(value.right, into: &buf) + } +} + + +public func FfiConverterTypeVersionVectorDiff_lift(_ buf: RustBuffer) throws -> VersionVectorDiff { + return try FfiConverterTypeVersionVectorDiff.lift(buf) +} + +public func FfiConverterTypeVersionVectorDiff_lower(_ value: VersionVectorDiff) -> RustBuffer { + return FfiConverterTypeVersionVectorDiff.lower(value) +} + + +public enum CannotFindRelativePosition { + + + + case ContainerDeleted(message: String) + + case HistoryCleared(message: String) + + case IdNotFound(message: String) + +} + + +public struct FfiConverterTypeCannotFindRelativePosition: FfiConverterRustBuffer { + typealias SwiftType = CannotFindRelativePosition + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CannotFindRelativePosition { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .ContainerDeleted( + message: try FfiConverterString.read(from: &buf) + ) + + case 2: return .HistoryCleared( + message: try FfiConverterString.read(from: &buf) + ) + + case 3: return .IdNotFound( + message: try FfiConverterString.read(from: &buf) + ) + + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: CannotFindRelativePosition, into buf: inout [UInt8]) { + switch value { + + + + + case .ContainerDeleted(_ /* message is ignored*/): + writeInt(&buf, Int32(1)) + case .HistoryCleared(_ /* message is ignored*/): + writeInt(&buf, Int32(2)) + case .IdNotFound(_ /* message is ignored*/): + writeInt(&buf, Int32(3)) + + + } + } +} + + +extension CannotFindRelativePosition: Equatable, Hashable {} + +extension CannotFindRelativePosition: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -6249,6 +8639,75 @@ extension EventTriggerKind: Equatable, Hashable {} +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum ExpandType { + + case before + case after + case both + case none +} + + +public struct FfiConverterTypeExpandType: FfiConverterRustBuffer { + typealias SwiftType = ExpandType + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ExpandType { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .before + + case 2: return .after + + case 3: return .both + + case 4: return .none + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: ExpandType, into buf: inout [UInt8]) { + switch value { + + + case .before: + writeInt(&buf, Int32(1)) + + + case .after: + writeInt(&buf, Int32(2)) + + + case .both: + writeInt(&buf, Int32(3)) + + + case .none: + writeInt(&buf, Int32(4)) + + } + } +} + + +public func FfiConverterTypeExpandType_lift(_ buf: RustBuffer) throws -> ExpandType { + return try FfiConverterTypeExpandType.lift(buf) +} + +public func FfiConverterTypeExpandType_lower(_ value: ExpandType) -> RustBuffer { + return FfiConverterTypeExpandType.lower(value) +} + + + +extension ExpandType: Equatable, Hashable {} + + + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -6320,6 +8779,66 @@ extension Index: Equatable, Hashable {} + +public enum JsonPathError { + + + + case InvalidJsonPath(message: String) + + case EvaluationError(message: String) + +} + + +public struct FfiConverterTypeJsonPathError: FfiConverterRustBuffer { + typealias SwiftType = JsonPathError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> JsonPathError { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .InvalidJsonPath( + message: try FfiConverterString.read(from: &buf) + ) + + case 2: return .EvaluationError( + message: try FfiConverterString.read(from: &buf) + ) + + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: JsonPathError, into buf: inout [UInt8]) { + switch value { + + + + + case .InvalidJsonPath(_ /* message is ignored*/): + writeInt(&buf, Int32(1)) + case .EvaluationError(_ /* message is ignored*/): + writeInt(&buf, Int32(2)) + + + } + } +} + + +extension JsonPathError: Equatable, Hashable {} + +extension JsonPathError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -6389,18 +8908,86 @@ public struct FfiConverterTypeListDiffItem: FfiConverterRustBuffer { } -public func FfiConverterTypeListDiffItem_lift(_ buf: RustBuffer) throws -> ListDiffItem { - return try FfiConverterTypeListDiffItem.lift(buf) -} +public func FfiConverterTypeListDiffItem_lift(_ buf: RustBuffer) throws -> ListDiffItem { + return try FfiConverterTypeListDiffItem.lift(buf) +} + +public func FfiConverterTypeListDiffItem_lower(_ value: ListDiffItem) -> RustBuffer { + return FfiConverterTypeListDiffItem.lower(value) +} + + + + + +public enum LoroEncodeError { + + + + case FrontiersNotFound(message: String) + + case TrimmedSnapshotIncompatibleWithOldFormat(message: String) + + case UnknownContainer(message: String) + +} + + +public struct FfiConverterTypeLoroEncodeError: FfiConverterRustBuffer { + typealias SwiftType = LoroEncodeError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LoroEncodeError { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .FrontiersNotFound( + message: try FfiConverterString.read(from: &buf) + ) + + case 2: return .TrimmedSnapshotIncompatibleWithOldFormat( + message: try FfiConverterString.read(from: &buf) + ) + + case 3: return .UnknownContainer( + message: try FfiConverterString.read(from: &buf) + ) + + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: LoroEncodeError, into buf: inout [UInt8]) { + switch value { + + + + + case .FrontiersNotFound(_ /* message is ignored*/): + writeInt(&buf, Int32(1)) + case .TrimmedSnapshotIncompatibleWithOldFormat(_ /* message is ignored*/): + writeInt(&buf, Int32(2)) + case .UnknownContainer(_ /* message is ignored*/): + writeInt(&buf, Int32(3)) + + + } + } +} + + +extension LoroEncodeError: Equatable, Hashable {} -public func FfiConverterTypeListDiffItem_lower(_ value: ListDiffItem) -> RustBuffer { - return FfiConverterTypeListDiffItem.lower(value) +extension LoroEncodeError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } } - - - public enum LoroError { @@ -6467,6 +9054,16 @@ public enum LoroError { case InvalidRootContainerName(message: String) + case ImportUpdatesThatDependsOnOutdatedVersion(message: String) + + case SwitchToTrimmedVersion(message: String) + + case ContainerDeleted(message: String) + + case ConcurrentOpsWithSamePeerId(message: String) + + case InvalidPeerId(message: String) + } @@ -6604,6 +9201,26 @@ public struct FfiConverterTypeLoroError: FfiConverterRustBuffer { message: try FfiConverterString.read(from: &buf) ) + case 32: return .ImportUpdatesThatDependsOnOutdatedVersion( + message: try FfiConverterString.read(from: &buf) + ) + + case 33: return .SwitchToTrimmedVersion( + message: try FfiConverterString.read(from: &buf) + ) + + case 34: return .ContainerDeleted( + message: try FfiConverterString.read(from: &buf) + ) + + case 35: return .ConcurrentOpsWithSamePeerId( + message: try FfiConverterString.read(from: &buf) + ) + + case 36: return .InvalidPeerId( + message: try FfiConverterString.read(from: &buf) + ) + default: throw UniffiInternalError.unexpectedEnumCase } @@ -6677,6 +9294,16 @@ public struct FfiConverterTypeLoroError: FfiConverterRustBuffer { writeInt(&buf, Int32(30)) case .InvalidRootContainerName(_ /* message is ignored*/): writeInt(&buf, Int32(31)) + case .ImportUpdatesThatDependsOnOutdatedVersion(_ /* message is ignored*/): + writeInt(&buf, Int32(32)) + case .SwitchToTrimmedVersion(_ /* message is ignored*/): + writeInt(&buf, Int32(33)) + case .ContainerDeleted(_ /* message is ignored*/): + writeInt(&buf, Int32(34)) + case .ConcurrentOpsWithSamePeerId(_ /* message is ignored*/): + writeInt(&buf, Int32(35)) + case .InvalidPeerId(_ /* message is ignored*/): + writeInt(&buf, Int32(36)) } @@ -6704,7 +9331,7 @@ public enum LoroValue { ) case i64(value: Int64 ) - case binary(value: [UInt8] + case binary(value: Data ) case string(value: String ) @@ -6735,7 +9362,7 @@ public struct FfiConverterTypeLoroValue: FfiConverterRustBuffer { case 4: return .i64(value: try FfiConverterInt64.read(from: &buf) ) - case 5: return .binary(value: try FfiConverterSequenceUInt8.read(from: &buf) + case 5: return .binary(value: try FfiConverterData.read(from: &buf) ) case 6: return .string(value: try FfiConverterString.read(from: &buf) @@ -6779,7 +9406,7 @@ public struct FfiConverterTypeLoroValue: FfiConverterRustBuffer { case let .binary(value): writeInt(&buf, Int32(5)) - FfiConverterSequenceUInt8.write(value, into: &buf) + FfiConverterData.write(value, into: &buf) case let .string(value): @@ -6820,6 +9447,68 @@ extension LoroValue: Equatable, Hashable {} +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum Ordering { + + case less + case equal + case greater +} + + +public struct FfiConverterTypeOrdering: FfiConverterRustBuffer { + typealias SwiftType = Ordering + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Ordering { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .less + + case 2: return .equal + + case 3: return .greater + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: Ordering, into buf: inout [UInt8]) { + switch value { + + + case .less: + writeInt(&buf, Int32(1)) + + + case .equal: + writeInt(&buf, Int32(2)) + + + case .greater: + writeInt(&buf, Int32(3)) + + } + } +} + + +public func FfiConverterTypeOrdering_lift(_ buf: RustBuffer) throws -> Ordering { + return try FfiConverterTypeOrdering.lift(buf) +} + +public func FfiConverterTypeOrdering_lower(_ value: Ordering) -> RustBuffer { + return FfiConverterTypeOrdering.lower(value) +} + + + +extension Ordering: Equatable, Hashable {} + + + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -6960,11 +9649,12 @@ extension TextDelta: Equatable, Hashable {} public enum TreeExternalDiff { - case create(parent: TreeId?, index: UInt32, fractionalIndex: String + case create(parent: TreeParentId, index: UInt32, fractionalIndex: String + ) + case move(parent: TreeParentId, index: UInt32, fractionalIndex: String, oldParent: TreeParentId, oldIndex: UInt32 ) - case move(parent: TreeId?, index: UInt32, fractionalIndex: String + case delete(oldParent: TreeParentId, oldIndex: UInt32 ) - case delete } @@ -6975,13 +9665,14 @@ public struct FfiConverterTypeTreeExternalDiff: FfiConverterRustBuffer { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return .create(parent: try FfiConverterOptionTypeTreeID.read(from: &buf), index: try FfiConverterUInt32.read(from: &buf), fractionalIndex: try FfiConverterString.read(from: &buf) + case 1: return .create(parent: try FfiConverterTypeTreeParentId.read(from: &buf), index: try FfiConverterUInt32.read(from: &buf), fractionalIndex: try FfiConverterString.read(from: &buf) ) - case 2: return .move(parent: try FfiConverterOptionTypeTreeID.read(from: &buf), index: try FfiConverterUInt32.read(from: &buf), fractionalIndex: try FfiConverterString.read(from: &buf) + case 2: return .move(parent: try FfiConverterTypeTreeParentId.read(from: &buf), index: try FfiConverterUInt32.read(from: &buf), fractionalIndex: try FfiConverterString.read(from: &buf), oldParent: try FfiConverterTypeTreeParentId.read(from: &buf), oldIndex: try FfiConverterUInt32.read(from: &buf) ) - case 3: return .delete + case 3: return .delete(oldParent: try FfiConverterTypeTreeParentId.read(from: &buf), oldIndex: try FfiConverterUInt32.read(from: &buf) + ) default: throw UniffiInternalError.unexpectedEnumCase } @@ -6993,21 +9684,25 @@ public struct FfiConverterTypeTreeExternalDiff: FfiConverterRustBuffer { case let .create(parent,index,fractionalIndex): writeInt(&buf, Int32(1)) - FfiConverterOptionTypeTreeID.write(parent, into: &buf) + FfiConverterTypeTreeParentId.write(parent, into: &buf) FfiConverterUInt32.write(index, into: &buf) FfiConverterString.write(fractionalIndex, into: &buf) - case let .move(parent,index,fractionalIndex): + case let .move(parent,index,fractionalIndex,oldParent,oldIndex): writeInt(&buf, Int32(2)) - FfiConverterOptionTypeTreeID.write(parent, into: &buf) + FfiConverterTypeTreeParentId.write(parent, into: &buf) FfiConverterUInt32.write(index, into: &buf) FfiConverterString.write(fractionalIndex, into: &buf) + FfiConverterTypeTreeParentId.write(oldParent, into: &buf) + FfiConverterUInt32.write(oldIndex, into: &buf) - case .delete: + case let .delete(oldParent,oldIndex): writeInt(&buf, Int32(3)) - + FfiConverterTypeTreeParentId.write(oldParent, into: &buf) + FfiConverterUInt32.write(oldIndex, into: &buf) + } } } @@ -7027,6 +9722,78 @@ extension TreeExternalDiff: Equatable, Hashable {} +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum TreeParentId { + + case node(id: TreeId + ) + case root + case deleted + case unexist +} + + +public struct FfiConverterTypeTreeParentId: FfiConverterRustBuffer { + typealias SwiftType = TreeParentId + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TreeParentId { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .node(id: try FfiConverterTypeTreeID.read(from: &buf) + ) + + case 2: return .root + + case 3: return .deleted + + case 4: return .unexist + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: TreeParentId, into buf: inout [UInt8]) { + switch value { + + + case let .node(id): + writeInt(&buf, Int32(1)) + FfiConverterTypeTreeID.write(id, into: &buf) + + + case .root: + writeInt(&buf, Int32(2)) + + + case .deleted: + writeInt(&buf, Int32(3)) + + + case .unexist: + writeInt(&buf, Int32(4)) + + } + } +} + + +public func FfiConverterTypeTreeParentId_lift(_ buf: RustBuffer) throws -> TreeParentId { + return try FfiConverterTypeTreeParentId.lift(buf) +} + +public func FfiConverterTypeTreeParentId_lower(_ value: TreeParentId) -> RustBuffer { + return FfiConverterTypeTreeParentId.lower(value) +} + + + +extension TreeParentId: Equatable, Hashable {} + + + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -7124,6 +9891,27 @@ fileprivate struct FfiConverterOptionInt32: FfiConverterRustBuffer { } } +fileprivate struct FfiConverterOptionInt64: FfiConverterRustBuffer { + typealias SwiftType = Int64? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterInt64.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterInt64.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer { typealias SwiftType = String? @@ -7166,6 +9954,27 @@ fileprivate struct FfiConverterOptionTypeCursor: FfiConverterRustBuffer { } } +fileprivate struct FfiConverterOptionTypeFrontiers: FfiConverterRustBuffer { + typealias SwiftType = Frontiers? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeFrontiers.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeFrontiers.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + fileprivate struct FfiConverterOptionTypeLoroCounter: FfiConverterRustBuffer { typealias SwiftType = LoroCounter? @@ -7376,6 +10185,48 @@ fileprivate struct FfiConverterOptionTypeVersionVector: FfiConverterRustBuffer { } } +fileprivate struct FfiConverterOptionTypeChangeMeta: FfiConverterRustBuffer { + typealias SwiftType = ChangeMeta? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeChangeMeta.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeChangeMeta.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionTypeCounterSpan: FfiConverterRustBuffer { + typealias SwiftType = CounterSpan? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeCounterSpan.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeCounterSpan.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + fileprivate struct FfiConverterOptionTypeID: FfiConverterRustBuffer { typealias SwiftType = Id? @@ -7385,20 +10236,83 @@ fileprivate struct FfiConverterOptionTypeID: FfiConverterRustBuffer { return } writeInt(&buf, Int8(1)) - FfiConverterTypeID.write(value, into: &buf) + FfiConverterTypeID.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeID.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionTypeStyleConfig: FfiConverterRustBuffer { + typealias SwiftType = StyleConfig? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeStyleConfig.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeStyleConfig.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionTypeContainerID: FfiConverterRustBuffer { + typealias SwiftType = ContainerId? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeContainerID.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeContainerID.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionTypeLoroValue: FfiConverterRustBuffer { + typealias SwiftType = LoroValue? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeLoroValue.write(value, into: &buf) } public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeID.read(from: &buf) + case 1: return try FfiConverterTypeLoroValue.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeTreeID: FfiConverterRustBuffer { - typealias SwiftType = TreeId? +fileprivate struct FfiConverterOptionTypeOrdering: FfiConverterRustBuffer { + typealias SwiftType = Ordering? public static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { @@ -7406,20 +10320,20 @@ fileprivate struct FfiConverterOptionTypeTreeID: FfiConverterRustBuffer { return } writeInt(&buf, Int8(1)) - FfiConverterTypeTreeID.write(value, into: &buf) + FfiConverterTypeOrdering.write(value, into: &buf) } public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeTreeID.read(from: &buf) + case 1: return try FfiConverterTypeOrdering.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeContainerID: FfiConverterRustBuffer { - typealias SwiftType = ContainerId? +fileprivate struct FfiConverterOptionSequenceTypeContainerPath: FfiConverterRustBuffer { + typealias SwiftType = [ContainerPath]? public static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { @@ -7427,20 +10341,20 @@ fileprivate struct FfiConverterOptionTypeContainerID: FfiConverterRustBuffer { return } writeInt(&buf, Int8(1)) - FfiConverterTypeContainerID.write(value, into: &buf) + FfiConverterSequenceTypeContainerPath.write(value, into: &buf) } public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeContainerID.read(from: &buf) + case 1: return try FfiConverterSequenceTypeContainerPath.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeLoroValue: FfiConverterRustBuffer { - typealias SwiftType = LoroValue? +fileprivate struct FfiConverterOptionSequenceTypeTreeID: FfiConverterRustBuffer { + typealias SwiftType = [TreeId]? public static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { @@ -7448,20 +10362,20 @@ fileprivate struct FfiConverterOptionTypeLoroValue: FfiConverterRustBuffer { return } writeInt(&buf, Int8(1)) - FfiConverterTypeLoroValue.write(value, into: &buf) + FfiConverterSequenceTypeTreeID.write(value, into: &buf) } public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeLoroValue.read(from: &buf) + case 1: return try FfiConverterSequenceTypeTreeID.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionSequenceTypeTreeID: FfiConverterRustBuffer { - typealias SwiftType = [TreeId]? +fileprivate struct FfiConverterOptionDictionaryUInt64TypeCounterSpan: FfiConverterRustBuffer { + typealias SwiftType = [UInt64: CounterSpan]? public static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { @@ -7469,13 +10383,13 @@ fileprivate struct FfiConverterOptionSequenceTypeTreeID: FfiConverterRustBuffer return } writeInt(&buf, Int8(1)) - FfiConverterSequenceTypeTreeID.write(value, into: &buf) + FfiConverterDictionaryUInt64TypeCounterSpan.write(value, into: &buf) } public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterSequenceTypeTreeID.read(from: &buf) + case 1: return try FfiConverterDictionaryUInt64TypeCounterSpan.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } @@ -7502,23 +10416,23 @@ fileprivate struct FfiConverterOptionDictionaryStringTypeLoroValue: FfiConverter } } -fileprivate struct FfiConverterSequenceUInt8: FfiConverterRustBuffer { - typealias SwiftType = [UInt8] +fileprivate struct FfiConverterSequenceUInt64: FfiConverterRustBuffer { + typealias SwiftType = [UInt64] - public static func write(_ value: [UInt8], into buf: inout [UInt8]) { + public static func write(_ value: [UInt64], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { - FfiConverterUInt8.write(item, into: &buf) + FfiConverterUInt64.write(item, into: &buf) } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [UInt8] { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [UInt64] { let len: Int32 = try readInt(&buf) - var seq = [UInt8]() + var seq = [UInt64]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterUInt8.read(from: &buf)) + seq.append(try FfiConverterUInt64.read(from: &buf)) } return seq } @@ -7590,6 +10504,28 @@ fileprivate struct FfiConverterSequenceTypeContainerDiff: FfiConverterRustBuffer } } +fileprivate struct FfiConverterSequenceTypeContainerPath: FfiConverterRustBuffer { + typealias SwiftType = [ContainerPath] + + public static func write(_ value: [ContainerPath], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeContainerPath.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [ContainerPath] { + let len: Int32 = try readInt(&buf) + var seq = [ContainerPath]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeContainerPath.read(from: &buf)) + } + return seq + } +} + fileprivate struct FfiConverterSequenceTypeCursorWithPos: FfiConverterRustBuffer { typealias SwiftType = [CursorWithPos] @@ -7612,6 +10548,50 @@ fileprivate struct FfiConverterSequenceTypeCursorWithPos: FfiConverterRustBuffer } } +fileprivate struct FfiConverterSequenceTypeID: FfiConverterRustBuffer { + typealias SwiftType = [Id] + + public static func write(_ value: [Id], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeID.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Id] { + let len: Int32 = try readInt(&buf) + var seq = [Id]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeID.read(from: &buf)) + } + return seq + } +} + +fileprivate struct FfiConverterSequenceTypeIdSpan: FfiConverterRustBuffer { + typealias SwiftType = [IdSpan] + + public static func write(_ value: [IdSpan], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeIdSpan.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [IdSpan] { + let len: Int32 = try readInt(&buf) + var seq = [IdSpan]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeIdSpan.read(from: &buf)) + } + return seq + } +} + fileprivate struct FfiConverterSequenceTypePathItem: FfiConverterRustBuffer { typealias SwiftType = [PathItem] @@ -7766,6 +10746,52 @@ fileprivate struct FfiConverterSequenceTypeTextDelta: FfiConverterRustBuffer { } } +fileprivate struct FfiConverterDictionaryUInt64TypeCounterSpan: FfiConverterRustBuffer { + public static func write(_ value: [UInt64: CounterSpan], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for (key, value) in value { + FfiConverterUInt64.write(key, into: &buf) + FfiConverterTypeCounterSpan.write(value, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [UInt64: CounterSpan] { + let len: Int32 = try readInt(&buf) + var dict = [UInt64: CounterSpan]() + dict.reserveCapacity(Int(len)) + for _ in 0.. [UInt64: PeerInfo] { + let len: Int32 = try readInt(&buf) + var dict = [UInt64: PeerInfo]() + dict.reserveCapacity(Int(len)) + for _ in 0.. SubId { - return try FfiConverterUInt32.read(from: &buf) - } - - public static func write(_ value: SubId, into buf: inout [UInt8]) { - return FfiConverterUInt32.write(value, into: &buf) - } - - public static func lift(_ value: UInt32) throws -> SubId { - return try FfiConverterUInt32.lift(value) - } - - public static func lower(_ value: SubId) -> UInt32 { - return FfiConverterUInt32.lower(value) - } -} - - -public func FfiConverterTypeSubID_lift(_ value: UInt32) throws -> SubId { - return try FfiConverterTypeSubID.lift(value) -} - -public func FfiConverterTypeSubID_lower(_ value: SubId) -> UInt32 { - return FfiConverterTypeSubID.lower(value) -} - - private enum InitializationResult { case ok case contractVersionMismatch @@ -7861,9 +10853,63 @@ private var initializationResult: InitializationResult = { if bindings_contract_version != scaffolding_contract_version { return InitializationResult.contractVersionMismatch } + if (uniffi_loro_checksum_method_awareness_apply() != 41900) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_awareness_encode() != 37443) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_awareness_encode_all() != 38982) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_awareness_get_all_states() != 30017) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_awareness_get_local_state() != 59706) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_awareness_peer() != 10202) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_awareness_remove_outdated() != 1483) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_awareness_set_local_state() != 517) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_configure_fork() != 57176) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_configure_merge_interval() != 43546) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_configure_record_timestamp() != 41033) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_configure_set_merge_interval() != 4893) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_configure_set_record_timestamp() != 30145) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_configure_text_style_config() != 50151) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_containeridlike_as_container_id() != 41081) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_fractionalindex_to_string() != 57024) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_frontiers_encode() != 48230) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_frontiers_eq() != 20207) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_localupdatecallback_on_local_update() != 21789) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorocounter_decrement() != 53919) { return InitializationResult.apiChecksumMismatch } @@ -7879,27 +10925,66 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_attach() != 7252) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_check_state_correctness_slow() != 43878) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_checkout() != 415) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorodoc_checkout_to_latest() != 2349) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_cmp_with_frontiers() != 31942) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_commit() != 53174) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_commit_with() != 29999) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorodoc_compact_change_store() != 26224) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorodoc_config() != 3400) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorodoc_config_text_style() != 52393) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorodoc_decode_import_blob_meta() != 12658) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_detach() != 61399) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorodoc_export_from() != 2990) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_export_json_updates() != 15152) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_export_snapshot() != 8377) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_export_state_only() != 16747) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorodoc_export_trimmed_snapshot() != 3451) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorodoc_export_updates_in_range() != 35227) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_fork() != 45665) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_free_diff_calculator() != 32937) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorodoc_free_history_cache() != 22144) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_frontiers_to_vv() != 11123) { return InitializationResult.apiChecksumMismatch } @@ -7909,12 +10994,21 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_get_by_str_path() != 6739) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_get_change() != 17896) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_get_counter() != 12597) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_get_cursor_pos() != 30480) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_get_deep_value() != 3404) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_get_deep_value_with_id() != 49124) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_get_list() != 9609) { return InitializationResult.apiChecksumMismatch } @@ -7924,30 +11018,48 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_get_movable_list() != 7302) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_get_path_to_container() != 62623) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_get_text() != 56069) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorodoc_get_tree() != 54189) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorodoc_import() != 8639) { + if (uniffi_loro_checksum_method_lorodoc_get_value() != 29857) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorodoc_has_history_cache() != 53741) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorodoc_import() != 11528) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorodoc_import_batch() != 60062) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorodoc_import_with() != 59166) { + if (uniffi_loro_checksum_method_lorodoc_import_json_updates() != 57379) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorodoc_import_with() != 12897) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorodoc_is_detached() != 30909) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_jsonpath() != 15996) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_len_changes() != 62401) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorodoc_len_ops() != 11644) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_log_estimate_size() != 19429) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_oplog_frontiers() != 49043) { return InitializationResult.apiChecksumMismatch } @@ -7960,7 +11072,7 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_set_change_merge_interval() != 55133) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorodoc_set_fractional_index_jitter() != 47450) { + if (uniffi_loro_checksum_method_lorodoc_set_next_commit_message() != 18940) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorodoc_set_peer_id() != 29379) { @@ -7975,13 +11087,16 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_state_vv() != 1627) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorodoc_subscribe() != 28252) { + if (uniffi_loro_checksum_method_lorodoc_subscribe() != 7981) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorodoc_subscribe_local_update() != 58652) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorodoc_subscribe_root() != 7800) { + if (uniffi_loro_checksum_method_lorodoc_subscribe_root() != 16564) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorodoc_unsubscribe() != 32901) { + if (uniffi_loro_checksum_method_lorodoc_trimmed_vv() != 26703) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorodoc_vv_to_frontiers() != 47960) { @@ -8215,24 +11330,30 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorotext_update() != 55624) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorotree_children() != 53501) { + if (uniffi_loro_checksum_method_lorotree_children() != 4750) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorotree_children_num() != 14969) { + if (uniffi_loro_checksum_method_lorotree_children_num() != 50997) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorotree_contains() != 62174) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorotree_create() != 44237) { + if (uniffi_loro_checksum_method_lorotree_create() != 55490) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorotree_create_at() != 42548) { + if (uniffi_loro_checksum_method_lorotree_create_at() != 64751) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorotree_delete() != 36355) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorotree_disable_fractional_index() != 52853) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorotree_enable_fractional_index() != 39633) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorotree_fractional_index() != 51036) { return InitializationResult.apiChecksumMismatch } @@ -8251,7 +11372,13 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorotree_is_attached() != 37303) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorotree_mov() != 51136) { + if (uniffi_loro_checksum_method_lorotree_is_fractional_index_enabled() != 19364) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorotree_is_node_deleted() != 7339) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorotree_mov() != 33288) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorotree_mov_after() != 48871) { @@ -8260,13 +11387,16 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorotree_mov_before() != 39654) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorotree_mov_to() != 12640) { + if (uniffi_loro_checksum_method_lorotree_mov_to() != 21629) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorotree_nodes() != 31738) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorotree_parent() != 11311) { + if (uniffi_loro_checksum_method_lorotree_parent() != 6903) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorotree_roots() != 60881) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorounknown_id() != 65156) { @@ -8281,9 +11411,18 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_onpush_on_push() != 4043) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_styleconfigmap_get() != 25442) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_styleconfigmap_insert() != 49128) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_subscriber_on_diff() != 462) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_subscription_detach() != 64699) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_undomanager_add_exclude_origin_prefix() != 61306) { return InitializationResult.apiChecksumMismatch } @@ -8314,6 +11453,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_undomanager_undo() != 32659) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_unsubscriber_on_unsubscribe() != 17877) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_valueorcontainer_as_container() != 61163) { return InitializationResult.apiChecksumMismatch } @@ -8344,18 +11486,69 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_valueorcontainer_is_value() != 13911) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_versionvector_diff() != 29529) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_versionvector_encode() != 64665) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_versionvector_eq() != 30406) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_versionvector_extend_to_include_vv() != 28076) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_versionvector_get_last() != 45434) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_versionvector_get_missing_span() != 2797) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_versionvector_includes_id() != 50408) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_versionvector_includes_vv() != 23089) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_versionvector_intersect_span() != 54748) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_versionvector_merge() != 23694) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_versionvector_partial_cmp() != 27570) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_versionvector_set_end() != 27313) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_versionvector_set_last() != 40968) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_constructor_awareness_new() != 33037) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_constructor_cursor_new() != 11721) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_constructor_fractionalindex_from_bytes() != 35415) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_constructor_fractionalindex_from_hex_string() != 10737) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_constructor_frontiers_decode() != 27043) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_constructor_frontiers_from_id() != 60928) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_constructor_frontiers_from_ids() != 61832) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_constructor_frontiers_new() != 5172) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_constructor_lorocounter_new() != 44867) { return InitializationResult.apiChecksumMismatch } @@ -8377,18 +11570,32 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_constructor_lorotree_new() != 42150) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_constructor_styleconfigmap_default_rich_text_config() != 46944) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_constructor_styleconfigmap_new() != 23831) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_constructor_subscription_new() != 51704) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_constructor_undomanager_new() != 35328) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_constructor_versionvector_decode() != 19639) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_constructor_versionvector_new() != 31126) { return InitializationResult.apiChecksumMismatch } uniffiCallbackInitContainerIdLike() + uniffiCallbackInitLocalUpdateCallback() uniffiCallbackInitLoroValueLike() uniffiCallbackInitOnPop() uniffiCallbackInitOnPush() uniffiCallbackInitSubscriber() + uniffiCallbackInitUnsubscriber() return InitializationResult.ok }() diff --git a/Sources/Loro/Value.swift b/Sources/Loro/Value.swift index 4ecedd4..5c07098 100644 --- a/Sources/Loro/Value.swift +++ b/Sources/Loro/Value.swift @@ -4,6 +4,7 @@ // // Created by Leon Zhao on 2024/8/6. // +import Foundation extension LoroValue: LoroValueLike { public func asLoroValue() -> LoroValue { @@ -99,7 +100,7 @@ extension String:LoroValueLike{ extension Array: LoroValueLike where Element:LoroValueLike{ public func asLoroValue() -> LoroValue { if let uint8Array = self as? [UInt8] { - return LoroValue.binary(value: uint8Array) + return LoroValue.binary(value: Data(uint8Array)) } else { let loroValues = self.map { $0.asLoroValue() } return LoroValue.list(value: loroValues) @@ -120,3 +121,9 @@ extension ContainerId:LoroValueLike{ return LoroValue.container(value: self) } } + +extension Data: LoroValueLike{ + public func asLoroValue() -> LoroValue { + return LoroValue.binary(value: self) + } +} \ No newline at end of file diff --git a/Sources/Loro/Version.swift b/Sources/Loro/Version.swift new file mode 100644 index 0000000..84802d6 --- /dev/null +++ b/Sources/Loro/Version.swift @@ -0,0 +1,11 @@ +extension VersionVector: Equatable{ + static public func == (lhs: VersionVector, rhs: VersionVector) -> Bool { + return lhs.eq(other: rhs) + } +} + +extension Frontiers: Equatable{ + static public func == (lhs: Frontiers, rhs: Frontiers) -> Bool { + return lhs.eq(other: rhs) + } +} \ No newline at end of file diff --git a/Tests/LoroTests/LoroTests.swift b/Tests/LoroTests/LoroTests.swift index ddab122..d82f4d3 100644 --- a/Tests/LoroTests/LoroTests.swift +++ b/Tests/LoroTests/LoroTests.swift @@ -5,14 +5,13 @@ final class LoroTests: XCTestCase { func testEvent(){ let doc = LoroDoc() var num = 0 - let id = doc.subscribeRoot{ diffEvent in + let _ = doc.subscribeRoot{ diffEvent in num += 1 } let list = doc.getList(id: "list") try! list.insert(pos: 0, v: 123) doc.commit() XCTAssertEqual(num, 1) - doc.unsubscribe(subId: id) } func testText(){ @@ -37,7 +36,7 @@ final class LoroTests: XCTestCase { try! doc2.setPeerId(peer: 1) let text2 = doc2.getText(id: "text") try! text2.insert(pos: 0, s:"123") - try! doc2.import(bytes: doc.exportSnapshot()) + let _ = try! doc2.import(bytes: doc.exportSnapshot()) try! doc2.importBatch(bytes: [doc.exportSnapshot(), doc.exportFrom(vv: VersionVector())]) XCTAssertEqual(text2.toString(), "bc123") } From dc2c1f4e795ca69b65e119b1e1298be4ae832184 Mon Sep 17 00:00:00 2001 From: Leon Zhao Date: Sat, 5 Oct 2024 20:22:28 +0800 Subject: [PATCH 08/12] chore: --- Package.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Package.swift b/Package.swift index e0efd5d..3752229 100644 --- a/Package.swift +++ b/Package.swift @@ -6,15 +6,15 @@ import PackageDescription let FFIbinaryTarget: PackageDescription.Target -// if ProcessInfo.processInfo.environment["LOCAL_BUILD"] != nil { +if ProcessInfo.processInfo.environment["LOCAL_BUILD"] != nil { FFIbinaryTarget = .binaryTarget(name: "LoroFFI", path: "./loroFFI.xcframework.zip") -// }else { -// FFIbinaryTarget = .binaryTarget( -// name: "LoroFFI", -// url: "https://github.com/loro-dev/loro-swift/releases/download/0.16.2-alpha.2/loroFFI.xcframework.zip", -// checksum: "002f5343f0088f05ac90183e5dc1545e6b1f53f39b547ec7d3c2aa07d0f643c8" -// ) -// } +}else { + FFIbinaryTarget = .binaryTarget( + name: "LoroFFI", + url: "https://github.com/loro-dev/loro-swift/releases/download/0.16.2-alpha.2/loroFFI.xcframework.zip", + checksum: "002f5343f0088f05ac90183e5dc1545e6b1f53f39b547ec7d3c2aa07d0f643c8" + ) +} let package = Package( name: "Loro", From a83c5881683325745b7932030dbfeeea1f7ea598 Mon Sep 17 00:00:00 2001 From: leeeon233 Date: Thu, 10 Oct 2024 14:44:51 +0800 Subject: [PATCH 09/12] fix: rename trimmed --- Package.swift | 16 +++---- Sources/Loro/LoroFFI.swift | 82 ++++++++++++++++----------------- Tests/LoroTests/LoroTests.swift | 3 +- loro-rs/Cargo.lock | 1 + loro-rs/src/loro.udl | 8 ++-- 5 files changed, 56 insertions(+), 54 deletions(-) diff --git a/Package.swift b/Package.swift index 2ff3c7c..68eacb7 100644 --- a/Package.swift +++ b/Package.swift @@ -6,15 +6,15 @@ import PackageDescription let FFIbinaryTarget: PackageDescription.Target -if ProcessInfo.processInfo.environment["LOCAL_BUILD"] != nil { +// if ProcessInfo.processInfo.environment["LOCAL_BUILD"] != nil { FFIbinaryTarget = .binaryTarget(name: "LoroFFI", path: "./loroFFI.xcframework.zip") -}else { - FFIbinaryTarget = .binaryTarget( - name: "LoroFFI", - url: "https://github.com/loro-dev/loro-swift/releases/download/0.16.2-alpha.3/loroFFI.xcframework.zip", - checksum: "9475660c4fcee609a498212b8ca038278b34c1325b30fece0ce5740d4025377a" - ) -} +// }else { +// FFIbinaryTarget = .binaryTarget( +// name: "LoroFFI", +// url: "https://github.com/loro-dev/loro-swift/releases/download/0.16.2-alpha.3/loroFFI.xcframework.zip", +// checksum: "9475660c4fcee609a498212b8ca038278b34c1325b30fece0ce5740d4025377a" +// ) +// } let package = Package( name: "Loro", diff --git a/Sources/Loro/LoroFFI.swift b/Sources/Loro/LoroFFI.swift index 120ae68..6ac1419 100644 --- a/Sources/Loro/LoroFFI.swift +++ b/Sources/Loro/LoroFFI.swift @@ -1802,6 +1802,8 @@ public protocol LoroDocProtocol : AnyObject { */ func exportJsonUpdates(startVv: VersionVector, endVv: VersionVector) -> String + func exportShallowSnapshot(frontiers: Frontiers) -> Data + /** * Export the current state and history of the document. */ @@ -1809,8 +1811,6 @@ public protocol LoroDocProtocol : AnyObject { func exportStateOnly(frontiers: Frontiers?) throws -> Data - func exportTrimmedSnapshot(frontiers: Frontiers) -> Data - func exportUpdatesInRange(spans: [IdSpan]) -> Data /** @@ -2053,6 +2053,13 @@ public protocol LoroDocProtocol : AnyObject { */ func setRecordTimestamp(record: Bool) + /** + * Get the `VersionVector` of trimmed history + * + * The ops included by the trimmed history are not in the doc. + */ + func shallowSinceVv() -> VersionVector + /** * Get the `Frontiers` version of `DocState` * @@ -2086,13 +2093,6 @@ public protocol LoroDocProtocol : AnyObject { */ func subscribeRoot(subscriber: Subscriber) -> Subscription - /** - * Get the `VersionVector` of trimmed history - * - * The ops included by the trimmed history are not in the doc. - */ - func trimmedVv() -> VersionVector - /** * Convert `VersionVector` into `Frontiers` */ @@ -2323,6 +2323,14 @@ open func exportJsonUpdates(startVv: VersionVector, endVv: VersionVector) -> Str FfiConverterTypeVersionVector.lower(endVv),$0 ) }) +} + +open func exportShallowSnapshot(frontiers: Frontiers) -> Data { + return try! FfiConverterData.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_export_shallow_snapshot(self.uniffiClonePointer(), + FfiConverterTypeFrontiers.lower(frontiers),$0 + ) +}) } /** @@ -2343,14 +2351,6 @@ open func exportStateOnly(frontiers: Frontiers?)throws -> Data { }) } -open func exportTrimmedSnapshot(frontiers: Frontiers) -> Data { - return try! FfiConverterData.lift(try! rustCall() { - uniffi_loro_fn_method_lorodoc_export_trimmed_snapshot(self.uniffiClonePointer(), - FfiConverterTypeFrontiers.lower(frontiers),$0 - ) -}) -} - open func exportUpdatesInRange(spans: [IdSpan]) -> Data { return try! FfiConverterData.lift(try! rustCall() { uniffi_loro_fn_method_lorodoc_export_updates_in_range(self.uniffiClonePointer(), @@ -2786,6 +2786,18 @@ open func setRecordTimestamp(record: Bool) {try! rustCall() { FfiConverterBool.lower(record),$0 ) } +} + + /** + * Get the `VersionVector` of trimmed history + * + * The ops included by the trimmed history are not in the doc. + */ +open func shallowSinceVv() -> VersionVector { + return try! FfiConverterTypeVersionVector.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_shallow_since_vv(self.uniffiClonePointer(),$0 + ) +}) } /** @@ -2848,18 +2860,6 @@ open func subscribeRoot(subscriber: Subscriber) -> Subscription { FfiConverterTypeSubscriber.lower(subscriber),$0 ) }) -} - - /** - * Get the `VersionVector` of trimmed history - * - * The ops included by the trimmed history are not in the doc. - */ -open func trimmedVv() -> VersionVector { - return try! FfiConverterTypeVersionVector.lift(try! rustCall() { - uniffi_loro_fn_method_lorodoc_trimmed_vv(self.uniffiClonePointer(),$0 - ) -}) } /** @@ -8947,7 +8947,7 @@ public enum LoroEncodeError { case FrontiersNotFound(message: String) - case TrimmedSnapshotIncompatibleWithOldFormat(message: String) + case ShallowSnapshotIncompatibleWithOldFormat(message: String) case UnknownContainer(message: String) @@ -8968,7 +8968,7 @@ public struct FfiConverterTypeLoroEncodeError: FfiConverterRustBuffer { message: try FfiConverterString.read(from: &buf) ) - case 2: return .TrimmedSnapshotIncompatibleWithOldFormat( + case 2: return .ShallowSnapshotIncompatibleWithOldFormat( message: try FfiConverterString.read(from: &buf) ) @@ -8989,7 +8989,7 @@ public struct FfiConverterTypeLoroEncodeError: FfiConverterRustBuffer { case .FrontiersNotFound(_ /* message is ignored*/): writeInt(&buf, Int32(1)) - case .TrimmedSnapshotIncompatibleWithOldFormat(_ /* message is ignored*/): + case .ShallowSnapshotIncompatibleWithOldFormat(_ /* message is ignored*/): writeInt(&buf, Int32(2)) case .UnknownContainer(_ /* message is ignored*/): writeInt(&buf, Int32(3)) @@ -9077,7 +9077,7 @@ public enum LoroError { case ImportUpdatesThatDependsOnOutdatedVersion(message: String) - case SwitchToTrimmedVersion(message: String) + case SwitchToVersionBeforeShallowRoot(message: String) case ContainerDeleted(message: String) @@ -9226,7 +9226,7 @@ public struct FfiConverterTypeLoroError: FfiConverterRustBuffer { message: try FfiConverterString.read(from: &buf) ) - case 33: return .SwitchToTrimmedVersion( + case 33: return .SwitchToVersionBeforeShallowRoot( message: try FfiConverterString.read(from: &buf) ) @@ -9317,7 +9317,7 @@ public struct FfiConverterTypeLoroError: FfiConverterRustBuffer { writeInt(&buf, Int32(31)) case .ImportUpdatesThatDependsOnOutdatedVersion(_ /* message is ignored*/): writeInt(&buf, Int32(32)) - case .SwitchToTrimmedVersion(_ /* message is ignored*/): + case .SwitchToVersionBeforeShallowRoot(_ /* message is ignored*/): writeInt(&buf, Int32(33)) case .ContainerDeleted(_ /* message is ignored*/): writeInt(&buf, Int32(34)) @@ -10985,13 +10985,13 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_export_json_updates() != 15152) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorodoc_export_snapshot() != 8377) { + if (uniffi_loro_checksum_method_lorodoc_export_shallow_snapshot() != 50284) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorodoc_export_state_only() != 16747) { + if (uniffi_loro_checksum_method_lorodoc_export_snapshot() != 8377) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorodoc_export_trimmed_snapshot() != 3451) { + if (uniffi_loro_checksum_method_lorodoc_export_state_only() != 16747) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorodoc_export_updates_in_range() != 35227) { @@ -11102,6 +11102,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_set_record_timestamp() != 15945) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_shallow_since_vv() != 13449) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_state_frontiers() != 17079) { return InitializationResult.apiChecksumMismatch } @@ -11117,9 +11120,6 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_subscribe_root() != 16564) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorodoc_trimmed_vv() != 26703) { - return InitializationResult.apiChecksumMismatch - } if (uniffi_loro_checksum_method_lorodoc_vv_to_frontiers() != 47960) { return InitializationResult.apiChecksumMismatch } diff --git a/Tests/LoroTests/LoroTests.swift b/Tests/LoroTests/LoroTests.swift index 4571647..31007da 100644 --- a/Tests/LoroTests/LoroTests.swift +++ b/Tests/LoroTests/LoroTests.swift @@ -5,12 +5,13 @@ final class LoroTests: XCTestCase { func testEvent(){ let doc = LoroDoc() var num = 0 - let _ = doc.subscribeRoot{ diffEvent in + let sub = doc.subscribeRoot{ diffEvent in num += 1 } let list = doc.getList(id: "list") try! list.insert(pos: 0, v: 123) doc.commit() + sub.detach() XCTAssertEqual(num, 1) } diff --git a/loro-rs/Cargo.lock b/loro-rs/Cargo.lock index 44007df..0bc7d98 100644 --- a/loro-rs/Cargo.lock +++ b/loro-rs/Cargo.lock @@ -739,6 +739,7 @@ dependencies = [ "lz4_flex", "once_cell", "quick_cache", + "tracing", "xxhash-rust", ] diff --git a/loro-rs/src/loro.udl b/loro-rs/src/loro.udl index fb192a6..d0e1e5e 100644 --- a/loro-rs/src/loro.udl +++ b/loro-rs/src/loro.udl @@ -252,7 +252,7 @@ interface LoroDoc{ /// Get the `VersionVector` of trimmed history /// /// The ops included by the trimmed history are not in the doc. - VersionVector trimmed_vv(); + VersionVector shallow_since_vv(); /// Get the total number of operations in the `OpLog` u64 len_ops(); @@ -339,7 +339,7 @@ interface LoroDoc{ bytes export_updates_in_range([ByRef]sequence spans); - bytes export_trimmed_snapshot([ByRef]Frontiers frontiers); + bytes export_shallow_snapshot([ByRef]Frontiers frontiers); [Throws=LoroEncodeError] bytes export_state_only(Frontiers? frontiers); @@ -1344,7 +1344,7 @@ enum LoroError { "EndIndexLessThanStartIndex", "InvalidRootContainerName", "ImportUpdatesThatDependsOnOutdatedVersion", - "SwitchToTrimmedVersion", + "SwitchToVersionBeforeShallowRoot", "ContainerDeleted", "ConcurrentOpsWithSamePeerID", "InvalidPeerID", @@ -1366,6 +1366,6 @@ enum JsonPathError{ [Error, NonExhaustive] enum LoroEncodeError{ "FrontiersNotFound", - "TrimmedSnapshotIncompatibleWithOldFormat", + "ShallowSnapshotIncompatibleWithOldFormat", "UnknownContainer", }; \ No newline at end of file From a0884e1f928af200c129442f953560f4bdba3cec Mon Sep 17 00:00:00 2001 From: Leon Zhao Date: Thu, 10 Oct 2024 21:00:16 +0800 Subject: [PATCH 10/12] chore: release v1.0.0-alpha.5 --- Package.swift | 16 ++++++++-------- README.md | 12 +++++------- scripts/build_swift_ffi.sh | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Package.swift b/Package.swift index 68eacb7..24d038d 100644 --- a/Package.swift +++ b/Package.swift @@ -6,15 +6,15 @@ import PackageDescription let FFIbinaryTarget: PackageDescription.Target -// if ProcessInfo.processInfo.environment["LOCAL_BUILD"] != nil { +if ProcessInfo.processInfo.environment["LOCAL_BUILD"] != nil { FFIbinaryTarget = .binaryTarget(name: "LoroFFI", path: "./loroFFI.xcframework.zip") -// }else { -// FFIbinaryTarget = .binaryTarget( -// name: "LoroFFI", -// url: "https://github.com/loro-dev/loro-swift/releases/download/0.16.2-alpha.3/loroFFI.xcframework.zip", -// checksum: "9475660c4fcee609a498212b8ca038278b34c1325b30fece0ce5740d4025377a" -// ) -// } +}else { + FFIbinaryTarget = .binaryTarget( + name: "LoroFFI", + url: "https://github.com/loro-dev/loro-swift/releases/download/1.0.0-alpha.5/loroFFI.xcframework.zip", + checksum: "2b9c11aecf4f90ead28e12c8487b072e3fc406885e91ab2d1999b8c83040bd6c" + ) +} let package = Package( name: "Loro", diff --git a/README.md b/README.md index 2d3ee7c..d512903 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ If you have any suggestions for API, please feel free to create an issue or join - [x] Checkout - [x] Subscribe Event - [x] UndoManager -- [ ] Bindings for all types in Loro +- [x] Bindings for all types in Loro - [ ] Tests - [ ] Benchmarks @@ -37,7 +37,7 @@ let package = Package( products: [......], dependencies:[ ..., - .package(url: "https://github.com/loro-dev/loro-swift.git", from: "0.16.2-alpha.3") + .package(url: "https://github.com/loro-dev/loro-swift.git", from: "1.0.0-alpha.5") ], targets:[ .executableTarget( @@ -66,11 +66,9 @@ let s = text.toString() // XCTAssertEqual(s, "bc") // subscribe the event -let subId = doc.subscribeRoot{ diffEvent in +let sub = doc.subscribeRoot{ diffEvent in print(diffEvent) } -// unsubscribe -doc.unsubscribe(subId: id) // export updates or snapshot let doc2 = LoroDoc() @@ -78,8 +76,8 @@ let snapshot = doc.exportSnapshot() let updates = doc.exportFrom(vv: VersionVector()) // import updates or snapshot -try! doc2.import(snapshot) -try! doc2.import(updates) +let status = try! doc2.import(snapshot) +let status2 = try! doc2.import(updates) // import batch of updates or snapshot try! doc2.importBatch(bytes: [snapshot, updates]) diff --git a/scripts/build_swift_ffi.sh b/scripts/build_swift_ffi.sh index aea0ca2..54fece4 100755 --- a/scripts/build_swift_ffi.sh +++ b/scripts/build_swift_ffi.sh @@ -20,7 +20,7 @@ XCFRAMEWORK_FOLDER="$THIS_SCRIPT_DIR/../${FRAMEWORK_NAME}.xcframework" # (as of 10/10/23), but leaving it open to float seems less useful than # moving the pinning forward, since Catalyst support (target macabi) still # requires an active, nightly toolchain. -RUST_NIGHTLY="nightly-2024-05-23" +RUST_NIGHTLY="nightly-2024-10-09" echo "Install nightly and rust-src for Catalyst" rustup toolchain install ${RUST_NIGHTLY} From 3b7be5069b48324f6b681a075eddf3cb73d7cb21 Mon Sep 17 00:00:00 2001 From: Leon Zhao Date: Wed, 27 Nov 2024 16:33:46 +0800 Subject: [PATCH 11/12] feat: update loro to v1.1.3 --- Sources/Loro/Loro.swift | 20 + Sources/Loro/LoroFFI.swift | 1260 +++++++++++++++++++++++++++++++++--- loro-rs/Cargo.lock | 105 +-- loro-rs/src/loro.udl | 227 ++++++- 4 files changed, 1385 insertions(+), 227 deletions(-) diff --git a/Sources/Loro/Loro.swift b/Sources/Loro/Loro.swift index fda67c9..ac8cfcd 100644 --- a/Sources/Loro/Loro.swift +++ b/Sources/Loro/Loro.swift @@ -53,3 +53,23 @@ extension UndoManager{ } } } + + +class ChangeAncestorsTravel: ChangeAncestorsTraveler{ + private let closure: (ChangeMeta)->Bool + + public init(closure: @escaping (ChangeMeta)->Bool) { + self.closure = closure + } + + func travel(change: ChangeMeta) -> Bool { + closure(change) + } +} + +extension LoroDoc{ + public func travelChangeAncestors(ids: [Id], f: @escaping (ChangeMeta)->Bool) throws { + let closureSubscriber = ChangeAncestorsTravel(closure: f) + try self.travelChangeAncestors(ids: ids, f: closureSubscriber) + } +} \ No newline at end of file diff --git a/Sources/Loro/LoroFFI.swift b/Sources/Loro/LoroFFI.swift index 6ac1419..c29236a 100644 --- a/Sources/Loro/LoroFFI.swift +++ b/Sources/Loro/LoroFFI.swift @@ -713,6 +713,163 @@ public func FfiConverterTypeAwareness_lower(_ value: Awareness) -> UnsafeMutable +public protocol ChangeAncestorsTraveler : AnyObject { + + func travel(change: ChangeMeta) -> Bool + +} + +open class ChangeAncestorsTravelerImpl: + ChangeAncestorsTraveler { + fileprivate let pointer: UnsafeMutableRawPointer! + + /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + /// This constructor can be used to instantiate a fake object. + /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + /// + /// - Warning: + /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + public init(noPointer: NoPointer) { + self.pointer = nil + } + + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_loro_fn_clone_changeancestorstraveler(self.pointer, $0) } + } + // No primary constructor declared for this class. + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_loro_fn_free_changeancestorstraveler(pointer, $0) } + } + + + + +open func travel(change: ChangeMeta) -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_changeancestorstraveler_travel(self.uniffiClonePointer(), + FfiConverterTypeChangeMeta.lower(change),$0 + ) +}) +} + + +} +// Magic number for the Rust proxy to call using the same mechanism as every other method, +// to free the callback once it's dropped by Rust. +private let IDX_CALLBACK_FREE: Int32 = 0 +// Callback return codes +private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0 +private let UNIFFI_CALLBACK_ERROR: Int32 = 1 +private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2 + +// Put the implementation in a struct so we don't pollute the top-level namespace +fileprivate struct UniffiCallbackInterfaceChangeAncestorsTraveler { + + // Create the VTable using a series of closures. + // Swift automatically converts these into C callback functions. + static var vtable: UniffiVTableCallbackInterfaceChangeAncestorsTraveler = UniffiVTableCallbackInterfaceChangeAncestorsTraveler( + travel: { ( + uniffiHandle: UInt64, + change: RustBuffer, + uniffiOutReturn: UnsafeMutablePointer, + uniffiCallStatus: UnsafeMutablePointer + ) in + let makeCall = { + () throws -> Bool in + guard let uniffiObj = try? FfiConverterTypeChangeAncestorsTraveler.handleMap.get(handle: uniffiHandle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return uniffiObj.travel( + change: try FfiConverterTypeChangeMeta.lift(change) + ) + } + + + let writeReturn = { uniffiOutReturn.pointee = FfiConverterBool.lower($0) } + uniffiTraitInterfaceCall( + callStatus: uniffiCallStatus, + makeCall: makeCall, + writeReturn: writeReturn + ) + }, + uniffiFree: { (uniffiHandle: UInt64) -> () in + let result = try? FfiConverterTypeChangeAncestorsTraveler.handleMap.remove(handle: uniffiHandle) + if result == nil { + print("Uniffi callback interface ChangeAncestorsTraveler: handle missing in uniffiFree") + } + } + ) +} + +private func uniffiCallbackInitChangeAncestorsTraveler() { + uniffi_loro_fn_init_callback_vtable_changeancestorstraveler(&UniffiCallbackInterfaceChangeAncestorsTraveler.vtable) +} + +public struct FfiConverterTypeChangeAncestorsTraveler: FfiConverter { + fileprivate static var handleMap = UniffiHandleMap() + + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = ChangeAncestorsTraveler + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> ChangeAncestorsTraveler { + return ChangeAncestorsTravelerImpl(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: ChangeAncestorsTraveler) -> UnsafeMutableRawPointer { + guard let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: handleMap.insert(obj: value))) else { + fatalError("Cast to UnsafeMutableRawPointer failed") + } + return ptr + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChangeAncestorsTraveler { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: ChangeAncestorsTraveler, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + + + + +public func FfiConverterTypeChangeAncestorsTraveler_lift(_ pointer: UnsafeMutableRawPointer) throws -> ChangeAncestorsTraveler { + return try FfiConverterTypeChangeAncestorsTraveler.lift(pointer) +} + +public func FfiConverterTypeChangeAncestorsTraveler_lower(_ value: ChangeAncestorsTraveler) -> UnsafeMutableRawPointer { + return FfiConverterTypeChangeAncestorsTraveler.lower(value) +} + + + + public protocol ConfigureProtocol : AnyObject { func fork() -> Configure @@ -917,13 +1074,7 @@ open func asContainerId(ty: ContainerType) -> ContainerId { } -// Magic number for the Rust proxy to call using the same mechanism as every other method, -// to free the callback once it's dropped by Rust. -private let IDX_CALLBACK_FREE: Int32 = 0 -// Callback return codes -private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0 -private let UNIFFI_CALLBACK_ERROR: Int32 = 1 -private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2 + // Put the implementation in a struct so we don't pollute the top-level namespace fileprivate struct UniffiCallbackInterfaceContainerIdLike { @@ -1554,6 +1705,11 @@ public protocol LoroCounterProtocol : AnyObject { */ func increment(value: Double) throws + /** + * Whether the container is deleted. + */ + func isDeleted() -> Bool + } open class LoroCounter: @@ -1647,6 +1803,16 @@ open func increment(value: Double)throws {try rustCallWithError(FfiConverterTyp } } + /** + * Whether the container is deleted. + */ +open func isDeleted() -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_lorocounter_is_deleted(self.uniffiClonePointer(),$0 + ) +}) +} + } @@ -1716,10 +1882,10 @@ public protocol LoroDocProtocol : AnyObject { /** * Checkout the `DocState` to a specific version. * - * > The document becomes detached during a `checkout` operation. - * > Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`. - * > In a detached state, the document is not editable, and any `import` operations will be - * > recorded in the `OpLog` without being applied to the `DocState`. + * The document becomes detached during a `checkout` operation. + * Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`. + * In a detached state, the document is not editable, and any `import` operations will be + * recorded in the `OpLog` without being applied to the `DocState`. * * You should call `attach` to attach the `DocState` to the latest version of `OpLog`. */ @@ -1748,8 +1914,12 @@ public protocol LoroDocProtocol : AnyObject { * Commit the cumulative auto commit transaction. * * There is a transaction behind every operation. - * It will automatically commit when users invoke export or import. - * The event will be sent after a transaction is committed + * The events will be emitted after a transaction is committed. A transaction is committed when: + * + * - `doc.commit()` is called. + * - `doc.export(mode)` is called. + * - `doc.import(data)` is called. + * - `doc.checkout(version)` is called. */ func commit() @@ -1778,11 +1948,6 @@ public protocol LoroDocProtocol : AnyObject { */ func configTextStyle(textStyle: StyleConfigMap) - /** - * Decodes the metadata for an imported blob from the provided bytes. - */ - func decodeImportBlobMeta(bytes: Data) throws -> ImportBlobMetadata - /** * Force the document enter the detached mode. * @@ -1817,9 +1982,19 @@ public protocol LoroDocProtocol : AnyObject { * Duplicate the document with a different PeerID * * The time complexity and space complexity of this operation are both O(n), + * + * When called in detached mode, it will fork at the current state frontiers. + * It will have the same effect as `fork_at(&self.state_frontiers())`. */ func fork() -> LoroDoc + /** + * Fork the document at the given frontiers. + * + * The created doc will only contain the history before the specified frontiers. + */ + func forkAt(frontiers: Frontiers) -> LoroDoc + /** * Free the cached diff calculator that is used for checkout. */ @@ -1865,6 +2040,21 @@ public protocol LoroDocProtocol : AnyObject { */ func getChange(id: Id) -> ChangeMeta? + /** + * Gets container IDs modified in the given ID range. + * + * **NOTE:** This method will implicitly commit. + * + * This method can be used in conjunction with `doc.travel_change_ancestors()` to traverse + * the history and identify all changes that affected specific containers. + * + * # Arguments + * + * * `id` - The starting ID of the change range + * * `len` - The length of the change range to check + */ + func getChangedContainersIn(id: Id, len: UInt32) -> [ContainerId] + /** * Get a [LoroCounter] by container id. * @@ -1875,12 +2065,12 @@ public protocol LoroDocProtocol : AnyObject { func getCursorPos(cursor: Cursor) throws -> PosQueryResult /** - * Get the current state of the document. + * Get the entire state of the current DocState */ func getDeepValue() -> LoroValue /** - * Get the current state with container id of the doc + * Get the entire state of the current DocState with container id */ func getDeepValueWithId() -> LoroValue @@ -1910,6 +2100,14 @@ public protocol LoroDocProtocol : AnyObject { */ func getPathToContainer(id: ContainerId) -> [ContainerPath]? + /** + * Get the number of operations in the pending transaction. + * + * The pending transaction is the one that is not committed yet. It will be committed + * after calling `doc.commit()`, `doc.export(mode)` or `doc.checkout(version)`. + */ + func getPendingTxnLen() -> UInt32 + /** * Get a [LoroText] by container id. * @@ -1959,6 +2157,11 @@ public protocol LoroDocProtocol : AnyObject { */ func isDetached() -> Bool + /** + * Check if the doc contains the full history. + */ + func isShallow() -> Bool + /** * Evaluate a JSONPath expression on the document and return matching values or handlers. * @@ -2007,6 +2210,11 @@ public protocol LoroDocProtocol : AnyObject { */ func logEstimateSize() + /** + * Minimize the frontiers by removing the unnecessary entries. + */ + func minimizeFrontiers(frontiers: Frontiers) -> FrontiersOrId + /** * Get the `Frontiers` version of `OpLog` */ @@ -2023,7 +2231,7 @@ public protocol LoroDocProtocol : AnyObject { func peerId() -> UInt64 /** - * Set the interval of mergeable changes, in milliseconds. + * Set the interval of mergeable changes, in seconds. * * If two continuous local changes are within the interval, they will be merged into one change. * The default value is 1000 seconds. @@ -2035,7 +2243,7 @@ public protocol LoroDocProtocol : AnyObject { /** * Change the PeerID * - * NOTE: You need ot make sure there is no chance two peer have the same PeerID. + * NOTE: You need to make sure there is no chance two peer have the same PeerID. * If it happens, the document will be corrupted. */ func setPeerId(peer: UInt64) throws @@ -2063,12 +2271,12 @@ public protocol LoroDocProtocol : AnyObject { /** * Get the `Frontiers` version of `DocState` * - * [Learn more about `Frontiers`]() + * Learn more about [`Frontiers`](https://loro.dev/docs/advanced/version_deep_dive) */ func stateFrontiers() -> Frontiers /** - * Get the `VersionVector` version of `OpLog` + * Get the `VersionVector` version of `DocState` */ func stateVv() -> VersionVector @@ -2076,7 +2284,14 @@ public protocol LoroDocProtocol : AnyObject { * Subscribe the events of a container. * * The callback will be invoked when the container is changed. - * Returns a subscription id that can be used to unsubscribe. + * Returns a subscription that can be used to unsubscribe. + * + * The events will be emitted after a transaction is committed. A transaction is committed when: + * + * - `doc.commit()` is called. + * - `doc.export(mode)` is called. + * - `doc.import(data)` is called. + * - `doc.checkout(version)` is called. */ func subscribe(containerId: ContainerId, subscriber: Subscriber) -> Subscription @@ -2089,10 +2304,23 @@ public protocol LoroDocProtocol : AnyObject { * Subscribe all the events. * * The callback will be invoked when any part of the [loro_internal::DocState] is changed. - * Returns a subscription id that can be used to unsubscribe. + * Returns a subscription that can be used to unsubscribe. */ func subscribeRoot(subscriber: Subscriber) -> Subscription + /** + * Traverses the ancestors of the Change containing the given ID, including itself. + * + * This method visits all ancestors in causal order, from the latest to the oldest, + * based on their Lamport timestamps. + * + * # Arguments + * + * * `ids` - The IDs of the Change to start the traversal from. + * * `f` - A mutable function that is called for each ancestor. It can return `ControlFlow::Break(())` to stop the traversal. + */ + func travelChangeAncestors(ids: [Id], f: ChangeAncestorsTraveler) throws + /** * Convert `VersionVector` into `Frontiers` */ @@ -2178,10 +2406,10 @@ open func checkStateCorrectnessSlow() {try! rustCall() { /** * Checkout the `DocState` to a specific version. * - * > The document becomes detached during a `checkout` operation. - * > Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`. - * > In a detached state, the document is not editable, and any `import` operations will be - * > recorded in the `OpLog` without being applied to the `DocState`. + * The document becomes detached during a `checkout` operation. + * Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`. + * In a detached state, the document is not editable, and any `import` operations will be + * recorded in the `OpLog` without being applied to the `DocState`. * * You should call `attach` to attach the `DocState` to the latest version of `OpLog`. */ @@ -2225,8 +2453,12 @@ open func cmpWithFrontiers(other: Frontiers) -> Ordering { * Commit the cumulative auto commit transaction. * * There is a transaction behind every operation. - * It will automatically commit when users invoke export or import. - * The event will be sent after a transaction is committed + * The events will be emitted after a transaction is committed. A transaction is committed when: + * + * - `doc.commit()` is called. + * - `doc.export(mode)` is called. + * - `doc.import(data)` is called. + * - `doc.checkout(version)` is called. */ open func commit() {try! rustCall() { uniffi_loro_fn_method_lorodoc_commit(self.uniffiClonePointer(),$0 @@ -2276,17 +2508,6 @@ open func configTextStyle(textStyle: StyleConfigMap) {try! rustCall() { FfiConverterTypeStyleConfigMap.lower(textStyle),$0 ) } -} - - /** - * Decodes the metadata for an imported blob from the provided bytes. - */ -open func decodeImportBlobMeta(bytes: Data)throws -> ImportBlobMetadata { - return try FfiConverterTypeImportBlobMetadata.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { - uniffi_loro_fn_method_lorodoc_decode_import_blob_meta(self.uniffiClonePointer(), - FfiConverterData.lower(bytes),$0 - ) -}) } /** @@ -2363,12 +2584,28 @@ open func exportUpdatesInRange(spans: [IdSpan]) -> Data { * Duplicate the document with a different PeerID * * The time complexity and space complexity of this operation are both O(n), + * + * When called in detached mode, it will fork at the current state frontiers. + * It will have the same effect as `fork_at(&self.state_frontiers())`. */ open func fork() -> LoroDoc { return try! FfiConverterTypeLoroDoc.lift(try! rustCall() { uniffi_loro_fn_method_lorodoc_fork(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Fork the document at the given frontiers. + * + * The created doc will only contain the history before the specified frontiers. + */ +open func forkAt(frontiers: Frontiers) -> LoroDoc { + return try! FfiConverterTypeLoroDoc.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_fork_at(self.uniffiClonePointer(), + FfiConverterTypeFrontiers.lower(frontiers),$0 + ) +}) } /** @@ -2446,6 +2683,28 @@ open func getChange(id: Id) -> ChangeMeta? { FfiConverterTypeID.lower(id),$0 ) }) +} + + /** + * Gets container IDs modified in the given ID range. + * + * **NOTE:** This method will implicitly commit. + * + * This method can be used in conjunction with `doc.travel_change_ancestors()` to traverse + * the history and identify all changes that affected specific containers. + * + * # Arguments + * + * * `id` - The starting ID of the change range + * * `len` - The length of the change range to check + */ +open func getChangedContainersIn(id: Id, len: UInt32) -> [ContainerId] { + return try! FfiConverterSequenceTypeContainerID.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_get_changed_containers_in(self.uniffiClonePointer(), + FfiConverterTypeID.lower(id), + FfiConverterUInt32.lower(len),$0 + ) +}) } /** @@ -2470,7 +2729,7 @@ open func getCursorPos(cursor: Cursor)throws -> PosQueryResult { } /** - * Get the current state of the document. + * Get the entire state of the current DocState */ open func getDeepValue() -> LoroValue { return try! FfiConverterTypeLoroValue.lift(try! rustCall() { @@ -2480,7 +2739,7 @@ open func getDeepValue() -> LoroValue { } /** - * Get the current state with container id of the doc + * Get the entire state of the current DocState with container id */ open func getDeepValueWithId() -> LoroValue { return try! FfiConverterTypeLoroValue.lift(try! rustCall() { @@ -2537,6 +2796,19 @@ open func getPathToContainer(id: ContainerId) -> [ContainerPath]? { FfiConverterTypeContainerID.lower(id),$0 ) }) +} + + /** + * Get the number of operations in the pending transaction. + * + * The pending transaction is the one that is not committed yet. It will be committed + * after calling `doc.commit()`, `doc.export(mode)` or `doc.checkout(version)`. + */ +open func getPendingTxnLen() -> UInt32 { + return try! FfiConverterUInt32.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_get_pending_txn_len(self.uniffiClonePointer(),$0 + ) +}) } /** @@ -2637,6 +2909,16 @@ open func isDetached() -> Bool { uniffi_loro_fn_method_lorodoc_is_detached(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Check if the doc contains the full history. + */ +open func isShallow() -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_is_shallow(self.uniffiClonePointer(),$0 + ) +}) } /** @@ -2705,6 +2987,17 @@ open func logEstimateSize() {try! rustCall() { uniffi_loro_fn_method_lorodoc_log_estimate_size(self.uniffiClonePointer(),$0 ) } +} + + /** + * Minimize the frontiers by removing the unnecessary entries. + */ +open func minimizeFrontiers(frontiers: Frontiers) -> FrontiersOrId { + return try! FfiConverterTypeFrontiersOrID.lift(try! rustCall() { + uniffi_loro_fn_method_lorodoc_minimize_frontiers(self.uniffiClonePointer(), + FfiConverterTypeFrontiers.lower(frontiers),$0 + ) +}) } /** @@ -2738,7 +3031,7 @@ open func peerId() -> UInt64 { } /** - * Set the interval of mergeable changes, in milliseconds. + * Set the interval of mergeable changes, in seconds. * * If two continuous local changes are within the interval, they will be merged into one change. * The default value is 1000 seconds. @@ -2760,7 +3053,7 @@ open func setNextCommitMessage(msg: String) {try! rustCall() { /** * Change the PeerID * - * NOTE: You need ot make sure there is no chance two peer have the same PeerID. + * NOTE: You need to make sure there is no chance two peer have the same PeerID. * If it happens, the document will be corrupted. */ open func setPeerId(peer: UInt64)throws {try rustCallWithError(FfiConverterTypeLoroError.lift) { @@ -2803,7 +3096,7 @@ open func shallowSinceVv() -> VersionVector { /** * Get the `Frontiers` version of `DocState` * - * [Learn more about `Frontiers`]() + * Learn more about [`Frontiers`](https://loro.dev/docs/advanced/version_deep_dive) */ open func stateFrontiers() -> Frontiers { return try! FfiConverterTypeFrontiers.lift(try! rustCall() { @@ -2813,7 +3106,7 @@ open func stateFrontiers() -> Frontiers { } /** - * Get the `VersionVector` version of `OpLog` + * Get the `VersionVector` version of `DocState` */ open func stateVv() -> VersionVector { return try! FfiConverterTypeVersionVector.lift(try! rustCall() { @@ -2826,7 +3119,14 @@ open func stateVv() -> VersionVector { * Subscribe the events of a container. * * The callback will be invoked when the container is changed. - * Returns a subscription id that can be used to unsubscribe. + * Returns a subscription that can be used to unsubscribe. + * + * The events will be emitted after a transaction is committed. A transaction is committed when: + * + * - `doc.commit()` is called. + * - `doc.export(mode)` is called. + * - `doc.import(data)` is called. + * - `doc.checkout(version)` is called. */ open func subscribe(containerId: ContainerId, subscriber: Subscriber) -> Subscription { return try! FfiConverterTypeSubscription.lift(try! rustCall() { @@ -2852,7 +3152,7 @@ open func subscribeLocalUpdate(callback: LocalUpdateCallback) -> Subscription { * Subscribe all the events. * * The callback will be invoked when any part of the [loro_internal::DocState] is changed. - * Returns a subscription id that can be used to unsubscribe. + * Returns a subscription that can be used to unsubscribe. */ open func subscribeRoot(subscriber: Subscriber) -> Subscription { return try! FfiConverterTypeSubscription.lift(try! rustCall() { @@ -2860,6 +3160,25 @@ open func subscribeRoot(subscriber: Subscriber) -> Subscription { FfiConverterTypeSubscriber.lower(subscriber),$0 ) }) +} + + /** + * Traverses the ancestors of the Change containing the given ID, including itself. + * + * This method visits all ancestors in causal order, from the latest to the oldest, + * based on their Lamport timestamps. + * + * # Arguments + * + * * `ids` - The IDs of the Change to start the traversal from. + * * `f` - A mutable function that is called for each ancestor. It can return `ControlFlow::Break(())` to stop the traversal. + */ +open func travelChangeAncestors(ids: [Id], f: ChangeAncestorsTraveler)throws {try rustCallWithError(FfiConverterTypeChangeTravelError.lift) { + uniffi_loro_fn_method_lorodoc_travel_change_ancestors(self.uniffiClonePointer(), + FfiConverterSequenceTypeID.lower(ids), + FfiConverterTypeChangeAncestorsTraveler.lower(f),$0 + ) +} } /** @@ -2923,6 +3242,11 @@ public func FfiConverterTypeLoroDoc_lower(_ value: LoroDoc) -> UnsafeMutableRawP public protocol LoroListProtocol : AnyObject { + /** + * Delete all elements in the list. + */ + func clear() throws + /** * Delete values at the given position. */ @@ -2940,6 +3264,11 @@ public protocol LoroListProtocol : AnyObject { */ func getDeepValue() -> LoroValue + /** + * Get the ID of the list item at the given position. + */ + func getIdAt(pos: UInt32) -> Id? + /** * Get the shallow value of the container. * @@ -2977,6 +3306,11 @@ public protocol LoroListProtocol : AnyObject { */ func isAttached() -> Bool + /** + * Whether the container is deleted. + */ + func isDeleted() -> Bool + func isEmpty() -> Bool func len() -> UInt32 @@ -2988,6 +3322,14 @@ public protocol LoroListProtocol : AnyObject { func push(v: LoroValueLike) throws + /** + * Converts the LoroList to a Vec of LoroValue. + * + * This method unwraps the internal Arc and clones the data if necessary, + * returning a Vec containing all the elements of the LoroList as LoroValue. + */ + func toVec() -> [LoroValue] + } open class LoroList: @@ -3044,6 +3386,15 @@ public convenience init() { + /** + * Delete all elements in the list. + */ +open func clear()throws {try rustCallWithError(FfiConverterTypeLoroError.lift) { + uniffi_loro_fn_method_lorolist_clear(self.uniffiClonePointer(),$0 + ) +} +} + /** * Delete values at the given position. */ @@ -3078,9 +3429,20 @@ open func getCursor(pos: UInt32, side: Side) -> Cursor? { /** * Get the deep value of the container. */ -open func getDeepValue() -> LoroValue { - return try! FfiConverterTypeLoroValue.lift(try! rustCall() { - uniffi_loro_fn_method_lorolist_get_deep_value(self.uniffiClonePointer(),$0 +open func getDeepValue() -> LoroValue { + return try! FfiConverterTypeLoroValue.lift(try! rustCall() { + uniffi_loro_fn_method_lorolist_get_deep_value(self.uniffiClonePointer(),$0 + ) +}) +} + + /** + * Get the ID of the list item at the given position. + */ +open func getIdAt(pos: UInt32) -> Id? { + return try! FfiConverterOptionTypeID.lift(try! rustCall() { + uniffi_loro_fn_method_lorolist_get_id_at(self.uniffiClonePointer(), + FfiConverterUInt32.lower(pos),$0 ) }) } @@ -3183,6 +3545,16 @@ open func isAttached() -> Bool { uniffi_loro_fn_method_lorolist_is_attached(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Whether the container is deleted. + */ +open func isDeleted() -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_lorolist_is_deleted(self.uniffiClonePointer(),$0 + ) +}) } open func isEmpty() -> Bool { @@ -3216,6 +3588,19 @@ open func push(v: LoroValueLike)throws {try rustCallWithError(FfiConverterTypeL } } + /** + * Converts the LoroList to a Vec of LoroValue. + * + * This method unwraps the internal Arc and clones the data if necessary, + * returning a Vec containing all the elements of the LoroList as LoroValue. + */ +open func toVec() -> [LoroValue] { + return try! FfiConverterSequenceTypeLoroValue.lift(try! rustCall() { + uniffi_loro_fn_method_lorolist_to_vec(self.uniffiClonePointer(),$0 + ) +}) +} + } @@ -3266,6 +3651,11 @@ public func FfiConverterTypeLoroList_lower(_ value: LoroList) -> UnsafeMutableRa public protocol LoroMapProtocol : AnyObject { + /** + * Delete all key-value pairs in the map. + */ + func clear() throws + /** * Delete a key-value pair from the map. */ @@ -3283,6 +3673,11 @@ public protocol LoroMapProtocol : AnyObject { */ func getDeepValue() -> LoroValue + /** + * Get the peer id of the last editor on the given entry + */ + func getLastEditor(key: String) -> UInt64? + /** * Get the shallow value of the map. * @@ -3317,16 +3712,31 @@ public protocol LoroMapProtocol : AnyObject { */ func isAttached() -> Bool + /** + * Whether the container is deleted. + */ + func isDeleted() -> Bool + /** * Whether the map is empty. */ func isEmpty() -> Bool + /** + * Get the keys of the map. + */ + func keys() -> [String] + /** * Get the length of the map. */ func len() -> UInt32 + /** + * Get the values of the map. + */ + func values() -> [ValueOrContainer] + } open class LoroMap: @@ -3383,6 +3793,15 @@ public convenience init() { + /** + * Delete all key-value pairs in the map. + */ +open func clear()throws {try rustCallWithError(FfiConverterTypeLoroError.lift) { + uniffi_loro_fn_method_loromap_clear(self.uniffiClonePointer(),$0 + ) +} +} + /** * Delete a key-value pair from the map. */ @@ -3414,6 +3833,17 @@ open func getDeepValue() -> LoroValue { uniffi_loro_fn_method_loromap_get_deep_value(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Get the peer id of the last editor on the given entry + */ +open func getLastEditor(key: String) -> UInt64? { + return try! FfiConverterOptionUInt64.lift(try! rustCall() { + uniffi_loro_fn_method_loromap_get_last_editor(self.uniffiClonePointer(), + FfiConverterString.lower(key),$0 + ) +}) } /** @@ -3511,6 +3941,16 @@ open func isAttached() -> Bool { uniffi_loro_fn_method_loromap_is_attached(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Whether the container is deleted. + */ +open func isDeleted() -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_loromap_is_deleted(self.uniffiClonePointer(),$0 + ) +}) } /** @@ -3521,6 +3961,16 @@ open func isEmpty() -> Bool { uniffi_loro_fn_method_loromap_is_empty(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Get the keys of the map. + */ +open func keys() -> [String] { + return try! FfiConverterSequenceString.lift(try! rustCall() { + uniffi_loro_fn_method_loromap_keys(self.uniffiClonePointer(),$0 + ) +}) } /** @@ -3533,6 +3983,16 @@ open func len() -> UInt32 { }) } + /** + * Get the values of the map. + */ +open func values() -> [ValueOrContainer] { + return try! FfiConverterSequenceTypeValueOrContainer.lift(try! rustCall() { + uniffi_loro_fn_method_loromap_values(self.uniffiClonePointer(),$0 + ) +}) +} + } @@ -3583,6 +4043,11 @@ public func FfiConverterTypeLoroMap_lower(_ value: LoroMap) -> UnsafeMutableRawP public protocol LoroMovableListProtocol : AnyObject { + /** + * Delete all elements in the list. + */ + func clear() throws + /** * Delete values at the given position. */ @@ -3593,6 +4058,8 @@ public protocol LoroMovableListProtocol : AnyObject { */ func get(index: UInt32) -> ValueOrContainer? + func getCreatorAt(pos: UInt32) -> UInt64? + /** * Get the cursor at the given position. * @@ -3615,6 +4082,16 @@ public protocol LoroMovableListProtocol : AnyObject { */ func getDeepValue() -> LoroValue + /** + * Get the last editor of the list item at the given position. + */ + func getLastEditorAt(pos: UInt32) -> UInt64? + + /** + * Get the last mover of the list item at the given position. + */ + func getLastMoverAt(pos: UInt32) -> UInt64? + /** * Get the shallow value of the container. * @@ -3652,6 +4129,11 @@ public protocol LoroMovableListProtocol : AnyObject { */ func isAttached() -> Bool + /** + * Whether the container is deleted. + */ + func isDeleted() -> Bool + func isEmpty() -> Bool func len() -> UInt32 @@ -3685,6 +4167,15 @@ public protocol LoroMovableListProtocol : AnyObject { func setTreeContainer(pos: UInt32, child: LoroTree) throws -> LoroTree + /** + * Get the elements of the list as a vector of LoroValues. + * + * This method returns a vector containing all the elements in the list as LoroValues. + * It provides a convenient way to access the entire contents of the LoroMovableList + * as a standard Rust vector. + */ + func toVec() -> [LoroValue] + } open class LoroMovableList: @@ -3741,6 +4232,15 @@ public convenience init() { + /** + * Delete all elements in the list. + */ +open func clear()throws {try rustCallWithError(FfiConverterTypeLoroError.lift) { + uniffi_loro_fn_method_loromovablelist_clear(self.uniffiClonePointer(),$0 + ) +} +} + /** * Delete values at the given position. */ @@ -3761,6 +4261,14 @@ open func get(index: UInt32) -> ValueOrContainer? { FfiConverterUInt32.lower(index),$0 ) }) +} + +open func getCreatorAt(pos: UInt32) -> UInt64? { + return try! FfiConverterOptionUInt64.lift(try! rustCall() { + uniffi_loro_fn_method_loromovablelist_get_creator_at(self.uniffiClonePointer(), + FfiConverterUInt32.lower(pos),$0 + ) +}) } /** @@ -3795,6 +4303,28 @@ open func getDeepValue() -> LoroValue { uniffi_loro_fn_method_loromovablelist_get_deep_value(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Get the last editor of the list item at the given position. + */ +open func getLastEditorAt(pos: UInt32) -> UInt64? { + return try! FfiConverterOptionUInt64.lift(try! rustCall() { + uniffi_loro_fn_method_loromovablelist_get_last_editor_at(self.uniffiClonePointer(), + FfiConverterUInt32.lower(pos),$0 + ) +}) +} + + /** + * Get the last mover of the list item at the given position. + */ +open func getLastMoverAt(pos: UInt32) -> UInt64? { + return try! FfiConverterOptionUInt64.lift(try! rustCall() { + uniffi_loro_fn_method_loromovablelist_get_last_mover_at(self.uniffiClonePointer(), + FfiConverterUInt32.lower(pos),$0 + ) +}) } /** @@ -3895,6 +4425,16 @@ open func isAttached() -> Bool { uniffi_loro_fn_method_loromovablelist_is_attached(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Whether the container is deleted. + */ +open func isDeleted() -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_loromovablelist_is_deleted(self.uniffiClonePointer(),$0 + ) +}) } open func isEmpty() -> Bool { @@ -4004,6 +4544,20 @@ open func setTreeContainer(pos: UInt32, child: LoroTree)throws -> LoroTree { }) } + /** + * Get the elements of the list as a vector of LoroValues. + * + * This method returns a vector containing all the elements in the list as LoroValues. + * It provides a convenient way to access the entire contents of the LoroMovableList + * as a standard Rust vector. + */ +open func toVec() -> [LoroValue] { + return try! FfiConverterSequenceTypeLoroValue.lift(try! rustCall() { + uniffi_loro_fn_method_loromovablelist_to_vec(self.uniffiClonePointer(),$0 + ) +}) +} + } @@ -4065,7 +4619,7 @@ public protocol LoroTextProtocol : AnyObject { func deleteUtf8(pos: UInt32, len: UInt32) throws /** - * Get the cursor at the given position. + * Get the cursor at the given position in the given Unicode position.. * * Using "index" to denote cursor positions can be unstable, as positions may * shift with document edits. To reliably represent a position or range within @@ -4081,6 +4635,11 @@ public protocol LoroTextProtocol : AnyObject { */ func getCursor(pos: UInt32, side: Side) -> Cursor? + /** + * Get the editor of the text at the given position. + */ + func getEditorAtUnicodePos(pos: UInt32) -> UInt64? + /** * Get the [ContainerID] of the text container. */ @@ -4104,6 +4663,11 @@ public protocol LoroTextProtocol : AnyObject { */ func isAttached() -> Bool + /** + * Whether the container is deleted. + */ + func isDeleted() -> Bool + /** * Whether the text container is empty. */ @@ -4142,6 +4706,11 @@ public protocol LoroTextProtocol : AnyObject { */ func mark(from: UInt32, to: UInt32, key: String, value: LoroValueLike) throws + /** + * Push a string to the end of the text container. + */ + func pushStr(s: String) throws + /** * Get a string slice at the given Unicode range */ @@ -4184,8 +4753,21 @@ public protocol LoroTextProtocol : AnyObject { /** * Update the current text based on the provided text. + * + * It will calculate the minimal difference and apply it to the current text. + * It uses Myers' diff algorithm to compute the optimal difference. + * + * This could take a long time for large texts (e.g. > 50_000 characters). + * In that case, you should use `updateByLine` instead. + */ + func update(s: String, options: UpdateOptions) throws + + /** + * Update the current text based on the provided text. + * + * This update calculation is line-based, which will be more efficient but less precise. */ - func update(s: String) + func updateByLine(s: String, options: UpdateOptions) throws } @@ -4266,7 +4848,7 @@ open func deleteUtf8(pos: UInt32, len: UInt32)throws {try rustCallWithError(Ffi } /** - * Get the cursor at the given position. + * Get the cursor at the given position in the given Unicode position.. * * Using "index" to denote cursor positions can be unstable, as positions may * shift with document edits. To reliably represent a position or range within @@ -4287,6 +4869,17 @@ open func getCursor(pos: UInt32, side: Side) -> Cursor? { FfiConverterTypeSide.lower(side),$0 ) }) +} + + /** + * Get the editor of the text at the given position. + */ +open func getEditorAtUnicodePos(pos: UInt32) -> UInt64? { + return try! FfiConverterOptionUInt64.lift(try! rustCall() { + uniffi_loro_fn_method_lorotext_get_editor_at_unicode_pos(self.uniffiClonePointer(), + FfiConverterUInt32.lower(pos),$0 + ) +}) } /** @@ -4332,6 +4925,16 @@ open func isAttached() -> Bool { uniffi_loro_fn_method_lorotext_is_attached(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Whether the container is deleted. + */ +open func isDeleted() -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_lorotext_is_deleted(self.uniffiClonePointer(),$0 + ) +}) } /** @@ -4398,6 +5001,16 @@ open func mark(from: UInt32, to: UInt32, key: String, value: LoroValueLike)throw FfiConverterTypeLoroValueLike.lower(value),$0 ) } +} + + /** + * Push a string to the end of the text container. + */ +open func pushStr(s: String)throws {try rustCallWithError(FfiConverterTypeLoroError.lift) { + uniffi_loro_fn_method_lorotext_push_str(self.uniffiClonePointer(), + FfiConverterString.lower(s),$0 + ) +} } /** @@ -4474,10 +5087,30 @@ open func unmark(from: UInt32, to: UInt32, key: String)throws {try rustCallWith /** * Update the current text based on the provided text. + * + * It will calculate the minimal difference and apply it to the current text. + * It uses Myers' diff algorithm to compute the optimal difference. + * + * This could take a long time for large texts (e.g. > 50_000 characters). + * In that case, you should use `updateByLine` instead. */ -open func update(s: String) {try! rustCall() { +open func update(s: String, options: UpdateOptions)throws {try rustCallWithError(FfiConverterTypeUpdateTimeoutError.lift) { uniffi_loro_fn_method_lorotext_update(self.uniffiClonePointer(), - FfiConverterString.lower(s),$0 + FfiConverterString.lower(s), + FfiConverterTypeUpdateOptions.lower(options),$0 + ) +} +} + + /** + * Update the current text based on the provided text. + * + * This update calculation is line-based, which will be more efficient but less precise. + */ +open func updateByLine(s: String, options: UpdateOptions)throws {try rustCallWithError(FfiConverterTypeUpdateTimeoutError.lift) { + uniffi_loro_fn_method_lorotext_update_by_line(self.uniffiClonePointer(), + FfiConverterString.lower(s), + FfiConverterTypeUpdateOptions.lower(options),$0 ) } } @@ -4574,8 +5207,11 @@ public protocol LoroTreeProtocol : AnyObject { func delete(target: TreeId) throws /** - * Disable the fractional index generation for Tree Position when - * you don't need the Tree's siblings to be sorted. The fractional index will be always default. + * Disable the fractional index generation when you don't need the Tree's siblings to be sorted. + * The fractional index will always be set to the same default value 0. + * + * After calling this, you cannot use `tree.moveTo()`, `tree.moveBefore()`, `tree.moveAfter()`, + * and `tree.createAt()`. */ func disableFractionalIndex() @@ -4595,6 +5231,11 @@ public protocol LoroTreeProtocol : AnyObject { */ func fractionalIndex(target: TreeId) -> String? + /** + * Get the last move id of the target node. + */ + func getLastMoveId(target: TreeId) -> Id? + /** * Get the associated metadata map handler of a tree node. */ @@ -4626,6 +5267,11 @@ public protocol LoroTreeProtocol : AnyObject { */ func isAttached() -> Bool + /** + * Whether the container is deleted. + */ + func isDeleted() -> Bool + /** * Whether the fractional index is enabled. */ @@ -4814,8 +5460,11 @@ open func delete(target: TreeId)throws {try rustCallWithError(FfiConverterTypeL } /** - * Disable the fractional index generation for Tree Position when - * you don't need the Tree's siblings to be sorted. The fractional index will be always default. + * Disable the fractional index generation when you don't need the Tree's siblings to be sorted. + * The fractional index will always be set to the same default value 0. + * + * After calling this, you cannot use `tree.moveTo()`, `tree.moveBefore()`, `tree.moveAfter()`, + * and `tree.createAt()`. */ open func disableFractionalIndex() {try! rustCall() { uniffi_loro_fn_method_lorotree_disable_fractional_index(self.uniffiClonePointer(),$0 @@ -4848,6 +5497,17 @@ open func fractionalIndex(target: TreeId) -> String? { FfiConverterTypeTreeID.lower(target),$0 ) }) +} + + /** + * Get the last move id of the target node. + */ +open func getLastMoveId(target: TreeId) -> Id? { + return try! FfiConverterOptionTypeID.lift(try! rustCall() { + uniffi_loro_fn_method_lorotree_get_last_move_id(self.uniffiClonePointer(), + FfiConverterTypeTreeID.lower(target),$0 + ) +}) } /** @@ -4905,6 +5565,16 @@ open func isAttached() -> Bool { uniffi_loro_fn_method_lorotree_is_attached(self.uniffiClonePointer(),$0 ) }) +} + + /** + * Whether the container is deleted. + */ +open func isDeleted() -> Bool { + return try! FfiConverterBool.lift(try! rustCall() { + uniffi_loro_fn_method_lorotree_is_deleted(self.uniffiClonePointer(),$0 + ) +}) } /** @@ -5951,19 +6621,7 @@ open class Subscription: public func uniffiClonePointer() -> UnsafeMutableRawPointer { return try! rustCall { uniffi_loro_fn_clone_subscription(self.pointer, $0) } } - /** - * Creates a new subscription with a callback that gets invoked when - * this subscription is dropped. - */ -public convenience init(unsubscribe: Unsubscriber) { - let pointer = - try! rustCall() { - uniffi_loro_fn_constructor_subscription_new( - FfiConverterTypeUnsubscriber.lower(unsubscribe),$0 - ) -} - self.init(unsafeFromRawPointer: pointer) -} + // No primary constructor declared for this class. deinit { guard let pointer = pointer else { @@ -7436,6 +8094,45 @@ public func FfiConverterTypeDiffEvent_lower(_ value: DiffEvent) -> RustBuffer { } +public struct FrontiersOrId { + public var frontiers: Frontiers? + public var id: Id? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(frontiers: Frontiers?, id: Id?) { + self.frontiers = frontiers + self.id = id + } +} + + + +public struct FfiConverterTypeFrontiersOrID: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FrontiersOrId { + return + try FrontiersOrId( + frontiers: FfiConverterOptionTypeFrontiers.read(from: &buf), + id: FfiConverterOptionTypeID.read(from: &buf) + ) + } + + public static func write(_ value: FrontiersOrId, into buf: inout [UInt8]) { + FfiConverterOptionTypeFrontiers.write(value.frontiers, into: &buf) + FfiConverterOptionTypeID.write(value.id, into: &buf) + } +} + + +public func FfiConverterTypeFrontiersOrID_lift(_ buf: RustBuffer) throws -> FrontiersOrId { + return try FfiConverterTypeFrontiersOrID.lift(buf) +} + +public func FfiConverterTypeFrontiersOrID_lower(_ value: FrontiersOrId) -> RustBuffer { + return FfiConverterTypeFrontiersOrID.lower(value) +} + + public struct Id { public var peer: UInt64 public var counter: Int32 @@ -7628,7 +8325,7 @@ public struct ImportBlobMetadata { public var startFrontiers: Frontiers public var endTimestamp: Int64 public var changeNum: UInt32 - public var isSnapshot: Bool + public var mode: String // Default memberwise initializers are never public by default, so we // declare one manually. @@ -7646,14 +8343,14 @@ public struct ImportBlobMetadata { * Import blob includes all the ops from `partial_start_vv` to `partial_end_vv`. * However, it does not constitute a complete version vector, as it only contains counters * from peers included within the import blob. - */partialEndVv: VersionVector, startTimestamp: Int64, startFrontiers: Frontiers, endTimestamp: Int64, changeNum: UInt32, isSnapshot: Bool) { + */partialEndVv: VersionVector, startTimestamp: Int64, startFrontiers: Frontiers, endTimestamp: Int64, changeNum: UInt32, mode: String) { self.partialStartVv = partialStartVv self.partialEndVv = partialEndVv self.startTimestamp = startTimestamp self.startFrontiers = startFrontiers self.endTimestamp = endTimestamp self.changeNum = changeNum - self.isSnapshot = isSnapshot + self.mode = mode } } @@ -7669,7 +8366,7 @@ public struct FfiConverterTypeImportBlobMetadata: FfiConverterRustBuffer { startFrontiers: FfiConverterTypeFrontiers.read(from: &buf), endTimestamp: FfiConverterInt64.read(from: &buf), changeNum: FfiConverterUInt32.read(from: &buf), - isSnapshot: FfiConverterBool.read(from: &buf) + mode: FfiConverterString.read(from: &buf) ) } @@ -7680,7 +8377,7 @@ public struct FfiConverterTypeImportBlobMetadata: FfiConverterRustBuffer { FfiConverterTypeFrontiers.write(value.startFrontiers, into: &buf) FfiConverterInt64.write(value.endTimestamp, into: &buf) FfiConverterUInt32.write(value.changeNum, into: &buf) - FfiConverterBool.write(value.isSnapshot, into: &buf) + FfiConverterString.write(value.mode, into: &buf) } } @@ -8159,42 +8856,99 @@ public func FfiConverterTypeTreeID_lower(_ value: TreeId) -> RustBuffer { } -public struct UndoItemMeta { - public var value: LoroValue - public var cursors: [CursorWithPos] +public struct UndoItemMeta { + public var value: LoroValue + public var cursors: [CursorWithPos] + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(value: LoroValue, cursors: [CursorWithPos]) { + self.value = value + self.cursors = cursors + } +} + + + +public struct FfiConverterTypeUndoItemMeta: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UndoItemMeta { + return + try UndoItemMeta( + value: FfiConverterTypeLoroValue.read(from: &buf), + cursors: FfiConverterSequenceTypeCursorWithPos.read(from: &buf) + ) + } + + public static func write(_ value: UndoItemMeta, into buf: inout [UInt8]) { + FfiConverterTypeLoroValue.write(value.value, into: &buf) + FfiConverterSequenceTypeCursorWithPos.write(value.cursors, into: &buf) + } +} + + +public func FfiConverterTypeUndoItemMeta_lift(_ buf: RustBuffer) throws -> UndoItemMeta { + return try FfiConverterTypeUndoItemMeta.lift(buf) +} + +public func FfiConverterTypeUndoItemMeta_lower(_ value: UndoItemMeta) -> RustBuffer { + return FfiConverterTypeUndoItemMeta.lower(value) +} + + +public struct UpdateOptions { + public var timeoutMs: Double? + public var useRefinedDiff: Bool // Default memberwise initializers are never public by default, so we // declare one manually. - public init(value: LoroValue, cursors: [CursorWithPos]) { - self.value = value - self.cursors = cursors + public init(timeoutMs: Double?, useRefinedDiff: Bool) { + self.timeoutMs = timeoutMs + self.useRefinedDiff = useRefinedDiff } } -public struct FfiConverterTypeUndoItemMeta: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UndoItemMeta { +extension UpdateOptions: Equatable, Hashable { + public static func ==(lhs: UpdateOptions, rhs: UpdateOptions) -> Bool { + if lhs.timeoutMs != rhs.timeoutMs { + return false + } + if lhs.useRefinedDiff != rhs.useRefinedDiff { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(timeoutMs) + hasher.combine(useRefinedDiff) + } +} + + +public struct FfiConverterTypeUpdateOptions: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UpdateOptions { return - try UndoItemMeta( - value: FfiConverterTypeLoroValue.read(from: &buf), - cursors: FfiConverterSequenceTypeCursorWithPos.read(from: &buf) + try UpdateOptions( + timeoutMs: FfiConverterOptionDouble.read(from: &buf), + useRefinedDiff: FfiConverterBool.read(from: &buf) ) } - public static func write(_ value: UndoItemMeta, into buf: inout [UInt8]) { - FfiConverterTypeLoroValue.write(value.value, into: &buf) - FfiConverterSequenceTypeCursorWithPos.write(value.cursors, into: &buf) + public static func write(_ value: UpdateOptions, into buf: inout [UInt8]) { + FfiConverterOptionDouble.write(value.timeoutMs, into: &buf) + FfiConverterBool.write(value.useRefinedDiff, into: &buf) } } -public func FfiConverterTypeUndoItemMeta_lift(_ buf: RustBuffer) throws -> UndoItemMeta { - return try FfiConverterTypeUndoItemMeta.lift(buf) +public func FfiConverterTypeUpdateOptions_lift(_ buf: RustBuffer) throws -> UpdateOptions { + return try FfiConverterTypeUpdateOptions.lift(buf) } -public func FfiConverterTypeUndoItemMeta_lower(_ value: UndoItemMeta) -> RustBuffer { - return FfiConverterTypeUndoItemMeta.lower(value) +public func FfiConverterTypeUpdateOptions_lower(_ value: UpdateOptions) -> RustBuffer { + return FfiConverterTypeUpdateOptions.lower(value) } @@ -8334,6 +9088,66 @@ extension CannotFindRelativePosition: Foundation.LocalizedError { } } + +public enum ChangeTravelError { + + + + case TargetIdNotFound(message: String) + + case TargetVersionNotIncluded(message: String) + +} + + +public struct FfiConverterTypeChangeTravelError: FfiConverterRustBuffer { + typealias SwiftType = ChangeTravelError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChangeTravelError { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .TargetIdNotFound( + message: try FfiConverterString.read(from: &buf) + ) + + case 2: return .TargetVersionNotIncluded( + message: try FfiConverterString.read(from: &buf) + ) + + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: ChangeTravelError, into buf: inout [UInt8]) { + switch value { + + + + + case .TargetIdNotFound(_ /* message is ignored*/): + writeInt(&buf, Int32(1)) + case .TargetVersionNotIncluded(_ /* message is ignored*/): + writeInt(&buf, Int32(2)) + + + } + } +} + + +extension ChangeTravelError: Equatable, Hashable {} + +extension ChangeTravelError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -9870,6 +10684,58 @@ extension UndoOrRedo: Equatable, Hashable {} + +public enum UpdateTimeoutError { + + + + case Timeout(message: String) + +} + + +public struct FfiConverterTypeUpdateTimeoutError: FfiConverterRustBuffer { + typealias SwiftType = UpdateTimeoutError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UpdateTimeoutError { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .Timeout( + message: try FfiConverterString.read(from: &buf) + ) + + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: UpdateTimeoutError, into buf: inout [UInt8]) { + switch value { + + + + + case .Timeout(_ /* message is ignored*/): + writeInt(&buf, Int32(1)) + + + } + } +} + + +extension UpdateTimeoutError: Equatable, Hashable {} + +extension UpdateTimeoutError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + fileprivate struct FfiConverterOptionUInt32: FfiConverterRustBuffer { typealias SwiftType = UInt32? @@ -9912,6 +10778,27 @@ fileprivate struct FfiConverterOptionInt32: FfiConverterRustBuffer { } } +fileprivate struct FfiConverterOptionUInt64: FfiConverterRustBuffer { + typealias SwiftType = UInt64? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterUInt64.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterUInt64.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + fileprivate struct FfiConverterOptionInt64: FfiConverterRustBuffer { typealias SwiftType = Int64? @@ -9933,6 +10820,27 @@ fileprivate struct FfiConverterOptionInt64: FfiConverterRustBuffer { } } +fileprivate struct FfiConverterOptionDouble: FfiConverterRustBuffer { + typealias SwiftType = Double? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterDouble.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterDouble.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer { typealias SwiftType = String? @@ -10459,6 +11367,28 @@ fileprivate struct FfiConverterSequenceUInt64: FfiConverterRustBuffer { } } +fileprivate struct FfiConverterSequenceString: FfiConverterRustBuffer { + typealias SwiftType = [String] + + public static func write(_ value: [String], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterString.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String] { + let len: Int32 = try readInt(&buf) + var seq = [String]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterString.read(from: &buf)) + } + return seq + } +} + fileprivate struct FfiConverterSequenceData: FfiConverterRustBuffer { typealias SwiftType = [Data] @@ -10679,6 +11609,28 @@ fileprivate struct FfiConverterSequenceTypeTreeID: FfiConverterRustBuffer { } } +fileprivate struct FfiConverterSequenceTypeContainerID: FfiConverterRustBuffer { + typealias SwiftType = [ContainerId] + + public static func write(_ value: [ContainerId], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeContainerID.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [ContainerId] { + let len: Int32 = try readInt(&buf) + var seq = [ContainerId]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeContainerID.read(from: &buf)) + } + return seq + } +} + fileprivate struct FfiConverterSequenceTypeIndex: FfiConverterRustBuffer { typealias SwiftType = [Index] @@ -10858,6 +11810,17 @@ fileprivate struct FfiConverterDictionaryStringOptionTypeValueOrContainer: FfiCo return dict } } +/** + * Decodes the metadata for an imported blob from the provided bytes. + */ +public func decodeImportBlobMeta(bytes: Data, checkChecksum: Bool)throws -> ImportBlobMetadata { + return try FfiConverterTypeImportBlobMetadata.lift(try rustCallWithError(FfiConverterTypeLoroError.lift) { + uniffi_loro_fn_func_decode_import_blob_meta( + FfiConverterData.lower(bytes), + FfiConverterBool.lower(checkChecksum),$0 + ) +}) +} private enum InitializationResult { case ok @@ -10874,6 +11837,9 @@ private var initializationResult: InitializationResult = { if bindings_contract_version != scaffolding_contract_version { return InitializationResult.contractVersionMismatch } + if (uniffi_loro_checksum_func_decode_import_blob_meta() != 2769) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_awareness_apply() != 41900) { return InitializationResult.apiChecksumMismatch } @@ -10898,6 +11864,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_awareness_set_local_state() != 517) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_changeancestorstraveler_travel() != 17239) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_configure_fork() != 57176) { return InitializationResult.apiChecksumMismatch } @@ -10943,6 +11912,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorocounter_increment() != 47367) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorocounter_is_deleted() != 12079) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_attach() != 7252) { return InitializationResult.apiChecksumMismatch } @@ -10973,9 +11945,6 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_config_text_style() != 52393) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorodoc_decode_import_blob_meta() != 12658) { - return InitializationResult.apiChecksumMismatch - } if (uniffi_loro_checksum_method_lorodoc_detach() != 61399) { return InitializationResult.apiChecksumMismatch } @@ -11000,6 +11969,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_fork() != 45665) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_fork_at() != 40377) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_free_diff_calculator() != 32937) { return InitializationResult.apiChecksumMismatch } @@ -11018,6 +11990,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_get_change() != 17896) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_get_changed_containers_in() != 52454) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_get_counter() != 12597) { return InitializationResult.apiChecksumMismatch } @@ -11042,6 +12017,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_get_path_to_container() != 62623) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_get_pending_txn_len() != 15050) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_get_text() != 56069) { return InitializationResult.apiChecksumMismatch } @@ -11069,6 +12047,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_is_detached() != 30909) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_is_shallow() != 53044) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_jsonpath() != 15996) { return InitializationResult.apiChecksumMismatch } @@ -11081,6 +12062,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_log_estimate_size() != 19429) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_minimize_frontiers() != 39579) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_oplog_frontiers() != 49043) { return InitializationResult.apiChecksumMismatch } @@ -11120,9 +12104,15 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorodoc_subscribe_root() != 16564) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorodoc_travel_change_ancestors() != 39918) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorodoc_vv_to_frontiers() != 47960) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorolist_clear() != 61243) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorolist_delete() != 40414) { return InitializationResult.apiChecksumMismatch } @@ -11135,6 +12125,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorolist_get_deep_value() != 9355) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorolist_get_id_at() != 63640) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorolist_get_value() != 14384) { return InitializationResult.apiChecksumMismatch } @@ -11165,6 +12158,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorolist_is_attached() != 60548) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorolist_is_deleted() != 44383) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorolist_is_empty() != 13469) { return InitializationResult.apiChecksumMismatch } @@ -11177,6 +12173,12 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorolist_push() != 32091) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorolist_to_vec() != 34199) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_loromap_clear() != 22445) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_loromap_delete() != 54675) { return InitializationResult.apiChecksumMismatch } @@ -11186,6 +12188,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_loromap_get_deep_value() != 23748) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_loromap_get_last_editor() != 54864) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_loromap_get_value() != 7268) { return InitializationResult.apiChecksumMismatch } @@ -11216,24 +12221,45 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_loromap_is_attached() != 6283) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_loromap_is_deleted() != 20980) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_loromap_is_empty() != 38768) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_loromap_keys() != 11621) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_loromap_len() != 38088) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_loromap_values() != 46629) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_loromovablelist_clear() != 17252) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_loromovablelist_delete() != 51786) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_loromovablelist_get() != 10599) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_loromovablelist_get_creator_at() != 21542) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_loromovablelist_get_cursor() != 118) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_loromovablelist_get_deep_value() != 18542) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_loromovablelist_get_last_editor_at() != 8998) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_loromovablelist_get_last_mover_at() != 26603) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_loromovablelist_get_value() != 50843) { return InitializationResult.apiChecksumMismatch } @@ -11264,6 +12290,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_loromovablelist_is_attached() != 50724) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_loromovablelist_is_deleted() != 37438) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_loromovablelist_is_empty() != 44651) { return InitializationResult.apiChecksumMismatch } @@ -11300,6 +12329,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_loromovablelist_set_tree_container() != 8298) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_loromovablelist_to_vec() != 28826) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorotext_delete() != 47933) { return InitializationResult.apiChecksumMismatch } @@ -11309,6 +12341,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorotext_get_cursor() != 57876) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorotext_get_editor_at_unicode_pos() != 24596) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorotext_id() != 30925) { return InitializationResult.apiChecksumMismatch } @@ -11321,6 +12356,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorotext_is_attached() != 45378) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorotext_is_deleted() != 31871) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorotext_is_empty() != 7961) { return InitializationResult.apiChecksumMismatch } @@ -11336,6 +12374,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorotext_mark() != 42690) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorotext_push_str() != 2374) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorotext_slice() != 43152) { return InitializationResult.apiChecksumMismatch } @@ -11351,7 +12392,10 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorotext_unmark() != 14351) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_method_lorotext_update() != 55624) { + if (uniffi_loro_checksum_method_lorotext_update() != 16538) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_loro_checksum_method_lorotext_update_by_line() != 29301) { return InitializationResult.apiChecksumMismatch } if (uniffi_loro_checksum_method_lorotree_children() != 4750) { @@ -11381,6 +12425,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorotree_fractional_index() != 51036) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorotree_get_last_move_id() != 12557) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorotree_get_meta() != 3068) { return InitializationResult.apiChecksumMismatch } @@ -11396,6 +12443,9 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_method_lorotree_is_attached() != 37303) { return InitializationResult.apiChecksumMismatch } + if (uniffi_loro_checksum_method_lorotree_is_deleted() != 8644) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_loro_checksum_method_lorotree_is_fractional_index_enabled() != 19364) { return InitializationResult.apiChecksumMismatch } @@ -11600,9 +12650,6 @@ private var initializationResult: InitializationResult = { if (uniffi_loro_checksum_constructor_styleconfigmap_new() != 23831) { return InitializationResult.apiChecksumMismatch } - if (uniffi_loro_checksum_constructor_subscription_new() != 51704) { - return InitializationResult.apiChecksumMismatch - } if (uniffi_loro_checksum_constructor_undomanager_new() != 35328) { return InitializationResult.apiChecksumMismatch } @@ -11613,6 +12660,7 @@ private var initializationResult: InitializationResult = { return InitializationResult.apiChecksumMismatch } + uniffiCallbackInitChangeAncestorsTraveler() uniffiCallbackInitContainerIdLike() uniffiCallbackInitLocalUpdateCallback() uniffiCallbackInitLoroValueLike() diff --git a/loro-rs/Cargo.lock b/loro-rs/Cargo.lock index 0bc7d98..41fee07 100644 --- a/loro-rs/Cargo.lock +++ b/loro-rs/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ahash" @@ -186,12 +186,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "bitmaps" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d084b0137aaa901caf9f1e8b21daa6aa24d41cd806e111335541eff9683bd6" - [[package]] name = "byteorder" version = "1.5.0" @@ -550,7 +544,7 @@ version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" dependencies = [ - "bitmaps 2.1.0", + "bitmaps", "rand_core", "rand_xoshiro", "serde", @@ -559,28 +553,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "imbl" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc3be8d8cd36f33a46b1849f31f837c44d9fa87223baee3b4bd96b8f11df81eb" -dependencies = [ - "bitmaps 3.2.1", - "imbl-sized-chunks", - "rand_core", - "rand_xoshiro", - "version_check", -] - -[[package]] -name = "imbl-sized-chunks" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "144006fb58ed787dcae3f54575ff4349755b00ccc99f4b4873860b654be1ed63" -dependencies = [ - "bitmaps 3.2.1", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -641,9 +613,10 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "loro" -version = "0.16.12" +version = "1.1.0" dependencies = [ "enum-as-inner 0.6.0", + "fxhash", "generic-btree", "loro-common", "loro-delta", @@ -654,7 +627,7 @@ dependencies = [ [[package]] name = "loro-common" -version = "0.16.12" +version = "1.1.0" dependencies = [ "arbitrary", "enum-as-inner 0.6.0", @@ -665,24 +638,22 @@ dependencies = [ "serde", "serde_columnar", "serde_json", - "string_cache", "thiserror", ] [[package]] name = "loro-delta" -version = "0.16.12" +version = "1.1.0" dependencies = [ "arrayvec", "enum-as-inner 0.5.1", "generic-btree", "heapless 0.8.0", - "tracing", ] [[package]] name = "loro-ffi" -version = "0.16.2" +version = "1.1.3" dependencies = [ "loro", "serde_json", @@ -690,7 +661,7 @@ dependencies = [ [[package]] name = "loro-internal" -version = "0.16.12" +version = "1.1.0" dependencies = [ "append-only-bytes", "arref", @@ -713,7 +684,6 @@ dependencies = [ "md5", "nonmax", "num", - "num-derive", "num-traits", "once_cell", "postcard", @@ -730,7 +700,7 @@ dependencies = [ [[package]] name = "loro-kv-store" -version = "0.16.2" +version = "1.1.0" dependencies = [ "bytes", "ensure-cov", @@ -745,12 +715,9 @@ dependencies = [ [[package]] name = "loro-rle" -version = "0.16.12" +version = "1.1.0" dependencies = [ "append-only-bytes", - "arref", - "enum-as-inner 0.6.0", - "fxhash", "num", "smallvec", ] @@ -771,13 +738,11 @@ checksum = "3f3d053a135388e6b1df14e8af1212af5064746e9b87a06a345a7a779ee9695a" [[package]] name = "loro_fractional_index" -version = "0.16.12" +version = "1.1.0" dependencies = [ - "imbl", "once_cell", "rand", "serde", - "smallvec", ] [[package]] @@ -823,12 +788,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - [[package]] name = "nom" version = "7.1.3" @@ -878,17 +837,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "num-integer" version = "0.1.46" @@ -964,15 +912,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1006,12 +945,6 @@ dependencies = [ "zerocopy 0.6.6", ] -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - [[package]] name = "pretty_assertions" version = "1.4.1" @@ -1219,7 +1152,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" dependencies = [ - "bitmaps 2.1.0", + "bitmaps", "typenum", ] @@ -1259,20 +1192,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared", - "precomputed-hash", - "serde", -] - [[package]] name = "strsim" version = "0.11.1" diff --git a/loro-rs/src/loro.udl b/loro-rs/src/loro.udl index d0e1e5e..2dc8ec4 100644 --- a/loro-rs/src/loro.udl +++ b/loro-rs/src/loro.udl @@ -1,5 +1,7 @@ namespace loro{ - + /// Decodes the metadata for an imported blob from the provided bytes. + [Throws=LoroError] + ImportBlobMetadata decode_import_blob_meta([ByRef] bytes bytes, boolean check_checksum); }; // ============= Traits ============= @@ -59,6 +61,11 @@ interface OnPop{ // JsonSchema into_json_schema(); // }; +[Trait, WithForeign] +interface ChangeAncestorsTraveler{ + boolean travel(ChangeMeta change); +}; + // ============= LORO DOC ============= interface LoroDoc{ @@ -68,8 +75,16 @@ interface LoroDoc{ /// Duplicate the document with a different PeerID /// /// The time complexity and space complexity of this operation are both O(n), + /// + /// When called in detached mode, it will fork at the current state frontiers. + /// It will have the same effect as `fork_at(&self.state_frontiers())`. LoroDoc fork(); + /// Fork the document at the given frontiers. + /// + /// The created doc will only contain the history before the specified frontiers. + LoroDoc fork_at([ByRef] Frontiers frontiers); + /// Get the configurations of the document. Configure config(); @@ -88,10 +103,6 @@ interface LoroDoc{ /// The length of the `Change` is how many operations it contains ChangeMeta? get_change(ID id); - /// Decodes the metadata for an imported blob from the provided bytes. - [Throws=LoroError] - ImportBlobMetadata decode_import_blob_meta([ByRef] bytes bytes); - /// Set whether to record the timestamp of each change. Default is `false`. /// /// If enabled, the Unix timestamp will be recorded for each change automatically. @@ -103,7 +114,7 @@ interface LoroDoc{ /// the largest existing timestamp will be used instead. void set_record_timestamp(boolean record); - /// Set the interval of mergeable changes, in milliseconds. + /// Set the interval of mergeable changes, in seconds. /// /// If two continuous local changes are within the interval, they will be merged into one change. /// The default value is 1000 seconds. @@ -128,10 +139,10 @@ interface LoroDoc{ /// Checkout the `DocState` to a specific version. /// - /// > The document becomes detached during a `checkout` operation. - /// > Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`. - /// > In a detached state, the document is not editable, and any `import` operations will be - /// > recorded in the `OpLog` without being applied to the `DocState`. + /// The document becomes detached during a `checkout` operation. + /// Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`. + /// In a detached state, the document is not editable, and any `import` operations will be + /// recorded in the `OpLog` without being applied to the `DocState`. /// /// You should call `attach` to attach the `DocState` to the latest version of `OpLog`. [Throws=LoroError] @@ -201,8 +212,12 @@ interface LoroDoc{ /// Commit the cumulative auto commit transaction. /// /// There is a transaction behind every operation. - /// It will automatically commit when users invoke export or import. - /// The event will be sent after a transaction is committed + /// The events will be emitted after a transaction is committed. A transaction is committed when: + /// + /// - `doc.commit()` is called. + /// - `doc.export(mode)` is called. + /// - `doc.import(data)` is called. + /// - `doc.checkout(version)` is called. void commit(); void commit_with(CommitOptions options); @@ -239,6 +254,10 @@ interface LoroDoc{ /// Convert `Frontiers` into `VersionVector` VersionVector? frontiers_to_vv([ByRef] Frontiers frontiers); + /// Minimize the frontiers by removing the unnecessary entries. + // TODO: + FrontiersOrID minimize_frontiers([ByRef] Frontiers frontiers); + /// Convert `VersionVector` into `Frontiers` Frontiers vv_to_frontiers([ByRef] VersionVector vv); // with_oplog @@ -246,7 +265,7 @@ interface LoroDoc{ /// Get the `VersionVector` version of `OpLog` VersionVector oplog_vv(); - /// Get the `VersionVector` version of `OpLog` + /// Get the `VersionVector` version of `DocState` VersionVector state_vv(); /// Get the `VersionVector` of trimmed history @@ -263,10 +282,10 @@ interface LoroDoc{ /// Get the shallow value of the document. LoroValue get_value(); - /// Get the current state of the document. + /// Get the entire state of the current DocState LoroValue get_deep_value(); - /// Get the current state with container id of the doc + /// Get the entire state of the current DocState with container id LoroValue get_deep_value_with_id(); /// Get the `Frontiers` version of `OpLog` @@ -274,7 +293,7 @@ interface LoroDoc{ /// Get the `Frontiers` version of `DocState` /// - /// [Learn more about `Frontiers`]() + /// Learn more about [`Frontiers`](https://loro.dev/docs/advanced/version_deep_dive) Frontiers state_frontiers(); /// Get the PeerID @@ -282,7 +301,7 @@ interface LoroDoc{ /// Change the PeerID /// - /// NOTE: You need ot make sure there is no chance two peer have the same PeerID. + /// NOTE: You need to make sure there is no chance two peer have the same PeerID. /// If it happens, the document will be corrupted. [Throws=LoroError] void set_peer_id(u64 peer); @@ -290,13 +309,20 @@ interface LoroDoc{ /// Subscribe the events of a container. /// /// The callback will be invoked when the container is changed. - /// Returns a subscription id that can be used to unsubscribe. + /// Returns a subscription that can be used to unsubscribe. + /// + /// The events will be emitted after a transaction is committed. A transaction is committed when: + /// + /// - `doc.commit()` is called. + /// - `doc.export(mode)` is called. + /// - `doc.import(data)` is called. + /// - `doc.checkout(version)` is called. Subscription subscribe([ByRef] ContainerID container_id, Subscriber subscriber); /// Subscribe all the events. /// /// The callback will be invoked when any part of the [loro_internal::DocState] is changed. - /// Returns a subscription id that can be used to unsubscribe. + /// Returns a subscription that can be used to unsubscribe. Subscription subscribe_root(Subscriber subscriber); /// Subscribe the local update of the document. @@ -383,6 +409,41 @@ interface LoroDoc{ /// ``` [Throws=JsonPathError] sequence jsonpath([ByRef] string path); + + /// Traverses the ancestors of the Change containing the given ID, including itself. + /// + /// This method visits all ancestors in causal order, from the latest to the oldest, + /// based on their Lamport timestamps. + /// + /// # Arguments + /// + /// * `ids` - The IDs of the Change to start the traversal from. + /// * `f` - A mutable function that is called for each ancestor. It can return `ControlFlow::Break(())` to stop the traversal. + [Throws=ChangeTravelError] + void travel_change_ancestors([ByRef] sequence ids, ChangeAncestorsTraveler f); + + /// Gets container IDs modified in the given ID range. + /// + /// **NOTE:** This method will implicitly commit. + /// + /// This method can be used in conjunction with `doc.travel_change_ancestors()` to traverse + /// the history and identify all changes that affected specific containers. + /// + /// # Arguments + /// + /// * `id` - The starting ID of the change range + /// * `len` - The length of the change range to check + // TODO: + sequence get_changed_containers_in(ID id, u32 len); + + /// Check if the doc contains the full history. + boolean is_shallow(); + + /// Get the number of operations in the pending transaction. + /// + /// The pending transaction is the one that is not committed yet. It will be committed + /// after calling `doc.commit()`, `doc.export(mode)` or `doc.checkout(version)`. + u32 get_pending_txn_len(); }; dictionary ContainerPath{ @@ -445,7 +506,21 @@ interface LoroText{ u32 len_utf16(); /// Update the current text based on the provided text. - void update([ByRef] string s); + /// + /// It will calculate the minimal difference and apply it to the current text. + /// It uses Myers' diff algorithm to compute the optimal difference. + /// + /// This could take a long time for large texts (e.g. > 50_000 characters). + /// In that case, you should use `updateByLine` instead. + // TODO: + [Throws=UpdateTimeoutError] + void update([ByRef] string s, UpdateOptions options); + + /// Update the current text based on the provided text. + /// + /// This update calculation is line-based, which will be more efficient but less precise. + [Throws=UpdateTimeoutError] + void update_by_line([ByRef] string s, UpdateOptions options); /// Mark a range of text with a key-value pair. /// @@ -489,7 +564,7 @@ interface LoroText{ /// Get the text content of the text container. string to_string(); - /// Get the cursor at the given position. + /// Get the cursor at the given position in the given Unicode position.. /// /// Using "index" to denote cursor positions can be unstable, as positions may /// shift with document edits. To reliably represent a position or range within @@ -503,6 +578,16 @@ interface LoroText{ /// updates cursor info to reference only the IDs of currently present elements, /// thereby reducing the need for replay. Cursor? get_cursor(u32 pos, Side side); + + /// Whether the container is deleted. + boolean is_deleted(); + + /// Push a string to the end of the text container. + [Throws=LoroError] + void push_str([ByRef] string s); + + /// Get the editor of the text at the given position. + u64? get_editor_at_unicode_pos(u32 pos); }; interface LoroList{ @@ -571,6 +656,22 @@ interface LoroList{ LoroCounter insert_counter_container(u32 pos, LoroCounter child); Cursor? get_cursor(u32 pos, Side side); + + /// Converts the LoroList to a Vec of LoroValue. + /// + /// This method unwraps the internal Arc and clones the data if necessary, + /// returning a Vec containing all the elements of the LoroList as LoroValue. + sequence to_vec(); + + /// Delete all elements in the list. + [Throws=LoroError] + void clear(); + + /// Get the ID of the list item at the given position. + ID? get_id_at(u32 pos); + + /// Whether the container is deleted. + boolean is_deleted(); }; interface LoroMap{ @@ -625,6 +726,23 @@ interface LoroMap{ /// /// It will convert the state of sub-containers into a nested JSON value. LoroValue get_deep_value(); + + /// Whether the container is deleted. + boolean is_deleted(); + + /// Get the peer id of the last editor on the given entry + u64? get_last_editor([ByRef] string key); + + /// Delete all key-value pairs in the map. + [Throws=LoroError] + void clear(); + + // TODO: iter? + /// Get the keys of the map. + sequence keys(); + + /// Get the values of the map. + sequence values(); }; interface LoroTree{ @@ -742,9 +860,18 @@ interface LoroTree{ /// [Read more about it](https://www.loro.dev/blog/movable-tree#implementation-and-encoding-size) void enable_fractional_index(u8 jitter); - /// Disable the fractional index generation for Tree Position when - /// you don't need the Tree's siblings to be sorted. The fractional index will be always default. + /// Disable the fractional index generation when you don't need the Tree's siblings to be sorted. + /// The fractional index will always be set to the same default value 0. + /// + /// After calling this, you cannot use `tree.moveTo()`, `tree.moveBefore()`, `tree.moveAfter()`, + /// and `tree.createAt()`. void disable_fractional_index(); + + /// Get the last move id of the target node. + ID? get_last_move_id([ByRef] TreeID target); + + /// Whether the container is deleted. + boolean is_deleted(); }; interface LoroMovableList{ @@ -851,6 +978,30 @@ interface LoroMovableList{ /// Move the value at the given position to the given position. [Throws=LoroError] void mov(u32 from, u32 to); + + /// Get the elements of the list as a vector of LoroValues. + /// + /// This method returns a vector containing all the elements in the list as LoroValues. + /// It provides a convenient way to access the entire contents of the LoroMovableList + /// as a standard Rust vector. + sequence to_vec(); + + /// Delete all elements in the list. + [Throws=LoroError] + void clear(); + + + /// Whether the container is deleted. + boolean is_deleted(); + + // TODO: for each + u64? get_creator_at(u32 pos); + + /// Get the last mover of the list item at the given position. + u64? get_last_mover_at(u32 pos); + + /// Get the last editor of the list item at the given position. + u64? get_last_editor_at(u32 pos); }; interface LoroCounter{ @@ -870,6 +1021,9 @@ interface LoroCounter{ /// Get the current value of the counter. f64 get_value(); + + /// Whether the container is deleted. + boolean is_deleted(); }; interface LoroUnknown{ @@ -922,7 +1076,7 @@ dictionary ImportBlobMetadata{ Frontiers start_frontiers; i64 end_timestamp; u32 change_num; - boolean is_snapshot; + string mode; }; dictionary ImportStatus{ @@ -1225,10 +1379,6 @@ interface Index{ /// A handle to a subscription created by GPUI. When dropped, the subscription /// is cancelled and the callback will no longer be invoked. interface Subscription{ - /// Creates a new subscription with a callback that gets invoked when - /// this subscription is dropped. - constructor(Unsubscriber unsubscribe); - /// Detaches the subscription from this handle. The callback will /// continue to be invoked until the views or models it has been /// subscribed to are dropped @@ -1250,6 +1400,11 @@ interface TreeParentId{ Unexist(); }; +dictionary UpdateOptions{ + f64? timeout_ms; + boolean use_refined_diff; +}; + interface FractionalIndex{ [Name=from_bytes] constructor(bytes bytes); @@ -1297,6 +1452,11 @@ interface ContainerID{ Normal(u64 peer,i32 counter, ContainerType container_type); }; +dictionary FrontiersOrID{ + Frontiers? frontiers; + ID? id; +}; + [Enum] interface LoroValue{ Null(); @@ -1368,4 +1528,15 @@ enum LoroEncodeError{ "FrontiersNotFound", "ShallowSnapshotIncompatibleWithOldFormat", "UnknownContainer", +}; + +[Error] +enum ChangeTravelError{ + "TargetIdNotFound", + "TargetVersionNotIncluded" +}; + +[Error] +enum UpdateTimeoutError{ + "Timeout" }; \ No newline at end of file From 99278ecf2e1b53666879f974ad791a76d2874b76 Mon Sep 17 00:00:00 2001 From: Leon Zhao Date: Wed, 27 Nov 2024 16:38:42 +0800 Subject: [PATCH 12/12] chore: config --- loro-rs/Cargo.lock | 49 ++++++++++++++++++++++++++-------------------- loro-rs/Cargo.toml | 10 +++++----- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/loro-rs/Cargo.lock b/loro-rs/Cargo.lock index 41fee07..2758c00 100644 --- a/loro-rs/Cargo.lock +++ b/loro-rs/Cargo.lock @@ -614,6 +614,7 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "loro" version = "1.1.0" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-ffi%401.1.3#76c630027a4f19110e3a446efb317d0f567d4a51" dependencies = [ "enum-as-inner 0.6.0", "fxhash", @@ -628,6 +629,7 @@ dependencies = [ [[package]] name = "loro-common" version = "1.1.0" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-ffi%401.1.3#76c630027a4f19110e3a446efb317d0f567d4a51" dependencies = [ "arbitrary", "enum-as-inner 0.6.0", @@ -644,6 +646,7 @@ dependencies = [ [[package]] name = "loro-delta" version = "1.1.0" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-ffi%401.1.3#76c630027a4f19110e3a446efb317d0f567d4a51" dependencies = [ "arrayvec", "enum-as-inner 0.5.1", @@ -654,6 +657,7 @@ dependencies = [ [[package]] name = "loro-ffi" version = "1.1.3" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-ffi%401.1.3#76c630027a4f19110e3a446efb317d0f567d4a51" dependencies = [ "loro", "serde_json", @@ -662,6 +666,7 @@ dependencies = [ [[package]] name = "loro-internal" version = "1.1.0" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-ffi%401.1.3#76c630027a4f19110e3a446efb317d0f567d4a51" dependencies = [ "append-only-bytes", "arref", @@ -701,6 +706,7 @@ dependencies = [ [[package]] name = "loro-kv-store" version = "1.1.0" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-ffi%401.1.3#76c630027a4f19110e3a446efb317d0f567d4a51" dependencies = [ "bytes", "ensure-cov", @@ -716,6 +722,7 @@ dependencies = [ [[package]] name = "loro-rle" version = "1.1.0" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-ffi%401.1.3#76c630027a4f19110e3a446efb317d0f567d4a51" dependencies = [ "append-only-bytes", "num", @@ -724,7 +731,7 @@ dependencies = [ [[package]] name = "loro-swift" -version = "0.16.2" +version = "1.1.3" dependencies = [ "loro-ffi", "uniffi", @@ -739,6 +746,7 @@ checksum = "3f3d053a135388e6b1df14e8af1212af5064746e9b87a06a345a7a779ee9695a" [[package]] name = "loro_fractional_index" version = "1.1.0" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-ffi%401.1.3#76c630027a4f19110e3a446efb317d0f567d4a51" dependencies = [ "once_cell", "rand", @@ -1322,12 +1330,13 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "uniffi" -version = "0.28.0" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31bff6daf87277a9014bcdefbc2842b0553392919d1096843c5aad899ca4588" +checksum = "4cb08c58c7ed7033150132febe696bef553f891b1ede57424b40d87a89e3c170" dependencies = [ "anyhow", "camino", + "cargo_metadata", "clap", "uniffi_bindgen", "uniffi_build", @@ -1337,9 +1346,9 @@ dependencies = [ [[package]] name = "uniffi_bindgen" -version = "0.28.0" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96061d7e01b185aa405f7c9b134741ab3e50cc6796a47d6fd8ab9a5364b5feed" +checksum = "cade167af943e189a55020eda2c314681e223f1e42aca7c4e52614c2b627698f" dependencies = [ "anyhow", "askama", @@ -1355,15 +1364,14 @@ dependencies = [ "textwrap", "toml", "uniffi_meta", - "uniffi_testing", "uniffi_udl", ] [[package]] name = "uniffi_build" -version = "0.28.0" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6b86f9b221046af0c533eafe09ece04e2f1ded04ccdc9bba0ec09aec1c52bd" +checksum = "4c7cf32576e08104b7dc2a6a5d815f37616e66c6866c2a639fe16e6d2286b75b" dependencies = [ "anyhow", "camino", @@ -1372,9 +1380,9 @@ dependencies = [ [[package]] name = "uniffi_checksum_derive" -version = "0.28.0" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fcfa22f55829d3aaa7acfb1c5150224188fe0f27c59a8a3eddcaa24d1ffbe58" +checksum = "802d2051a700e3ec894c79f80d2705b69d85844dafbbe5d1a92776f8f48b563a" dependencies = [ "quote", "syn 2.0.72", @@ -1382,13 +1390,12 @@ dependencies = [ [[package]] name = "uniffi_core" -version = "0.28.0" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3210d57d6ab6065ab47a2898dacdb7c606fd6a4156196831fa3bf82e34ac58a6" +checksum = "bc7687007d2546c454d8ae609b105daceb88175477dac280707ad6d95bcd6f1f" dependencies = [ "anyhow", "bytes", - "camino", "log", "once_cell", "paste", @@ -1397,9 +1404,9 @@ dependencies = [ [[package]] name = "uniffi_macros" -version = "0.28.0" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58691741080935437dc862122e68d7414432a11824ac1137868de46181a0bd2" +checksum = "12c65a5b12ec544ef136693af8759fb9d11aefce740fb76916721e876639033b" dependencies = [ "bincode", "camino", @@ -1415,9 +1422,9 @@ dependencies = [ [[package]] name = "uniffi_meta" -version = "0.28.0" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7663eacdbd9fbf4a88907ddcfe2e6fa85838eb6dc2418a7d91eebb3786f8e20b" +checksum = "4a74ed96c26882dac1ca9b93ca23c827e284bacbd7ec23c6f0b0372f747d59e4" dependencies = [ "anyhow", "bytes", @@ -1427,9 +1434,9 @@ dependencies = [ [[package]] name = "uniffi_testing" -version = "0.28.0" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f922465f7566f25f8fe766920205fdfa9a3fcdc209c6bfb7557f0b5bf45b04dd" +checksum = "6a6f984f0781f892cc864a62c3a5c60361b1ccbd68e538e6c9fbced5d82268ac" dependencies = [ "anyhow", "camino", @@ -1440,9 +1447,9 @@ dependencies = [ [[package]] name = "uniffi_udl" -version = "0.28.0" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef408229a3a407fafa4c36dc4f6ece78a6fb258ab28d2b64bddd49c8cb680f6" +checksum = "037820a4cfc4422db1eaa82f291a3863c92c7d1789dc513489c36223f9b4cdfc" dependencies = [ "anyhow", "textwrap", diff --git a/loro-rs/Cargo.toml b/loro-rs/Cargo.toml index fa6755b..764d099 100644 --- a/loro-rs/Cargo.toml +++ b/loro-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "loro-swift" -version = "0.16.2" +version = "1.1.3" edition = "2021" [lib] @@ -14,12 +14,12 @@ path = "src/uniffi-bindgen.rs" [dependencies] -loro-ffi = { path = "../../loro/crates/loro-ffi" } -# loro-ffi = { git = "https://github.com/loro-dev/loro.git", rev = "a9f669d173807b80dde7ffef7f467c8a57fc5b1f" } -uniffi = { version = "0.28" } +# loro-ffi = { path = "../../loro/crates/loro-ffi" } +loro-ffi = { git = "https://github.com/loro-dev/loro.git", tag = "loro-ffi@1.1.3" } +uniffi = { version = "0.28.3" } [build-dependencies] -uniffi = { version = "0.28", features = ["build"] } +uniffi = { version = "0.28.3", features = ["build"] } [features] cli = ["uniffi/cli"]