loro/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3#![warn(missing_debug_implementations)]
4use event::DiffBatch;
5use event::{DiffEvent, Subscriber};
6use fxhash::FxHashSet;
7pub use loro_common::InternalString;
8pub use loro_internal::cursor::CannotFindRelativePosition;
9use loro_internal::cursor::Cursor;
10use loro_internal::cursor::PosQueryResult;
11use loro_internal::cursor::Side;
12pub use loro_internal::encoding::ImportStatus;
13use loro_internal::handler::{HandlerTrait, ValueOrHandler};
14pub use loro_internal::loro::ChangeTravelError;
15pub use loro_internal::pre_commit::{
16    ChangeModifier, FirstCommitFromPeerCallback, PreCommitCallback,
17};
18pub use loro_internal::sync;
19pub use loro_internal::undo::{OnPop, UndoItemMeta, UndoOrRedo};
20use loro_internal::version::shrink_frontiers;
21pub use loro_internal::version::ImVersionVector;
22use loro_internal::DocState;
23use loro_internal::LoroDoc as InnerLoroDoc;
24use loro_internal::OpLog;
25use loro_internal::{
26    handler::Handler as InnerHandler, ListHandler as InnerListHandler,
27    MapHandler as InnerMapHandler, MovableListHandler as InnerMovableListHandler,
28    TextHandler as InnerTextHandler, TreeHandler as InnerTreeHandler,
29    UnknownHandler as InnerUnknownHandler,
30};
31use std::cmp::Ordering;
32use std::ops::ControlFlow;
33use std::ops::Deref;
34use std::ops::Range;
35use std::sync::Arc;
36use tracing::info;
37
38pub use loro_internal::diff::diff_impl::UpdateOptions;
39pub use loro_internal::diff::diff_impl::UpdateTimeoutError;
40pub use loro_internal::subscription::LocalUpdateCallback;
41pub use loro_internal::subscription::PeerIdUpdateCallback;
42pub use loro_internal::ChangeMeta;
43pub use loro_internal::LORO_VERSION;
44pub mod event;
45pub use loro_internal::awareness;
46pub use loro_internal::change::Timestamp;
47pub use loro_internal::configure::Configure;
48pub use loro_internal::configure::{StyleConfig, StyleConfigMap};
49pub use loro_internal::container::richtext::ExpandType;
50pub use loro_internal::container::{ContainerID, ContainerType, IntoContainerId};
51pub use loro_internal::cursor;
52pub use loro_internal::delta::{TreeDeltaItem, TreeDiff, TreeDiffItem, TreeExternalDiff};
53pub use loro_internal::encoding::ImportBlobMetadata;
54pub use loro_internal::encoding::{EncodedBlobMode, ExportMode};
55pub use loro_internal::event::{EventTriggerKind, Index};
56pub use loro_internal::handler::TextDelta;
57pub use loro_internal::json;
58pub use loro_internal::json::{
59    FutureOp as JsonFutureOp, FutureOpWrapper as JsonFutureOpWrapper, JsonChange, JsonOp,
60    JsonOpContent, JsonSchema, ListOp as JsonListOp, MapOp as JsonMapOp,
61    MovableListOp as JsonMovableListOp, TextOp as JsonTextOp, TreeOp as JsonTreeOp,
62};
63pub use loro_internal::kv_store::{KvStore, MemKvStore};
64pub use loro_internal::loro::CommitOptions;
65pub use loro_internal::loro::DocAnalysis;
66pub use loro_internal::oplog::FrontiersNotIncluded;
67pub use loro_internal::undo;
68pub use loro_internal::version::{Frontiers, VersionRange, VersionVector, VersionVectorDiff};
69pub use loro_internal::ApplyDiff;
70pub use loro_internal::Subscription;
71pub use loro_internal::UndoManager as InnerUndoManager;
72pub use loro_internal::{loro_value, to_value};
73pub use loro_internal::{
74    Counter, CounterSpan, FractionalIndex, IdLp, IdSpan, Lamport, PeerID, TreeID, TreeParentId, ID,
75};
76pub use loro_internal::{
77    LoroBinaryValue, LoroEncodeError, LoroError, LoroListValue, LoroMapValue, LoroResult,
78    LoroStringValue, LoroTreeError, LoroValue, ToJson,
79};
80pub use loro_kv_store as kv_store;
81
82#[cfg(feature = "jsonpath")]
83pub use loro_internal::jsonpath;
84#[cfg(feature = "jsonpath")]
85pub use loro_internal::jsonpath::JsonPathError;
86
87#[cfg(feature = "counter")]
88mod counter;
89#[cfg(feature = "counter")]
90pub use counter::LoroCounter;
91
92/// `LoroDoc` is the entry for the whole document.
93/// When it's dropped, all the associated [`Handler`]s will be invalidated.
94///
95/// **Important:** Loro is a pure library and does not handle network protocols.
96/// It is the responsibility of the user to manage the storage, loading, and synchronization
97/// of the bytes exported by Loro in a manner suitable for their specific environment.
98#[derive(Debug)]
99pub struct LoroDoc {
100    doc: InnerLoroDoc,
101    // This field is here to prevent some weird issues in debug mode
102    #[cfg(debug_assertions)]
103    _temp: u8,
104}
105
106impl Default for LoroDoc {
107    fn default() -> Self {
108        Self::new()
109    }
110}
111
112impl Clone for LoroDoc {
113    fn clone(&self) -> Self {
114        let doc = self.doc.clone();
115        LoroDoc::_new(doc)
116    }
117}
118
119impl LoroDoc {
120    #[inline(always)]
121    fn _new(doc: InnerLoroDoc) -> Self {
122        Self {
123            doc,
124            #[cfg(debug_assertions)]
125            _temp: 0,
126        }
127    }
128
129    /// Create a new `LoroDoc` instance.
130    #[inline]
131    pub fn new() -> Self {
132        let doc = InnerLoroDoc::default();
133        doc.start_auto_commit();
134
135        LoroDoc::_new(doc)
136    }
137
138    /// Duplicate the document with a different PeerID
139    ///
140    /// The time complexity and space complexity of this operation are both O(n),
141    ///
142    /// When called in detached mode, it will fork at the current state frontiers.
143    /// It will have the same effect as `fork_at(&self.state_frontiers())`.
144    #[inline]
145    pub fn fork(&self) -> Self {
146        let doc = self.doc.fork();
147        LoroDoc::_new(doc)
148    }
149
150    /// Fork the document at the given frontiers.
151    ///
152    /// The created doc will only contain the history before the specified frontiers.
153    pub fn fork_at(&self, frontiers: &Frontiers) -> LoroDoc {
154        let new_doc = self.doc.fork_at(frontiers);
155        new_doc.start_auto_commit();
156        LoroDoc::_new(new_doc)
157    }
158
159    /// Get the configurations of the document.
160    #[inline]
161    pub fn config(&self) -> &Configure {
162        self.doc.config()
163    }
164
165    /// Get `Change` at the given id.
166    ///
167    /// `Change` is a grouped continuous operations that share the same id, timestamp, commit message.
168    ///
169    /// - The id of the `Change` is the id of its first op.
170    /// - The second op's id is `{ peer: change.id.peer, counter: change.id.counter + 1 }`
171    ///
172    /// The same applies on `Lamport`:
173    ///
174    /// - The lamport of the `Change` is the lamport of its first op.
175    /// - The second op's lamport is `change.lamport + 1`
176    ///
177    /// The length of the `Change` is how many operations it contains
178    pub fn get_change(&self, id: ID) -> Option<ChangeMeta> {
179        let change = self.doc.oplog().lock().unwrap().get_change_at(id)?;
180        Some(ChangeMeta::from_change(&change))
181    }
182
183    /// Decodes the metadata for an imported blob from the provided bytes.
184    #[inline]
185    pub fn decode_import_blob_meta(
186        bytes: &[u8],
187        check_checksum: bool,
188    ) -> LoroResult<ImportBlobMetadata> {
189        InnerLoroDoc::decode_import_blob_meta(bytes, check_checksum)
190    }
191
192    /// Set whether to record the timestamp of each change. Default is `false`.
193    ///
194    /// If enabled, the Unix timestamp will be recorded for each change automatically.
195    ///
196    /// You can set each timestamp manually when committing a change.
197    ///
198    /// NOTE: Timestamps are forced to be in ascending order.
199    /// If you commit a new change with a timestamp that is less than the existing one,
200    /// the largest existing timestamp will be used instead.
201    #[inline]
202    pub fn set_record_timestamp(&self, record: bool) {
203        self.doc.set_record_timestamp(record);
204    }
205
206    /// Enables editing in detached mode, which is disabled by default.
207    ///
208    /// The doc enter detached mode after calling `detach` or checking out a non-latest version.
209    ///
210    /// # Important Notes:
211    ///
212    /// - This mode uses a different PeerID for each checkout.
213    /// - Ensure no concurrent operations share the same PeerID if set manually.
214    /// - Importing does not affect the document's state or version; changes are
215    ///   recorded in the [OpLog] only. Call `checkout` to apply changes.
216    #[inline]
217    pub fn set_detached_editing(&self, enable: bool) {
218        self.doc.set_detached_editing(enable);
219    }
220
221    /// Whether editing the doc in detached mode is allowed, which is disabled by
222    /// default.
223    ///
224    /// The doc enter detached mode after calling `detach` or checking out a non-latest version.
225    ///
226    /// # Important Notes:
227    ///
228    /// - This mode uses a different PeerID for each checkout.
229    /// - Ensure no concurrent operations share the same PeerID if set manually.
230    /// - Importing does not affect the document's state or version; changes are
231    ///   recorded in the [OpLog] only. Call `checkout` to apply changes.
232    #[inline]
233    pub fn is_detached_editing_enabled(&self) -> bool {
234        self.doc.is_detached_editing_enabled()
235    }
236
237    /// Set the interval of mergeable changes, **in seconds**.
238    ///
239    /// If two continuous local changes are within the interval, they will be merged into one change.
240    /// The default value is 1000 seconds.
241    ///
242    /// By default, we record timestamps in seconds for each change. So if the merge interval is 1, and changes A and B
243    /// have timestamps of 3 and 4 respectively, then they will be merged into one change
244    #[inline]
245    pub fn set_change_merge_interval(&self, interval: i64) {
246        self.doc.set_change_merge_interval(interval);
247    }
248
249    /// Set the rich text format configuration of the document.
250    ///
251    /// You need to config it if you use rich text `mark` method.
252    /// Specifically, you need to config the `expand` property of each style.
253    ///
254    /// Expand is used to specify the behavior of expanding when new text is inserted at the
255    /// beginning or end of the style.
256    #[inline]
257    pub fn config_text_style(&self, text_style: StyleConfigMap) {
258        self.doc.config_text_style(text_style)
259    }
260
261    /// Configures the default text style for the document.
262    ///
263    /// This method sets the default text style configuration for the document when using LoroText.
264    /// If `None` is provided, the default style is reset.
265    ///
266    /// # Parameters
267    ///
268    /// - `text_style`: The style configuration to set as the default. `None` to reset.
269    pub fn config_default_text_style(&self, text_style: Option<StyleConfig>) {
270        self.doc.config_default_text_style(text_style);
271    }
272
273    /// Attach the document state to the latest known version.
274    ///
275    /// > The document becomes detached during a `checkout` operation.
276    /// > Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`.
277    /// > In a detached state, the document is not editable, and any `import` operations will be
278    /// > recorded in the `OpLog` without being applied to the `DocState`.
279    #[inline]
280    pub fn attach(&self) {
281        self.doc.attach()
282    }
283
284    /// Checkout the `DocState` to a specific version.
285    ///
286    /// The document becomes detached during a `checkout` operation.
287    /// Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`.
288    /// In a detached state, the document is not editable, and any `import` operations will be
289    /// recorded in the `OpLog` without being applied to the `DocState`.
290    ///
291    /// You should call `attach` to attach the `DocState` to the latest version of `OpLog`.
292    #[inline]
293    pub fn checkout(&self, frontiers: &Frontiers) -> LoroResult<()> {
294        self.doc.checkout(frontiers)
295    }
296
297    /// Checkout the `DocState` to the latest version.
298    ///
299    /// > The document becomes detached during a `checkout` operation.
300    /// > Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`.
301    /// > In a detached state, the document is not editable, and any `import` operations will be
302    /// > recorded in the `OpLog` without being applied to the `DocState`.
303    ///
304    /// This has the same effect as `attach`.
305    #[inline]
306    pub fn checkout_to_latest(&self) {
307        self.doc.checkout_to_latest()
308    }
309
310    /// Compare the frontiers with the current OpLog's version.
311    ///
312    /// If `other` contains any version that's not contained in the current OpLog, return [Ordering::Less].
313    #[inline]
314    pub fn cmp_with_frontiers(&self, other: &Frontiers) -> Ordering {
315        self.doc.cmp_with_frontiers(other)
316    }
317
318    /// Compare two frontiers.
319    ///
320    /// If the frontiers are not included in the document, return [`FrontiersNotIncluded`].
321    #[inline]
322    pub fn cmp_frontiers(
323        &self,
324        a: &Frontiers,
325        b: &Frontiers,
326    ) -> Result<Option<Ordering>, FrontiersNotIncluded> {
327        self.doc.cmp_frontiers(a, b)
328    }
329
330    /// Force the document enter the detached mode.
331    ///
332    /// In this mode, when you importing new updates, the [loro_internal::DocState] will not be changed.
333    ///
334    /// Learn more at https://loro.dev/docs/advanced/doc_state_and_oplog#attacheddetached-status
335    #[inline]
336    pub fn detach(&self) {
337        self.doc.detach()
338    }
339
340    /// Import a batch of updates/snapshot.
341    ///
342    /// The data can be in arbitrary order. The import result will be the same.
343    #[inline]
344    pub fn import_batch(&self, bytes: &[Vec<u8>]) -> LoroResult<ImportStatus> {
345        self.doc.import_batch(bytes)
346    }
347
348    /// Get a [LoroMovableList] by container id.
349    ///
350    /// If the provided id is string, it will be converted into a root container id with the name of the string.
351    #[inline]
352    pub fn get_movable_list<I: IntoContainerId>(&self, id: I) -> LoroMovableList {
353        LoroMovableList {
354            handler: self.doc.get_movable_list(id),
355        }
356    }
357
358    /// Get a [LoroList] by container id.
359    ///
360    /// If the provided id is string, it will be converted into a root container id with the name of the string.
361    #[inline]
362    pub fn get_list<I: IntoContainerId>(&self, id: I) -> LoroList {
363        LoroList {
364            handler: self.doc.get_list(id),
365        }
366    }
367
368    /// Get a [LoroMap] by container id.
369    ///
370    /// If the provided id is string, it will be converted into a root container id with the name of the string.
371    #[inline]
372    pub fn get_map<I: IntoContainerId>(&self, id: I) -> LoroMap {
373        LoroMap {
374            handler: self.doc.get_map(id),
375        }
376    }
377
378    /// Get a [LoroText] by container id.
379    ///
380    /// If the provided id is string, it will be converted into a root container id with the name of the string.
381    #[inline]
382    pub fn get_text<I: IntoContainerId>(&self, id: I) -> LoroText {
383        LoroText {
384            handler: self.doc.get_text(id),
385        }
386    }
387
388    /// Get a [LoroTree] by container id.
389    ///
390    /// If the provided id is string, it will be converted into a root container id with the name of the string.
391    #[inline]
392    pub fn get_tree<I: IntoContainerId>(&self, id: I) -> LoroTree {
393        LoroTree {
394            handler: self.doc.get_tree(id),
395        }
396    }
397
398    #[cfg(feature = "counter")]
399    /// Get a [LoroCounter] by container id.
400    ///
401    /// If the provided id is string, it will be converted into a root container id with the name of the string.
402    #[inline]
403    pub fn get_counter<I: IntoContainerId>(&self, id: I) -> LoroCounter {
404        LoroCounter {
405            handler: self.doc.get_counter(id),
406        }
407    }
408
409    /// Commit the cumulative auto commit transaction.
410    ///
411    /// There is a transaction behind every operation.
412    /// The events will be emitted after a transaction is committed. A transaction is committed when:
413    ///
414    /// - `doc.commit()` is called.
415    /// - `doc.export(mode)` is called.
416    /// - `doc.import(data)` is called.
417    /// - `doc.checkout(version)` is called.
418    #[inline]
419    pub fn commit(&self) {
420        self.doc.commit_then_renew();
421    }
422
423    /// Commit the cumulative auto commit transaction with custom configure.
424    ///
425    /// There is a transaction behind every operation.
426    /// It will automatically commit when users invoke export or import.
427    /// The event will be sent after a transaction is committed
428    #[inline]
429    pub fn commit_with(&self, options: CommitOptions) {
430        self.doc.commit_with(options);
431    }
432
433    /// Set commit message for the current uncommitted changes
434    ///
435    /// It will be persisted.
436    pub fn set_next_commit_message(&self, msg: &str) {
437        self.doc.set_next_commit_message(msg)
438    }
439
440    /// Set `origin` for the current uncommitted changes, it can be used to track the source of changes in an event.
441    ///
442    /// It will NOT be persisted.
443    pub fn set_next_commit_origin(&self, origin: &str) {
444        self.doc.set_next_commit_origin(origin)
445    }
446
447    /// Set the timestamp of the next commit.
448    ///
449    /// It will be persisted and stored in the `OpLog`.
450    /// You can get the timestamp from the [`Change`] type.
451    pub fn set_next_commit_timestamp(&self, timestamp: Timestamp) {
452        self.doc.set_next_commit_timestamp(timestamp)
453    }
454
455    /// Set the options of the next commit.
456    ///
457    /// It will be used when the next commit is performed.
458    pub fn set_next_commit_options(&self, options: CommitOptions) {
459        self.doc.set_next_commit_options(options);
460    }
461
462    /// Clear the options of the next commit.
463    pub fn clear_next_commit_options(&self) {
464        self.doc.clear_next_commit_options();
465    }
466
467    /// Whether the document is in detached mode, where the [loro_internal::DocState] is not
468    /// synchronized with the latest version of the [loro_internal::OpLog].
469    #[inline]
470    pub fn is_detached(&self) -> bool {
471        self.doc.is_detached()
472    }
473
474    /// Import updates/snapshot exported by [`LoroDoc::export_snapshot`] or [`LoroDoc::export_from`].
475    #[inline]
476    pub fn import(&self, bytes: &[u8]) -> Result<ImportStatus, LoroError> {
477        self.doc.import_with(bytes, "".into())
478    }
479
480    /// Import updates/snapshot exported by [`LoroDoc::export_snapshot`] or [`LoroDoc::export_from`].
481    ///
482    /// It marks the import with a custom `origin` string. It can be used to track the import source
483    /// in the generated events.
484    #[inline]
485    pub fn import_with(&self, bytes: &[u8], origin: &str) -> Result<ImportStatus, LoroError> {
486        self.doc.import_with(bytes, origin.into())
487    }
488
489    /// Import the json schema updates.
490    ///
491    /// only supports backward compatibility but not forward compatibility.
492    #[inline]
493    pub fn import_json_updates<T: TryInto<JsonSchema>>(
494        &self,
495        json: T,
496    ) -> Result<ImportStatus, LoroError> {
497        self.doc.import_json_updates(json)
498    }
499
500    /// Export the current state with json-string format of the document.
501    #[inline]
502    pub fn export_json_updates(
503        &self,
504        start_vv: &VersionVector,
505        end_vv: &VersionVector,
506    ) -> JsonSchema {
507        self.doc.export_json_updates(start_vv, end_vv, true)
508    }
509
510    /// Export the current state with json-string format of the document, without peer compression.
511    ///
512    /// Compared to [`export_json_updates`], this method does not compress the peer IDs in the updates.
513    /// So the operations are easier to be processed by application code.
514    #[inline]
515    pub fn export_json_updates_without_peer_compression(
516        &self,
517        start_vv: &VersionVector,
518        end_vv: &VersionVector,
519    ) -> JsonSchema {
520        self.doc.export_json_updates(start_vv, end_vv, false)
521    }
522
523    /// Exports changes within the specified ID span to JSON schema format.
524    ///
525    /// The JSON schema format produced by this method is identical to the one generated by `export_json_updates`.
526    /// It ensures deterministic output, making it ideal for hash calculations and integrity checks.
527    ///
528    /// This method can also export pending changes from the uncommitted transaction that have not yet been applied to the OpLog.
529    ///
530    /// This method will NOT trigger a new commit implicitly.
531    ///
532    /// # Example
533    /// ```
534    /// use loro::{LoroDoc, IdSpan};
535    ///
536    /// let doc = LoroDoc::new();
537    /// doc.set_peer_id(0).unwrap();
538    /// doc.get_text("text").insert(0, "a").unwrap();
539    /// doc.commit();
540    /// let doc_clone = doc.clone();
541    /// let _sub = doc.subscribe_pre_commit(Box::new(move |e| {
542    ///     let changes = doc_clone.export_json_in_id_span(IdSpan::new(
543    ///         0,
544    ///         0,
545    ///         e.change_meta.id.counter + e.change_meta.len as i32,
546    ///     ));
547    ///     // 2 because commit one and the uncommit one
548    ///     assert_eq!(changes.len(), 2);
549    ///     true
550    /// }));
551    /// doc.get_text("text").insert(0, "b").unwrap();
552    /// let changes = doc.export_json_in_id_span(IdSpan::new(0, 0, 2));
553    /// assert_eq!(changes.len(), 1);
554    /// doc.commit();
555    /// // change merged
556    /// assert_eq!(changes.len(), 1);
557    /// ```
558    pub fn export_json_in_id_span(&self, id_span: IdSpan) -> Vec<JsonChange> {
559        self.doc.export_json_in_id_span(id_span)
560    }
561
562    /// Export all the ops not included in the given `VersionVector`
563    #[deprecated(
564        since = "1.0.0",
565        note = "Use `export` with `ExportMode::Updates` instead"
566    )]
567    #[inline]
568    pub fn export_from(&self, vv: &VersionVector) -> Vec<u8> {
569        self.doc.export_from(vv)
570    }
571
572    /// Export the current state and history of the document.
573    #[deprecated(
574        since = "1.0.0",
575        note = "Use `export` with `ExportMode::Snapshot` instead"
576    )]
577    #[inline]
578    pub fn export_snapshot(&self) -> Vec<u8> {
579        self.doc.export_snapshot().unwrap()
580    }
581
582    /// Convert `Frontiers` into `VersionVector`
583    #[inline]
584    pub fn frontiers_to_vv(&self, frontiers: &Frontiers) -> Option<VersionVector> {
585        self.doc.frontiers_to_vv(frontiers)
586    }
587
588    /// Minimize the frontiers by removing the unnecessary entries.
589    pub fn minimize_frontiers(&self, frontiers: &Frontiers) -> Result<Frontiers, ID> {
590        self.with_oplog(|oplog| shrink_frontiers(frontiers, oplog.dag()))
591    }
592
593    /// Convert `VersionVector` into `Frontiers`
594    #[inline]
595    pub fn vv_to_frontiers(&self, vv: &VersionVector) -> Frontiers {
596        self.doc.vv_to_frontiers(vv)
597    }
598
599    /// Access the `OpLog`.
600    ///
601    /// NOTE: Please be ware that the API in `OpLog` is unstable
602    #[inline]
603    pub fn with_oplog<R>(&self, f: impl FnOnce(&OpLog) -> R) -> R {
604        let oplog = self.doc.oplog().lock().unwrap();
605        f(&oplog)
606    }
607
608    /// Access the `DocState`.
609    ///
610    /// NOTE: Please be ware that the API in `DocState` is unstable
611    #[inline]
612    pub fn with_state<R>(&self, f: impl FnOnce(&mut DocState) -> R) -> R {
613        let mut state = self.doc.app_state().lock().unwrap();
614        f(&mut state)
615    }
616
617    /// Get the `VersionVector` version of `OpLog`
618    #[inline]
619    pub fn oplog_vv(&self) -> VersionVector {
620        self.doc.oplog_vv()
621    }
622
623    /// Get the `VersionVector` version of `DocState`
624    #[inline]
625    pub fn state_vv(&self) -> VersionVector {
626        self.doc.state_vv()
627    }
628
629    /// The doc only contains the history since this version
630    ///
631    /// This is empty if the doc is not shallow.
632    ///
633    /// The ops included by the shallow history start version vector are not in the doc.
634    #[inline]
635    pub fn shallow_since_vv(&self) -> ImVersionVector {
636        self.doc.shallow_since_vv()
637    }
638
639    /// The doc only contains the history since this version
640    ///
641    /// This is empty if the doc is not shallow.
642    ///
643    /// The ops included by the shallow history start frontiers are not in the doc.
644    #[inline]
645    pub fn shallow_since_frontiers(&self) -> Frontiers {
646        self.doc.shallow_since_frontiers()
647    }
648
649    /// Get the total number of operations in the `OpLog`
650    #[inline]
651    pub fn len_ops(&self) -> usize {
652        self.doc.len_ops()
653    }
654
655    /// Get the total number of changes in the `OpLog`
656    #[inline]
657    pub fn len_changes(&self) -> usize {
658        self.doc.len_changes()
659    }
660
661    /// Get the shallow value of the document.
662    #[inline]
663    pub fn get_value(&self) -> LoroValue {
664        self.doc.get_value()
665    }
666
667    /// Get the entire state of the current DocState
668    #[inline]
669    pub fn get_deep_value(&self) -> LoroValue {
670        self.doc.get_deep_value()
671    }
672
673    /// Get the entire state of the current DocState with container id
674    pub fn get_deep_value_with_id(&self) -> LoroValue {
675        self.doc
676            .app_state()
677            .lock()
678            .unwrap()
679            .get_deep_value_with_id()
680    }
681
682    /// Get the `Frontiers` version of `OpLog`
683    #[inline]
684    pub fn oplog_frontiers(&self) -> Frontiers {
685        self.doc.oplog_frontiers()
686    }
687
688    /// Get the `Frontiers` version of `DocState`
689    ///
690    /// Learn more about [`Frontiers`](https://loro.dev/docs/advanced/version_deep_dive)
691    #[inline]
692    pub fn state_frontiers(&self) -> Frontiers {
693        self.doc.state_frontiers()
694    }
695
696    /// Get the PeerID
697    #[inline]
698    pub fn peer_id(&self) -> PeerID {
699        self.doc.peer_id()
700    }
701
702    /// Change the PeerID
703    ///
704    /// NOTE: You need to make sure there is no chance two peer have the same PeerID.
705    /// If it happens, the document will be corrupted.
706    #[inline]
707    pub fn set_peer_id(&self, peer: PeerID) -> LoroResult<()> {
708        self.doc.set_peer_id(peer)
709    }
710
711    /// Subscribe the events of a container.
712    ///
713    /// The callback will be invoked after a transaction that change the container.
714    /// Returns a subscription that can be used to unsubscribe.
715    ///
716    /// The events will be emitted after a transaction is committed. A transaction is committed when:
717    ///
718    /// - `doc.commit()` is called.
719    /// - `doc.export(mode)` is called.
720    /// - `doc.import(data)` is called.
721    /// - `doc.checkout(version)` is called.
722    ///
723    /// # Example
724    ///
725    /// ```
726    /// # use loro::LoroDoc;
727    /// # use std::sync::{atomic::AtomicBool, Arc};
728    /// # use loro::{event::DiffEvent, LoroResult, TextDelta};
729    /// #
730    /// let doc = LoroDoc::new();
731    /// let text = doc.get_text("text");
732    /// let ran = Arc::new(AtomicBool::new(false));
733    /// let ran2 = ran.clone();
734    /// let sub = doc.subscribe(
735    ///     &text.id(),
736    ///     Arc::new(move |event| {
737    ///         assert!(event.triggered_by.is_local());
738    ///         for event in event.events {
739    ///             let delta = event.diff.as_text().unwrap();
740    ///             let d = TextDelta::Insert {
741    ///                 insert: "123".into(),
742    ///                 attributes: Default::default(),
743    ///             };
744    ///             assert_eq!(delta, &vec![d]);
745    ///             ran2.store(true, std::sync::atomic::Ordering::Relaxed);
746    ///         }
747    ///     }),
748    /// );
749    /// text.insert(0, "123").unwrap();
750    /// doc.commit();
751    /// assert!(ran.load(std::sync::atomic::Ordering::Relaxed));
752    /// // unsubscribe
753    /// sub.unsubscribe();
754    /// ```
755    #[inline]
756    pub fn subscribe(&self, container_id: &ContainerID, callback: Subscriber) -> Subscription {
757        self.doc.subscribe(
758            container_id,
759            Arc::new(move |e| {
760                callback(DiffEvent::from(e));
761            }),
762        )
763    }
764
765    /// Subscribe all the events.
766    ///
767    /// The callback will be invoked when any part of the [loro_internal::DocState] is changed.
768    /// Returns a subscription that can be used to unsubscribe.
769    ///
770    /// The events will be emitted after a transaction is committed. A transaction is committed when:
771    ///
772    /// - `doc.commit()` is called.
773    /// - `doc.export(mode)` is called.
774    /// - `doc.import(data)` is called.
775    /// - `doc.checkout(version)` is called.
776    #[inline]
777    pub fn subscribe_root(&self, callback: Subscriber) -> Subscription {
778        // self.doc.subscribe_root(callback)
779        self.doc.subscribe_root(Arc::new(move |e| {
780            callback(DiffEvent::from(e));
781        }))
782    }
783
784    /// Subscribe the local update of the document.
785    pub fn subscribe_local_update(&self, callback: LocalUpdateCallback) -> Subscription {
786        self.doc.subscribe_local_update(callback)
787    }
788
789    /// Subscribe the peer id change of the document.
790    pub fn subscribe_peer_id_change(&self, callback: PeerIdUpdateCallback) -> Subscription {
791        self.doc.subscribe_peer_id_change(callback)
792    }
793
794    /// Estimate the size of the document states in memory.
795    #[inline]
796    pub fn log_estimate_size(&self) {
797        self.doc.log_estimated_size();
798    }
799
800    /// Check the correctness of the document state by comparing it with the state
801    /// calculated by applying all the history.
802    #[inline]
803    pub fn check_state_correctness_slow(&self) {
804        self.doc.check_state_diff_calc_consistency_slow()
805    }
806
807    /// Get the handler by the path.
808    #[inline]
809    pub fn get_by_path(&self, path: &[Index]) -> Option<ValueOrContainer> {
810        self.doc.get_by_path(path).map(ValueOrContainer::from)
811    }
812
813    /// Get the handler by the string path.
814    ///
815    /// The path can be specified in different ways depending on the container type:
816    ///
817    /// For Tree:
818    /// 1. Using node IDs: `tree/{node_id}/property`
819    /// 2. Using indices: `tree/0/1/property`
820    ///
821    /// For List and MovableList:
822    /// - Using indices: `list/0` or `list/1/property`
823    ///
824    /// For Map:
825    /// - Using keys: `map/key` or `map/nested/property`
826    ///
827    /// For tree structures, index-based paths follow depth-first traversal order.
828    /// The indices start from 0 and represent the position of a node among its siblings.
829    ///
830    /// # Examples
831    /// ```
832    /// # use loro::{LoroDoc, LoroValue};
833    /// let doc = LoroDoc::new();
834    ///
835    /// // Tree example
836    /// let tree = doc.get_tree("tree");
837    /// let root = tree.create(None).unwrap();
838    /// tree.get_meta(root).unwrap().insert("name", "root").unwrap();
839    /// // Access tree by ID or index
840    /// let name1 = doc.get_by_str_path(&format!("tree/{}/name", root)).unwrap().into_value().unwrap();
841    /// let name2 = doc.get_by_str_path("tree/0/name").unwrap().into_value().unwrap();
842    /// assert_eq!(name1, name2);
843    ///
844    /// // List example
845    /// let list = doc.get_list("list");
846    /// list.insert(0, "first").unwrap();
847    /// list.insert(1, "second").unwrap();
848    /// // Access list by index
849    /// let item = doc.get_by_str_path("list/0");
850    /// assert_eq!(item.unwrap().into_value().unwrap().into_string().unwrap(), "first".into());
851    ///
852    /// // Map example
853    /// let map = doc.get_map("map");
854    /// map.insert("key", "value").unwrap();
855    /// // Access map by key
856    /// let value = doc.get_by_str_path("map/key");
857    /// assert_eq!(value.unwrap().into_value().unwrap().into_string().unwrap(), "value".into());
858    ///
859    /// // MovableList example
860    /// let mlist = doc.get_movable_list("mlist");
861    /// mlist.insert(0, "item").unwrap();
862    /// // Access movable list by index
863    /// let item = doc.get_by_str_path("mlist/0");
864    /// assert_eq!(item.unwrap().into_value().unwrap().into_string().unwrap(), "item".into());
865    /// ```
866    #[inline]
867    pub fn get_by_str_path(&self, path: &str) -> Option<ValueOrContainer> {
868        self.doc.get_by_str_path(path).map(ValueOrContainer::from)
869    }
870
871    /// Get the absolute position of the given cursor.
872    ///
873    /// # Example
874    ///
875    /// ```
876    /// # use loro::{LoroDoc, ToJson};
877    /// let doc = LoroDoc::new();
878    /// let text = &doc.get_text("text");
879    /// text.insert(0, "01234").unwrap();
880    /// let pos = text.get_cursor(5, Default::default()).unwrap();
881    /// assert_eq!(doc.get_cursor_pos(&pos).unwrap().current.pos, 5);
882    /// text.insert(0, "01234").unwrap();
883    /// assert_eq!(doc.get_cursor_pos(&pos).unwrap().current.pos, 10);
884    /// text.delete(0, 10).unwrap();
885    /// assert_eq!(doc.get_cursor_pos(&pos).unwrap().current.pos, 0);
886    /// text.insert(0, "01234").unwrap();
887    /// assert_eq!(doc.get_cursor_pos(&pos).unwrap().current.pos, 5);
888    /// ```
889    #[inline]
890    pub fn get_cursor_pos(
891        &self,
892        cursor: &Cursor,
893    ) -> Result<PosQueryResult, CannotFindRelativePosition> {
894        self.doc.query_pos(cursor)
895    }
896
897    /// Get the inner LoroDoc ref.
898    #[inline]
899    pub fn inner(&self) -> &InnerLoroDoc {
900        &self.doc
901    }
902
903    /// Whether the history cache is built.
904    #[inline]
905    pub fn has_history_cache(&self) -> bool {
906        self.doc.has_history_cache()
907    }
908
909    /// Free the history cache that is used for making checkout faster.
910    ///
911    /// If you use checkout that switching to an old/concurrent version, the history cache will be built.
912    /// You can free it by calling this method.
913    #[inline]
914    pub fn free_history_cache(&self) {
915        self.doc.free_history_cache()
916    }
917
918    /// Free the cached diff calculator that is used for checkout.
919    #[inline]
920    pub fn free_diff_calculator(&self) {
921        self.doc.free_diff_calculator()
922    }
923
924    /// Encoded all ops and history cache to bytes and store them in the kv store.
925    ///
926    /// This will free up the memory that used by parsed ops
927    #[inline]
928    pub fn compact_change_store(&self) {
929        self.doc.compact_change_store()
930    }
931
932    /// Export the document in the given mode.
933    pub fn export(&self, mode: ExportMode) -> Result<Vec<u8>, LoroEncodeError> {
934        self.doc.export(mode)
935    }
936
937    /// Analyze the container info of the doc
938    ///
939    /// This is used for development and debugging. It can be slow.
940    pub fn analyze(&self) -> DocAnalysis {
941        self.doc.analyze()
942    }
943
944    /// Get the path from the root to the container
945    pub fn get_path_to_container(&self, id: &ContainerID) -> Option<Vec<(ContainerID, Index)>> {
946        self.doc.get_path_to_container(id)
947    }
948
949    /// Evaluate a JSONPath expression on the document and return matching values or handlers.
950    ///
951    /// This method allows querying the document structure using JSONPath syntax.
952    /// It returns a vector of `ValueOrHandler` which can represent either primitive values
953    /// or container handlers, depending on what the JSONPath expression matches.
954    ///
955    /// # Arguments
956    ///
957    /// * `path` - A string slice containing the JSONPath expression to evaluate.
958    ///
959    /// # Returns
960    ///
961    /// A `Result` containing either:
962    /// - `Ok(Vec<ValueOrHandler>)`: A vector of matching values or handlers.
963    /// - `Err(String)`: An error message if the JSONPath expression is invalid or evaluation fails.
964    ///
965    /// # Example
966    ///
967    /// ```
968    /// # use loro::{LoroDoc, ToJson};
969    ///
970    /// let doc = LoroDoc::new();
971    /// let map = doc.get_map("users");
972    /// map.insert("alice", 30).unwrap();
973    /// map.insert("bob", 25).unwrap();
974    ///
975    /// let result = doc.jsonpath("$.users.alice").unwrap();
976    /// assert_eq!(result.len(), 1);
977    /// assert_eq!(result[0].as_value().unwrap().to_json_value(), serde_json::json!(30));
978    /// ```
979    #[inline]
980    #[cfg(feature = "jsonpath")]
981    pub fn jsonpath(&self, path: &str) -> Result<Vec<ValueOrContainer>, JsonPathError> {
982        self.doc
983            .jsonpath(path)
984            .map(|vec| vec.into_iter().map(ValueOrContainer::from).collect())
985    }
986
987    /// Get the number of operations in the pending transaction.
988    ///
989    /// The pending transaction is the one that is not committed yet. It will be committed
990    /// after calling `doc.commit()`, `doc.export(mode)` or `doc.checkout(version)`.
991    pub fn get_pending_txn_len(&self) -> usize {
992        self.doc.get_pending_txn_len()
993    }
994
995    /// Traverses the ancestors of the Change containing the given ID, including itself.
996    ///
997    /// This method visits all ancestors in causal order, from the latest to the oldest,
998    /// based on their Lamport timestamps.
999    ///
1000    /// # Arguments
1001    ///
1002    /// * `ids` - The IDs of the Change to start the traversal from.
1003    /// * `f` - A mutable function that is called for each ancestor. It can return `ControlFlow::Break(())` to stop the traversal.
1004    pub fn travel_change_ancestors(
1005        &self,
1006        ids: &[ID],
1007        f: &mut dyn FnMut(ChangeMeta) -> ControlFlow<()>,
1008    ) -> Result<(), ChangeTravelError> {
1009        self.doc.travel_change_ancestors(ids, f)
1010    }
1011
1012    /// Check if the doc contains the full history.
1013    pub fn is_shallow(&self) -> bool {
1014        self.doc.is_shallow()
1015    }
1016
1017    /// Gets container IDs modified in the given ID range.
1018    ///
1019    /// **NOTE:** This method will implicitly commit.
1020    ///
1021    /// This method can be used in conjunction with `doc.travel_change_ancestors()` to traverse
1022    /// the history and identify all changes that affected specific containers.
1023    ///
1024    /// # Arguments
1025    ///
1026    /// * `id` - The starting ID of the change range
1027    /// * `len` - The length of the change range to check
1028    pub fn get_changed_containers_in(&self, id: ID, len: usize) -> FxHashSet<ContainerID> {
1029        self.doc.get_changed_containers_in(id, len)
1030    }
1031
1032    /// Find the operation id spans that between the `from` version and the `to` version.
1033    #[inline]
1034    pub fn find_id_spans_between(&self, from: &Frontiers, to: &Frontiers) -> VersionVectorDiff {
1035        self.doc.find_id_spans_between(from, to)
1036    }
1037
1038    /// Revert the current document state back to the target version
1039    ///
1040    /// Internally, it will generate a series of local operations that can revert the
1041    /// current doc to the target version. It will calculate the diff between the current
1042    /// state and the target state, and apply the diff to the current state.
1043    #[inline]
1044    pub fn revert_to(&self, version: &Frontiers) -> LoroResult<()> {
1045        self.doc.revert_to(version)
1046    }
1047
1048    /// Apply a diff to the current document state.
1049    ///
1050    /// Internally, it will apply the diff to the current state.
1051    #[inline]
1052    pub fn apply_diff(&self, diff: DiffBatch) -> LoroResult<()> {
1053        self.doc.apply_diff(diff.into())
1054    }
1055
1056    /// Calculate the diff between two versions
1057    #[inline]
1058    pub fn diff(&self, a: &Frontiers, b: &Frontiers) -> LoroResult<DiffBatch> {
1059        self.doc.diff(a, b).map(|x| x.into())
1060    }
1061
1062    /// Check if the doc contains the target container.
1063    ///
1064    /// A root container always exists, while a normal container exists
1065    /// if it has ever been created on the doc.
1066    ///
1067    /// # Examples
1068    /// ```
1069    /// use loro::{LoroDoc, LoroText, LoroList, ExportMode};
1070    ///
1071    /// let doc = LoroDoc::new();
1072    /// doc.set_peer_id(1);
1073    /// let map = doc.get_map("map");
1074    /// map.insert_container("text", LoroText::new()).unwrap();
1075    /// map.insert_container("list", LoroList::new()).unwrap();
1076    ///
1077    /// // Root map container exists
1078    /// assert!(doc.has_container(&"cid:root-map:Map".try_into().unwrap()));
1079    /// // Text container exists
1080    /// assert!(doc.has_container(&"cid:0@1:Text".try_into().unwrap()));
1081    /// // List container exists  
1082    /// assert!(doc.has_container(&"cid:1@1:List".try_into().unwrap()));
1083    ///
1084    /// let doc2 = LoroDoc::new();
1085    /// // Containers exist as long as the history or doc state includes them
1086    /// doc.detach();
1087    /// doc2.import(&doc.export(ExportMode::all_updates()).unwrap()).unwrap();
1088    /// assert!(doc2.has_container(&"cid:root-map:Map".try_into().unwrap()));
1089    /// assert!(doc2.has_container(&"cid:0@1:Text".try_into().unwrap()));
1090    /// assert!(doc2.has_container(&"cid:1@1:List".try_into().unwrap()));
1091    /// ```
1092    pub fn has_container(&self, container_id: &ContainerID) -> bool {
1093        self.doc.has_container(container_id)
1094    }
1095
1096    /// Subscribe to the first commit from a peer. Operations performed on the `LoroDoc` within this callback
1097    /// will be merged into the current commit.
1098    ///
1099    /// This is useful for managing the relationship between `PeerID` and user information.
1100    /// For example, you could store user names in a `LoroMap` using `PeerID` as the key and the `UserID` as the value.
1101    ///
1102    /// # Example
1103    /// ```
1104    /// use loro::LoroDoc;
1105    /// use std::sync::{Arc, Mutex};
1106    ///
1107    /// let doc = LoroDoc::new();
1108    /// doc.set_peer_id(0).unwrap();
1109    /// let p = Arc::new(Mutex::new(vec![]));
1110    /// let p2 = Arc::clone(&p);
1111    /// let sub = doc.subscribe_first_commit_from_peer(Box::new(move |e| {
1112    ///     p2.try_lock().unwrap().push(e.peer);
1113    ///     true
1114    /// }));
1115    /// doc.get_text("text").insert(0, "a").unwrap();
1116    /// doc.commit();
1117    /// doc.get_text("text").insert(0, "b").unwrap();
1118    /// doc.commit();
1119    /// doc.set_peer_id(1).unwrap();
1120    /// doc.get_text("text").insert(0, "c").unwrap();
1121    /// doc.commit();
1122    /// sub.unsubscribe();
1123    /// assert_eq!(p.try_lock().unwrap().as_slice(), &[0, 1]);
1124    /// ```
1125    pub fn subscribe_first_commit_from_peer(
1126        &self,
1127        callback: FirstCommitFromPeerCallback,
1128    ) -> Subscription {
1129        self.doc.subscribe_first_commit_from_peer(callback)
1130    }
1131
1132    /// Subscribe to the pre-commit event.
1133    ///
1134    /// The callback will be called when the changes are committed but not yet applied to the OpLog.
1135    /// You can modify the commit message and timestamp in the callback by [`ChangeModifier`].
1136    ///
1137    /// # Example
1138    /// ```rust
1139    /// use loro::LoroDoc;
1140    ///
1141    /// let doc = LoroDoc::new();
1142    /// let doc_clone = doc.clone();
1143    /// let sub = doc.subscribe_pre_commit(Box::new(move |e| {
1144    ///     e.modifier
1145    ///      .set_timestamp(e.change_meta.timestamp + 1)
1146    ///      .set_message(&format!("prefix\n{}", e.change_meta.message()));
1147    ///     true
1148    /// }));
1149    /// doc.get_text("text").insert(0, "a").unwrap();
1150    /// doc.commit();
1151    /// ```
1152    pub fn subscribe_pre_commit(&self, callback: PreCommitCallback) -> Subscription {
1153        self.doc.subscribe_pre_commit(callback)
1154    }
1155}
1156
1157/// It's used to prevent the user from implementing the trait directly.
1158#[allow(private_bounds)]
1159trait SealedTrait {}
1160
1161/// The common trait for all the containers.
1162/// It's used internally, you can't implement it directly.
1163#[allow(private_bounds)]
1164pub trait ContainerTrait: SealedTrait {
1165    /// The handler of the container.
1166    type Handler: HandlerTrait;
1167    /// Convert the container to a [Container].
1168    fn to_container(&self) -> Container;
1169    /// Convert the container to a handler.
1170    fn to_handler(&self) -> Self::Handler;
1171    /// Convert the handler to a container.
1172    fn from_handler(handler: Self::Handler) -> Self;
1173    /// Try to convert the container to the handler.
1174    fn try_from_container(container: Container) -> Option<Self>
1175    where
1176        Self: Sized;
1177    /// Whether the container is attached to a document.
1178    fn is_attached(&self) -> bool;
1179    /// If a detached container is attached, this method will return its corresponding attached handler.
1180    fn get_attached(&self) -> Option<Self>
1181    where
1182        Self: Sized;
1183    /// Whether the container is deleted.
1184    fn is_deleted(&self) -> bool;
1185    /// Get the doc of the container.
1186    fn doc(&self) -> Option<LoroDoc>;
1187}
1188
1189/// LoroList container. It's used to model array.
1190///
1191/// It can have sub containers.
1192///
1193/// ```
1194/// # use loro::{LoroDoc, ContainerType, ToJson};
1195/// # use serde_json::json;
1196/// let doc = LoroDoc::new();
1197/// let list = doc.get_list("list");
1198/// list.insert(0, 123).unwrap();
1199/// list.insert(1, "h").unwrap();
1200/// assert_eq!(
1201///     doc.get_deep_value().to_json_value(),
1202///     json!({
1203///         "list": [123, "h"]
1204///     })
1205/// );
1206/// ```
1207#[derive(Clone, Debug)]
1208pub struct LoroList {
1209    handler: InnerListHandler,
1210}
1211
1212impl SealedTrait for LoroList {}
1213impl ContainerTrait for LoroList {
1214    type Handler = InnerListHandler;
1215    fn to_container(&self) -> Container {
1216        Container::List(self.clone())
1217    }
1218
1219    fn to_handler(&self) -> Self::Handler {
1220        self.handler.clone()
1221    }
1222
1223    fn from_handler(handler: Self::Handler) -> Self {
1224        Self { handler }
1225    }
1226
1227    fn is_attached(&self) -> bool {
1228        self.handler.is_attached()
1229    }
1230
1231    fn get_attached(&self) -> Option<Self> {
1232        self.handler.get_attached().map(Self::from_handler)
1233    }
1234
1235    fn try_from_container(container: Container) -> Option<Self> {
1236        container.into_list().ok()
1237    }
1238
1239    fn is_deleted(&self) -> bool {
1240        self.handler.is_deleted()
1241    }
1242
1243    fn doc(&self) -> Option<LoroDoc> {
1244        self.handler.doc().map(LoroDoc::_new)
1245    }
1246}
1247
1248impl LoroList {
1249    /// Create a new container that is detached from the document.
1250    ///
1251    /// The edits on a detached container will not be persisted.
1252    /// To attach the container to the document, please insert it into an attached container.
1253    pub fn new() -> Self {
1254        Self {
1255            handler: InnerListHandler::new_detached(),
1256        }
1257    }
1258
1259    /// Whether the container is attached to a document
1260    ///
1261    /// The edits on a detached container will not be persisted.
1262    /// To attach the container to the document, please insert it into an attached container.
1263    pub fn is_attached(&self) -> bool {
1264        self.handler.is_attached()
1265    }
1266
1267    /// Insert a value at the given position.
1268    pub fn insert(&self, pos: usize, v: impl Into<LoroValue>) -> LoroResult<()> {
1269        self.handler.insert(pos, v)
1270    }
1271
1272    /// Delete values at the given position.
1273    #[inline]
1274    pub fn delete(&self, pos: usize, len: usize) -> LoroResult<()> {
1275        self.handler.delete(pos, len)
1276    }
1277
1278    /// Get the value at the given position.
1279    #[inline]
1280    pub fn get(&self, index: usize) -> Option<ValueOrContainer> {
1281        self.handler.get_(index).map(ValueOrContainer::from)
1282    }
1283
1284    /// Get the deep value of the container.
1285    #[inline]
1286    pub fn get_deep_value(&self) -> LoroValue {
1287        self.handler.get_deep_value()
1288    }
1289
1290    /// Get the shallow value of the container.
1291    ///
1292    /// This does not convert the state of sub-containers; instead, it represents them as [LoroValue::Container].
1293    #[inline]
1294    pub fn get_value(&self) -> LoroValue {
1295        self.handler.get_value()
1296    }
1297
1298    /// Get the ID of the container.
1299    #[inline]
1300    pub fn id(&self) -> ContainerID {
1301        self.handler.id().clone()
1302    }
1303
1304    /// Pop the last element of the list.
1305    #[inline]
1306    pub fn pop(&self) -> LoroResult<Option<LoroValue>> {
1307        self.handler.pop()
1308    }
1309
1310    /// Push a value to the list.
1311    #[inline]
1312    pub fn push(&self, v: impl Into<LoroValue>) -> LoroResult<()> {
1313        self.handler.push(v.into())
1314    }
1315
1316    /// Push a container to the list.
1317    #[inline]
1318    pub fn push_container<C: ContainerTrait>(&self, child: C) -> LoroResult<C> {
1319        let pos = self.handler.len();
1320        Ok(C::from_handler(
1321            self.handler.insert_container(pos, child.to_handler())?,
1322        ))
1323    }
1324
1325    /// Iterate over the elements of the list.
1326    pub fn for_each<I>(&self, mut f: I)
1327    where
1328        I: FnMut(ValueOrContainer),
1329    {
1330        self.handler.for_each(&mut |v| {
1331            f(ValueOrContainer::from(v));
1332        })
1333    }
1334
1335    /// Get the length of the list.
1336    #[inline]
1337    pub fn len(&self) -> usize {
1338        self.handler.len()
1339    }
1340
1341    /// Whether the list is empty.
1342    #[inline]
1343    pub fn is_empty(&self) -> bool {
1344        self.handler.is_empty()
1345    }
1346
1347    /// Insert a container with the given type at the given index.
1348    ///
1349    /// # Example
1350    ///
1351    /// ```
1352    /// # use loro::{LoroDoc, ContainerType, LoroText, ToJson};
1353    /// # use serde_json::json;
1354    /// let doc = LoroDoc::new();
1355    /// let list = doc.get_list("m");
1356    /// let text = list.insert_container(0, LoroText::new()).unwrap();
1357    /// text.insert(0, "12");
1358    /// text.insert(0, "0");
1359    /// assert_eq!(doc.get_deep_value().to_json_value(), json!({"m": ["012"]}));
1360    /// ```
1361    #[inline]
1362    pub fn insert_container<C: ContainerTrait>(&self, pos: usize, child: C) -> LoroResult<C> {
1363        Ok(C::from_handler(
1364            self.handler.insert_container(pos, child.to_handler())?,
1365        ))
1366    }
1367
1368    /// Get the cursor at the given position.
1369    ///
1370    /// Using "index" to denote cursor positions can be unstable, as positions may
1371    /// shift with document edits. To reliably represent a position or range within
1372    /// a document, it is more effective to leverage the unique ID of each item/character
1373    /// in a List CRDT or Text CRDT.
1374    ///
1375    /// Loro optimizes State metadata by not storing the IDs of deleted elements. This
1376    /// approach complicates tracking cursors since they rely on these IDs. The solution
1377    /// recalculates position by replaying relevant history to update stable positions
1378    /// accurately. To minimize the performance impact of history replay, the system
1379    /// updates cursor info to reference only the IDs of currently present elements,
1380    /// thereby reducing the need for replay.
1381    ///
1382    /// # Example
1383    ///
1384    /// ```
1385    /// use loro::LoroDoc;
1386    /// use loro_internal::cursor::Side;
1387    ///
1388    /// let doc = LoroDoc::new();
1389    /// let list = doc.get_list("list");
1390    /// list.insert(0, 0).unwrap();
1391    /// let cursor = list.get_cursor(0, Side::Middle).unwrap();
1392    /// assert_eq!(doc.get_cursor_pos(&cursor).unwrap().current.pos, 0);
1393    /// list.insert(0, 0).unwrap();
1394    /// assert_eq!(doc.get_cursor_pos(&cursor).unwrap().current.pos, 1);
1395    /// list.insert(0, 0).unwrap();
1396    /// list.insert(0, 0).unwrap();
1397    /// assert_eq!(doc.get_cursor_pos(&cursor).unwrap().current.pos, 3);
1398    /// list.insert(4, 0).unwrap();
1399    /// assert_eq!(doc.get_cursor_pos(&cursor).unwrap().current.pos, 3);
1400    /// ```
1401    pub fn get_cursor(&self, pos: usize, side: Side) -> Option<Cursor> {
1402        self.handler.get_cursor(pos, side)
1403    }
1404
1405    /// Converts the LoroList to a Vec of LoroValue.
1406    ///
1407    /// This method unwraps the internal Arc and clones the data if necessary,
1408    /// returning a Vec containing all the elements of the LoroList as LoroValue.
1409    ///
1410    /// # Returns
1411    ///
1412    /// A Vec<LoroValue> containing all elements of the LoroList.
1413    ///
1414    /// # Example
1415    ///
1416    /// ```
1417    /// use loro::{LoroDoc, LoroValue};
1418    ///
1419    /// let doc = LoroDoc::new();
1420    /// let list = doc.get_list("my_list");
1421    /// list.insert(0, 1).unwrap();
1422    /// list.insert(1, "hello").unwrap();
1423    /// list.insert(2, true).unwrap();
1424    ///
1425    /// let vec = list.to_vec();
1426    /// ```
1427    pub fn to_vec(&self) -> Vec<LoroValue> {
1428        self.get_value().into_list().unwrap().unwrap()
1429    }
1430
1431    /// Delete all elements in the list.
1432    pub fn clear(&self) -> LoroResult<()> {
1433        self.handler.clear()
1434    }
1435
1436    /// Get the ID of the list item at the given position.
1437    pub fn get_id_at(&self, pos: usize) -> Option<ID> {
1438        self.handler.get_id_at(pos)
1439    }
1440}
1441
1442impl Default for LoroList {
1443    fn default() -> Self {
1444        Self::new()
1445    }
1446}
1447
1448/// LoroMap container.
1449///
1450/// It's LWW(Last-Write-Win) Map. It can support Multi-Value Map in the future.
1451///
1452/// # Example
1453/// ```
1454/// # use loro::{LoroDoc, ToJson, ExpandType, LoroText, LoroValue};
1455/// # use serde_json::json;
1456/// let doc = LoroDoc::new();
1457/// let map = doc.get_map("map");
1458/// map.insert("key", "value").unwrap();
1459/// map.insert("true", true).unwrap();
1460/// map.insert("null", LoroValue::Null).unwrap();
1461/// map.insert("deleted", LoroValue::Null).unwrap();
1462/// map.delete("deleted").unwrap();
1463/// let text = map
1464///    .insert_container("text", LoroText::new()).unwrap();
1465/// text.insert(0, "Hello world!").unwrap();
1466/// assert_eq!(
1467///     doc.get_deep_value().to_json_value(),
1468///     json!({
1469///        "map": {
1470///            "key": "value",
1471///            "true": true,
1472///            "null": null,
1473///            "text": "Hello world!"
1474///        }
1475///    })
1476/// );
1477/// ```
1478#[derive(Clone, Debug)]
1479pub struct LoroMap {
1480    handler: InnerMapHandler,
1481}
1482
1483impl SealedTrait for LoroMap {}
1484impl ContainerTrait for LoroMap {
1485    type Handler = InnerMapHandler;
1486
1487    fn to_container(&self) -> Container {
1488        Container::Map(self.clone())
1489    }
1490
1491    fn to_handler(&self) -> Self::Handler {
1492        self.handler.clone()
1493    }
1494
1495    fn from_handler(handler: Self::Handler) -> Self {
1496        Self { handler }
1497    }
1498
1499    fn is_attached(&self) -> bool {
1500        self.handler.is_attached()
1501    }
1502
1503    fn get_attached(&self) -> Option<Self> {
1504        self.handler.get_attached().map(Self::from_handler)
1505    }
1506
1507    fn try_from_container(container: Container) -> Option<Self> {
1508        container.into_map().ok()
1509    }
1510
1511    fn is_deleted(&self) -> bool {
1512        self.handler.is_deleted()
1513    }
1514
1515    fn doc(&self) -> Option<LoroDoc> {
1516        self.handler.doc().map(LoroDoc::_new)
1517    }
1518}
1519
1520impl LoroMap {
1521    /// Create a new container that is detached from the document.
1522    ///
1523    /// The edits on a detached container will not be persisted.
1524    /// To attach the container to the document, please insert it into an attached container.
1525    pub fn new() -> Self {
1526        Self {
1527            handler: InnerMapHandler::new_detached(),
1528        }
1529    }
1530
1531    /// Whether the container is attached to a document.
1532    pub fn is_attached(&self) -> bool {
1533        self.handler.is_attached()
1534    }
1535
1536    /// Delete a key-value pair from the map.
1537    pub fn delete(&self, key: &str) -> LoroResult<()> {
1538        self.handler.delete(key)
1539    }
1540
1541    /// Iterate over the key-value pairs of the map.
1542    pub fn for_each<I>(&self, mut f: I)
1543    where
1544        I: FnMut(&str, ValueOrContainer),
1545    {
1546        self.handler.for_each(|k, v| {
1547            f(k, ValueOrContainer::from(v));
1548        })
1549    }
1550
1551    /// Insert a key-value pair into the map.
1552    ///
1553    /// > **Note**: When calling `map.set(key, value)` on a LoroMap, if `map.get(key)` already returns `value`,
1554    /// > the operation will be a no-op (no operation recorded) to avoid unnecessary updates.
1555    pub fn insert(&self, key: &str, value: impl Into<LoroValue>) -> LoroResult<()> {
1556        self.handler.insert(key, value)
1557    }
1558
1559    /// Get the length of the map.
1560    pub fn len(&self) -> usize {
1561        self.handler.len()
1562    }
1563
1564    /// Get the ID of the map.
1565    pub fn id(&self) -> ContainerID {
1566        self.handler.id().clone()
1567    }
1568
1569    /// Whether the map is empty.
1570    pub fn is_empty(&self) -> bool {
1571        self.handler.is_empty()
1572    }
1573
1574    /// Get the value of the map with the given key.
1575    pub fn get(&self, key: &str) -> Option<ValueOrContainer> {
1576        self.handler.get_(key).map(ValueOrContainer::from)
1577    }
1578
1579    /// Insert a container with the given type at the given key.
1580    ///
1581    /// # Example
1582    ///
1583    /// ```
1584    /// # use loro::{LoroDoc, LoroText, ContainerType, ToJson};
1585    /// # use serde_json::json;
1586    /// let doc = LoroDoc::new();
1587    /// let map = doc.get_map("m");
1588    /// let text = map.insert_container("t", LoroText::new()).unwrap();
1589    /// text.insert(0, "12");
1590    /// text.insert(0, "0");
1591    /// assert_eq!(doc.get_deep_value().to_json_value(), json!({"m": {"t": "012"}}));
1592    /// ```
1593    pub fn insert_container<C: ContainerTrait>(&self, key: &str, child: C) -> LoroResult<C> {
1594        Ok(C::from_handler(
1595            self.handler.insert_container(key, child.to_handler())?,
1596        ))
1597    }
1598
1599    /// Get the shallow value of the map.
1600    ///
1601    /// It will not convert the state of sub-containers, but represent them as [LoroValue::Container].
1602    pub fn get_value(&self) -> LoroValue {
1603        self.handler.get_value()
1604    }
1605
1606    /// Get the deep value of the map.
1607    ///
1608    /// It will convert the state of sub-containers into a nested JSON value.
1609    pub fn get_deep_value(&self) -> LoroValue {
1610        self.handler.get_deep_value()
1611    }
1612
1613    /// Get or create a container with the given key.
1614    pub fn get_or_create_container<C: ContainerTrait>(&self, key: &str, child: C) -> LoroResult<C> {
1615        Ok(C::from_handler(
1616            self.handler
1617                .get_or_create_container(key, child.to_handler())?,
1618        ))
1619    }
1620
1621    /// Delete all key-value pairs in the map.
1622    pub fn clear(&self) -> LoroResult<()> {
1623        self.handler.clear()
1624    }
1625
1626    /// Get the keys of the map.
1627    pub fn keys(&self) -> impl Iterator<Item = InternalString> + '_ {
1628        self.handler.keys()
1629    }
1630
1631    /// Get the values of the map.
1632    pub fn values(&self) -> impl Iterator<Item = ValueOrContainer> + '_ {
1633        self.handler.values().map(ValueOrContainer::from)
1634    }
1635
1636    /// Get the peer id of the last editor on the given entry
1637    pub fn get_last_editor(&self, key: &str) -> Option<PeerID> {
1638        self.handler.get_last_editor(key)
1639    }
1640}
1641
1642impl Default for LoroMap {
1643    fn default() -> Self {
1644        Self::new()
1645    }
1646}
1647
1648/// LoroText container. It's used to model plaintext/richtext.
1649#[derive(Clone, Debug)]
1650pub struct LoroText {
1651    handler: InnerTextHandler,
1652}
1653
1654impl SealedTrait for LoroText {}
1655impl ContainerTrait for LoroText {
1656    type Handler = InnerTextHandler;
1657
1658    fn to_container(&self) -> Container {
1659        Container::Text(self.clone())
1660    }
1661
1662    fn to_handler(&self) -> Self::Handler {
1663        self.handler.clone()
1664    }
1665
1666    fn from_handler(handler: Self::Handler) -> Self {
1667        Self { handler }
1668    }
1669
1670    fn is_attached(&self) -> bool {
1671        self.handler.is_attached()
1672    }
1673
1674    fn get_attached(&self) -> Option<Self> {
1675        self.handler.get_attached().map(Self::from_handler)
1676    }
1677
1678    fn try_from_container(container: Container) -> Option<Self> {
1679        container.into_text().ok()
1680    }
1681
1682    fn is_deleted(&self) -> bool {
1683        self.handler.is_deleted()
1684    }
1685
1686    fn doc(&self) -> Option<LoroDoc> {
1687        self.handler.doc().map(LoroDoc::_new)
1688    }
1689}
1690
1691impl LoroText {
1692    /// Create a new container that is detached from the document.
1693    ///
1694    /// The edits on a detached container will not be persisted.
1695    /// To attach the container to the document, please insert it into an attached container.
1696    pub fn new() -> Self {
1697        Self {
1698            handler: InnerTextHandler::new_detached(),
1699        }
1700    }
1701
1702    /// Whether the container is attached to a document
1703    ///
1704    /// The edits on a detached container will not be persisted.
1705    /// To attach the container to the document, please insert it into an attached container.
1706    pub fn is_attached(&self) -> bool {
1707        self.handler.is_attached()
1708    }
1709
1710    /// Get the [ContainerID]  of the text container.
1711    pub fn id(&self) -> ContainerID {
1712        self.handler.id().clone()
1713    }
1714
1715    /// Iterate each span(internal storage unit) of the text.
1716    ///
1717    /// The callback function will be called for each character in the text.
1718    /// If the callback returns `false`, the iteration will stop.
1719    ///
1720    /// Limitation: you cannot access or alter the doc state when iterating.
1721    /// If you need to access or alter the doc state, please use `to_string` instead.
1722    pub fn iter(&self, callback: impl FnMut(&str) -> bool) {
1723        self.handler.iter(callback);
1724    }
1725
1726    /// Insert a string at the given unicode position.
1727    pub fn insert(&self, pos: usize, s: &str) -> LoroResult<()> {
1728        self.handler.insert_unicode(pos, s)
1729    }
1730
1731    /// Insert a string at the given utf-8 position.
1732    pub fn insert_utf8(&self, pos: usize, s: &str) -> LoroResult<()> {
1733        self.handler.insert_utf8(pos, s)
1734    }
1735
1736    /// Delete a range of text at the given unicode position with unicode length.
1737    pub fn delete(&self, pos: usize, len: usize) -> LoroResult<()> {
1738        self.handler.delete_unicode(pos, len)
1739    }
1740
1741    /// Delete a range of text at the given utf-8 position with utf-8 length.
1742    pub fn delete_utf8(&self, pos: usize, len: usize) -> LoroResult<()> {
1743        self.handler.delete_utf8(pos, len)
1744    }
1745
1746    /// Get a string slice at the given Unicode range
1747    pub fn slice(&self, start_index: usize, end_index: usize) -> LoroResult<String> {
1748        self.handler.slice(start_index, end_index)
1749    }
1750
1751    /// Get the characters at given unicode position.
1752    pub fn char_at(&self, pos: usize) -> LoroResult<char> {
1753        self.handler.char_at(pos)
1754    }
1755
1756    /// Delete specified character and insert string at the same position at given unicode position.
1757    pub fn splice(&self, pos: usize, len: usize, s: &str) -> LoroResult<String> {
1758        self.handler.splice(pos, len, s)
1759    }
1760
1761    /// Whether the text container is empty.
1762    pub fn is_empty(&self) -> bool {
1763        self.handler.is_empty()
1764    }
1765
1766    /// Get the length of the text container in UTF-8.
1767    pub fn len_utf8(&self) -> usize {
1768        self.handler.len_utf8()
1769    }
1770
1771    /// Get the length of the text container in Unicode.
1772    pub fn len_unicode(&self) -> usize {
1773        self.handler.len_unicode()
1774    }
1775
1776    /// Get the length of the text container in UTF-16.
1777    pub fn len_utf16(&self) -> usize {
1778        self.handler.len_utf16()
1779    }
1780
1781    /// Update the current text based on the provided text.
1782    ///
1783    /// It will calculate the minimal difference and apply it to the current text.
1784    /// It uses Myers' diff algorithm to compute the optimal difference.
1785    ///
1786    /// This could take a long time for large texts (e.g. > 50_000 characters).
1787    /// In that case, you should use `updateByLine` instead.
1788    ///
1789    /// # Example
1790    /// ```rust
1791    /// use loro::LoroDoc;
1792    ///
1793    /// let doc = LoroDoc::new();
1794    /// let text = doc.get_text("text");
1795    /// text.insert(0, "Hello").unwrap();
1796    /// text.update("Hello World", Default::default()).unwrap();
1797    /// assert_eq!(text.to_string(), "Hello World");
1798    /// ```
1799    ///
1800    pub fn update(&self, text: &str, options: UpdateOptions) -> Result<(), UpdateTimeoutError> {
1801        self.handler.update(text, options)
1802    }
1803
1804    /// Update the current text based on the provided text.
1805    ///
1806    /// This update calculation is line-based, which will be more efficient but less precise.
1807    pub fn update_by_line(
1808        &self,
1809        text: &str,
1810        options: UpdateOptions,
1811    ) -> Result<(), UpdateTimeoutError> {
1812        self.handler.update_by_line(text, options)
1813    }
1814
1815    /// Apply a [delta](https://quilljs.com/docs/delta/) to the text container.
1816    pub fn apply_delta(&self, delta: &[TextDelta]) -> LoroResult<()> {
1817        self.handler.apply_delta(delta)
1818    }
1819
1820    /// Mark a range of text with a key-value pair.
1821    ///
1822    /// You can use it to create a highlight, make a range of text bold, or add a link to a range of text.
1823    ///
1824    /// You can specify the `expand` option to set the behavior when inserting text at the boundary of the range.
1825    ///
1826    /// - `after`(default): when inserting text right after the given range, the mark will be expanded to include the inserted text
1827    /// - `before`: when inserting text right before the given range, the mark will be expanded to include the inserted text
1828    /// - `none`: the mark will not be expanded to include the inserted text at the boundaries
1829    /// - `both`: when inserting text either right before or right after the given range, the mark will be expanded to include the inserted text
1830    ///
1831    /// *You should make sure that a key is always associated with the same expand type.*
1832    pub fn mark(
1833        &self,
1834        range: Range<usize>,
1835        key: &str,
1836        value: impl Into<LoroValue>,
1837    ) -> LoroResult<()> {
1838        self.handler.mark(range.start, range.end, key, value.into())
1839    }
1840
1841    /// Unmark a range of text with a key and a value.
1842    ///
1843    /// You can use it to remove highlights, bolds or links
1844    ///
1845    /// You can specify the `expand` option to set the behavior when inserting text at the boundary of the range.
1846    ///
1847    /// **Note: You should specify the same expand type as when you mark the text.**
1848    ///
1849    /// - `after`(default): when inserting text right after the given range, the mark will be expanded to include the inserted text
1850    /// - `before`: when inserting text right before the given range, the mark will be expanded to include the inserted text
1851    /// - `none`: the mark will not be expanded to include the inserted text at the boundaries
1852    /// - `both`: when inserting text either right before or right after the given range, the mark will be expanded to include the inserted text
1853    ///
1854    /// *You should make sure that a key is always associated with the same expand type.*
1855    ///
1856    /// Note: you cannot delete unmergeable annotations like comments by this method.
1857    pub fn unmark(&self, range: Range<usize>, key: &str) -> LoroResult<()> {
1858        self.handler.unmark(range.start, range.end, key)
1859    }
1860
1861    /// Get the text in [Delta](https://quilljs.com/docs/delta/) format.
1862    ///
1863    /// # Example
1864    /// ```
1865    /// use loro::{LoroDoc, ToJson, ExpandType, TextDelta};
1866    /// use serde_json::json;
1867    /// use fxhash::FxHashMap;
1868    ///
1869    /// let doc = LoroDoc::new();
1870    /// let text = doc.get_text("text");
1871    /// text.insert(0, "Hello world!").unwrap();
1872    /// text.mark(0..5, "bold", true).unwrap();
1873    /// assert_eq!(
1874    ///     text.to_delta(),
1875    ///     vec![
1876    ///         TextDelta::Insert {
1877    ///             insert: "Hello".to_string(),
1878    ///             attributes: Some(FxHashMap::from_iter([("bold".to_string(), true.into())])),
1879    ///         },
1880    ///         TextDelta::Insert {
1881    ///             insert: " world!".to_string(),
1882    ///             attributes: None,
1883    ///         },
1884    ///     ]
1885    /// );
1886    /// text.unmark(3..5, "bold").unwrap();
1887    /// assert_eq!(
1888    ///     text.to_delta(),
1889    ///     vec![
1890    ///         TextDelta::Insert {
1891    ///             insert: "Hel".to_string(),
1892    ///             attributes: Some(FxHashMap::from_iter([("bold".to_string(), true.into())])),
1893    ///         },
1894    ///         TextDelta::Insert {
1895    ///             insert: "lo world!".to_string(),
1896    ///             attributes: None,
1897    ///         },
1898    ///     ]
1899    /// );
1900    /// ```
1901    pub fn to_delta(&self) -> Vec<TextDelta> {
1902        let delta = self.handler.get_richtext_value().into_list().unwrap();
1903        delta
1904            .iter()
1905            .map(|x| {
1906                let map = x.as_map().unwrap();
1907                let insert = map.get("insert").unwrap().as_string().unwrap().to_string();
1908                let attributes = map
1909                    .get("attributes")
1910                    .map(|v| v.as_map().unwrap().deref().clone());
1911                TextDelta::Insert { insert, attributes }
1912            })
1913            .collect()
1914    }
1915
1916    /// Get the rich text value in [Delta](https://quilljs.com/docs/delta/) format.
1917    ///
1918    /// # Example
1919    /// ```
1920    /// # use loro::{LoroDoc, ToJson, ExpandType, TextDelta};
1921    /// # use serde_json::json;
1922    ///
1923    /// let doc = LoroDoc::new();
1924    /// let text = doc.get_text("text");
1925    /// text.insert(0, "Hello world!").unwrap();
1926    /// text.mark(0..5, "bold", true).unwrap();
1927    /// assert_eq!(
1928    ///     text.get_richtext_value().to_json_value(),
1929    ///     json!([
1930    ///         { "insert": "Hello", "attributes": {"bold": true} },
1931    ///         { "insert": " world!" },
1932    ///     ])
1933    /// );
1934    /// text.unmark(3..5, "bold").unwrap();
1935    /// assert_eq!(
1936    ///     text.get_richtext_value().to_json_value(),
1937    ///     json!([
1938    ///         { "insert": "Hel", "attributes": {"bold": true} },
1939    ///         { "insert": "lo world!" },
1940    ///    ])
1941    /// );
1942    /// ```
1943    pub fn get_richtext_value(&self) -> LoroValue {
1944        self.handler.get_richtext_value()
1945    }
1946
1947    /// Get the text content of the text container.
1948    #[allow(clippy::inherent_to_string)]
1949    pub fn to_string(&self) -> String {
1950        self.handler.to_string()
1951    }
1952
1953    /// Get the cursor at the given position in the given Unicode position.
1954    ///
1955    /// Using "index" to denote cursor positions can be unstable, as positions may
1956    /// shift with document edits. To reliably represent a position or range within
1957    /// a document, it is more effective to leverage the unique ID of each item/character
1958    /// in a List CRDT or Text CRDT.
1959    ///
1960    /// Loro optimizes State metadata by not storing the IDs of deleted elements. This
1961    /// approach complicates tracking cursors since they rely on these IDs. The solution
1962    /// recalculates position by replaying relevant history to update stable positions
1963    /// accurately. To minimize the performance impact of history replay, the system
1964    /// updates cursor info to reference only the IDs of currently present elements,
1965    /// thereby reducing the need for replay.
1966    ///
1967    /// # Example
1968    ///
1969    /// ```
1970    /// # use loro::{LoroDoc, ToJson};
1971    /// let doc = LoroDoc::new();
1972    /// let text = &doc.get_text("text");
1973    /// text.insert(0, "01234").unwrap();
1974    /// let pos = text.get_cursor(5, Default::default()).unwrap();
1975    /// assert_eq!(doc.get_cursor_pos(&pos).unwrap().current.pos, 5);
1976    /// text.insert(0, "01234").unwrap();
1977    /// assert_eq!(doc.get_cursor_pos(&pos).unwrap().current.pos, 10);
1978    /// text.delete(0, 10).unwrap();
1979    /// assert_eq!(doc.get_cursor_pos(&pos).unwrap().current.pos, 0);
1980    /// text.insert(0, "01234").unwrap();
1981    /// assert_eq!(doc.get_cursor_pos(&pos).unwrap().current.pos, 5);
1982    /// ```
1983    pub fn get_cursor(&self, pos: usize, side: Side) -> Option<Cursor> {
1984        self.handler.get_cursor(pos, side)
1985    }
1986
1987    /// Whether the text container is deleted.
1988    pub fn is_deleted(&self) -> bool {
1989        self.handler.is_deleted()
1990    }
1991
1992    /// Push a string to the end of the text container.
1993    pub fn push_str(&self, s: &str) -> LoroResult<()> {
1994        self.handler.push_str(s)
1995    }
1996
1997    /// Get the editor of the text at the given position.
1998    pub fn get_editor_at_unicode_pos(&self, pos: usize) -> Option<PeerID> {
1999        self.handler
2000            .get_cursor(pos, Side::Middle)
2001            .map(|x| x.id.unwrap().peer)
2002    }
2003}
2004
2005impl Default for LoroText {
2006    fn default() -> Self {
2007        Self::new()
2008    }
2009}
2010
2011/// LoroTree container. It's used to model movable trees.
2012///
2013/// You may use it to model directories, outline or other movable hierarchical data.
2014///
2015/// Learn more at https://loro.dev/docs/tutorial/tree
2016#[derive(Clone, Debug)]
2017pub struct LoroTree {
2018    handler: InnerTreeHandler,
2019}
2020
2021impl SealedTrait for LoroTree {}
2022impl ContainerTrait for LoroTree {
2023    type Handler = InnerTreeHandler;
2024
2025    fn to_container(&self) -> Container {
2026        Container::Tree(self.clone())
2027    }
2028
2029    fn to_handler(&self) -> Self::Handler {
2030        self.handler.clone()
2031    }
2032
2033    fn from_handler(handler: Self::Handler) -> Self {
2034        Self { handler }
2035    }
2036
2037    fn is_attached(&self) -> bool {
2038        self.handler.is_attached()
2039    }
2040
2041    fn get_attached(&self) -> Option<Self> {
2042        self.handler.get_attached().map(Self::from_handler)
2043    }
2044
2045    fn try_from_container(container: Container) -> Option<Self> {
2046        container.into_tree().ok()
2047    }
2048
2049    fn is_deleted(&self) -> bool {
2050        self.handler.is_deleted()
2051    }
2052    fn doc(&self) -> Option<LoroDoc> {
2053        self.handler.doc().map(LoroDoc::_new)
2054    }
2055}
2056
2057/// A tree node in the [LoroTree].
2058#[derive(Debug, Clone)]
2059pub struct TreeNode {
2060    /// ID of the tree node.
2061    pub id: TreeID,
2062    /// ID of the parent tree node.
2063    /// If the node is deleted this value is TreeParentId::Deleted.
2064    /// If you checkout to a version before the node is created, this value is TreeParentId::Unexist.
2065    pub parent: TreeParentId,
2066    /// Fraction index of the node
2067    pub fractional_index: FractionalIndex,
2068    /// The current index of the node in its parent's children list.
2069    pub index: usize,
2070}
2071
2072impl LoroTree {
2073    /// Create a new container that is detached from the document.
2074    ///
2075    /// The edits on a detached container will not be persisted.
2076    /// To attach the container to the document, please insert it into an attached container.
2077    pub fn new() -> Self {
2078        Self {
2079            handler: InnerTreeHandler::new_detached(),
2080        }
2081    }
2082
2083    /// Whether the container is attached to a document
2084    ///
2085    /// The edits on a detached container will not be persisted.
2086    /// To attach the container to the document, please insert it into an attached container.
2087    pub fn is_attached(&self) -> bool {
2088        self.handler.is_attached()
2089    }
2090
2091    /// Create a new tree node and return the [`TreeID`].
2092    ///
2093    /// If the `parent` is `None`, the created node is the root of a tree.
2094    /// Otherwise, the created node is a child of the parent tree node.
2095    ///
2096    /// # Example
2097    ///
2098    /// ```rust
2099    /// use loro::LoroDoc;
2100    ///
2101    /// let doc = LoroDoc::new();
2102    /// let tree = doc.get_tree("tree");
2103    /// // create a root
2104    /// let root = tree.create(None).unwrap();
2105    /// // create a new child
2106    /// let child = tree.create(root).unwrap();
2107    /// ```
2108    pub fn create<T: Into<TreeParentId>>(&self, parent: T) -> LoroResult<TreeID> {
2109        self.handler.create(parent.into())
2110    }
2111
2112    /// Get the root nodes of the forest.
2113    pub fn roots(&self) -> Vec<TreeID> {
2114        self.handler.roots()
2115    }
2116
2117    /// Create a new tree node at the given index and return the [`TreeID`].
2118    ///
2119    /// If the `parent` is `None`, the created node is the root of a tree.
2120    /// If the `index` is greater than the number of children of the parent, error will be returned.
2121    ///
2122    /// # Example
2123    ///
2124    /// ```rust
2125    /// use loro::LoroDoc;
2126    ///
2127    /// let doc = LoroDoc::new();
2128    /// let tree = doc.get_tree("tree");
2129    /// // enable generate fractional index
2130    /// tree.enable_fractional_index(0);
2131    /// // create a root
2132    /// let root = tree.create(None).unwrap();
2133    /// // create a new child at index 0
2134    /// let child = tree.create_at(root, 0).unwrap();
2135    /// ```
2136    pub fn create_at<T: Into<TreeParentId>>(&self, parent: T, index: usize) -> LoroResult<TreeID> {
2137        if !self.handler.is_fractional_index_enabled() {
2138            return Err(LoroTreeError::FractionalIndexNotEnabled.into());
2139        }
2140        self.handler.create_at(parent.into(), index)
2141    }
2142
2143    /// Move the `target` node to be a child of the `parent` node.
2144    ///
2145    /// If the `parent` is `None`, the `target` node will be a root.
2146    ///
2147    /// # Example
2148    ///
2149    /// ```rust
2150    /// use loro::LoroDoc;
2151    ///
2152    /// let doc = LoroDoc::new();
2153    /// let tree = doc.get_tree("tree");
2154    /// let root = tree.create(None).unwrap();
2155    /// let root2 = tree.create(None).unwrap();
2156    /// // move `root2` to be a child of `root`.
2157    /// tree.mov(root2, root).unwrap();
2158    /// ```
2159    pub fn mov<T: Into<TreeParentId>>(&self, target: TreeID, parent: T) -> LoroResult<()> {
2160        self.handler.mov(target, parent.into())
2161    }
2162
2163    /// Move the `target` node to be a child of the `parent` node at the given index.
2164    /// If the `parent` is `None`, the `target` node will be a root.
2165    ///
2166    /// # Example
2167    ///
2168    /// ```rust
2169    /// use loro::LoroDoc;
2170    ///
2171    /// let doc = LoroDoc::new();
2172    /// let tree = doc.get_tree("tree");
2173    /// // enable generate fractional index
2174    /// tree.enable_fractional_index(0);
2175    /// let root = tree.create(None).unwrap();
2176    /// let root2 = tree.create(None).unwrap();
2177    /// // move `root2` to be a child of `root` at index 0.
2178    /// tree.mov_to(root2, root, 0).unwrap();
2179    /// ```
2180    pub fn mov_to<T: Into<TreeParentId>>(
2181        &self,
2182        target: TreeID,
2183        parent: T,
2184        to: usize,
2185    ) -> LoroResult<()> {
2186        if !self.handler.is_fractional_index_enabled() {
2187            return Err(LoroTreeError::FractionalIndexNotEnabled.into());
2188        }
2189        self.handler.move_to(target, parent.into(), to)
2190    }
2191
2192    /// Move the `target` node to be a child after the `after` node with the same parent.
2193    ///
2194    /// # Example
2195    ///
2196    /// ```rust
2197    /// use loro::LoroDoc;
2198    ///
2199    /// let doc = LoroDoc::new();
2200    /// let tree = doc.get_tree("tree");
2201    /// // enable generate fractional index
2202    /// tree.enable_fractional_index(0);
2203    /// let root = tree.create(None).unwrap();
2204    /// let root2 = tree.create(None).unwrap();
2205    /// // move `root` to be a child after `root2`.
2206    /// tree.mov_after(root, root2).unwrap();
2207    /// ```
2208    pub fn mov_after(&self, target: TreeID, after: TreeID) -> LoroResult<()> {
2209        if !self.handler.is_fractional_index_enabled() {
2210            return Err(LoroTreeError::FractionalIndexNotEnabled.into());
2211        }
2212        self.handler.mov_after(target, after)
2213    }
2214
2215    /// Move the `target` node to be a child before the `before` node with the same parent.
2216    ///
2217    /// # Example
2218    ///
2219    /// ```rust
2220    /// use loro::LoroDoc;
2221    ///
2222    /// let doc = LoroDoc::new();
2223    /// let tree = doc.get_tree("tree");
2224    /// // enable generate fractional index
2225    /// tree.enable_fractional_index(0);
2226    /// let root = tree.create(None).unwrap();
2227    /// let root2 = tree.create(None).unwrap();
2228    /// // move `root` to be a child before `root2`.
2229    /// tree.mov_before(root, root2).unwrap();
2230    /// ```
2231    pub fn mov_before(&self, target: TreeID, before: TreeID) -> LoroResult<()> {
2232        if !self.handler.is_fractional_index_enabled() {
2233            return Err(LoroTreeError::FractionalIndexNotEnabled.into());
2234        }
2235        self.handler.mov_before(target, before)
2236    }
2237
2238    /// Delete a tree node.
2239    ///
2240    /// Note: If the deleted node has children, the children do not appear in the state
2241    /// rather than actually being deleted.
2242    ///
2243    /// # Example
2244    ///
2245    /// ```rust
2246    /// use loro::LoroDoc;
2247    ///
2248    /// let doc = LoroDoc::new();
2249    /// let tree = doc.get_tree("tree");
2250    /// let root = tree.create(None).unwrap();
2251    /// tree.delete(root).unwrap();
2252    /// ```
2253    pub fn delete(&self, target: TreeID) -> LoroResult<()> {
2254        self.handler.delete(target)
2255    }
2256
2257    /// Get the associated metadata map handler of a tree node.
2258    ///
2259    /// # Example
2260    /// ```rust
2261    /// use loro::LoroDoc;
2262    ///
2263    /// let doc = LoroDoc::new();
2264    /// let tree = doc.get_tree("tree");
2265    /// let root = tree.create(None).unwrap();
2266    /// let root_meta = tree.get_meta(root).unwrap();
2267    /// root_meta.insert("color", "red");
2268    /// ```
2269    pub fn get_meta(&self, target: TreeID) -> LoroResult<LoroMap> {
2270        self.handler
2271            .get_meta(target)
2272            .map(|h| LoroMap { handler: h })
2273    }
2274
2275    /// Return the parent of target node.
2276    ///
2277    /// - If the target node does not exist, return `None`.
2278    /// - If the target node is a root node, return `Some(None)`.
2279    pub fn parent(&self, target: TreeID) -> Option<TreeParentId> {
2280        self.handler.get_node_parent(&target)
2281    }
2282
2283    /// Return whether target node exists. including deleted node.
2284    pub fn contains(&self, target: TreeID) -> bool {
2285        self.handler.contains(target)
2286    }
2287
2288    /// Return whether target node is deleted.
2289    ///
2290    /// # Errors
2291    ///
2292    /// - If the target node does not exist, return `LoroTreeError::TreeNodeNotExist`.
2293    pub fn is_node_deleted(&self, target: &TreeID) -> LoroResult<bool> {
2294        self.handler.is_node_deleted(target)
2295    }
2296
2297    /// Return all nodes, including deleted nodes
2298    pub fn nodes(&self) -> Vec<TreeID> {
2299        self.handler.nodes()
2300    }
2301
2302    /// Return all nodes, if `with_deleted` is true, the deleted nodes will be included.
2303    pub fn get_nodes(&self, with_deleted: bool) -> Vec<TreeNode> {
2304        let mut ans = self.handler.get_nodes_under(TreeParentId::Root);
2305        if with_deleted {
2306            ans.extend(self.handler.get_nodes_under(TreeParentId::Deleted));
2307        }
2308        ans.into_iter()
2309            .map(|x| TreeNode {
2310                id: x.id,
2311                parent: x.parent,
2312                fractional_index: x.fractional_index,
2313                index: x.index,
2314            })
2315            .collect()
2316    }
2317
2318    /// Return all children of the target node.
2319    ///
2320    /// If the parent node does not exist, return `None`.
2321    pub fn children<T: Into<TreeParentId>>(&self, parent: T) -> Option<Vec<TreeID>> {
2322        self.handler.children(&parent.into())
2323    }
2324
2325    /// Return the number of children of the target node.
2326    pub fn children_num<T: Into<TreeParentId>>(&self, parent: T) -> Option<usize> {
2327        let parent: TreeParentId = parent.into();
2328        self.handler.children_num(&parent)
2329    }
2330
2331    /// Return container id of the tree.
2332    pub fn id(&self) -> ContainerID {
2333        self.handler.id()
2334    }
2335
2336    /// Return the fractional index of the target node with hex format.
2337    pub fn fractional_index(&self, target: TreeID) -> Option<String> {
2338        self.handler
2339            .get_position_by_tree_id(&target)
2340            .map(|x| x.to_string())
2341    }
2342
2343    /// Return the hierarchy array of the forest.
2344    ///
2345    /// Note: the metadata will be not resolved. So if you don't only care about hierarchy
2346    /// but also the metadata, you should use [TreeHandler::get_value_with_meta()].
2347    pub fn get_value(&self) -> LoroValue {
2348        self.handler.get_value()
2349    }
2350
2351    /// Return the hierarchy array of the forest, each node is with metadata.
2352    pub fn get_value_with_meta(&self) -> LoroValue {
2353        self.handler.get_deep_value()
2354    }
2355
2356    // This method is used for testing only.
2357    #[doc(hidden)]
2358    #[allow(non_snake_case)]
2359    pub fn __internal__next_tree_id(&self) -> TreeID {
2360        self.handler.__internal__next_tree_id()
2361    }
2362
2363    /// Whether the fractional index is enabled.
2364    pub fn is_fractional_index_enabled(&self) -> bool {
2365        self.handler.is_fractional_index_enabled()
2366    }
2367
2368    /// Enable fractional index for Tree Position.
2369    ///
2370    /// The jitter is used to avoid conflicts when multiple users are creating the node at the same position.
2371    /// value 0 is default, which means no jitter, any value larger than 0 will enable jitter.
2372    ///
2373    /// Generally speaking, jitter will affect the growth rate of document size.
2374    /// [Read more about it](https://www.loro.dev/blog/movable-tree#implementation-and-encoding-size)
2375    #[inline]
2376    pub fn enable_fractional_index(&self, jitter: u8) {
2377        self.handler.enable_fractional_index(jitter);
2378    }
2379
2380    /// Disable the fractional index generation when you don't need the Tree's siblings to be sorted.
2381    /// The fractional index will always be set to the same default value 0.
2382    ///
2383    /// After calling this, you cannot use `tree.moveTo()`, `tree.moveBefore()`, `tree.moveAfter()`,
2384    /// and `tree.createAt()`.
2385    #[inline]
2386    pub fn disable_fractional_index(&self) {
2387        self.handler.disable_fractional_index();
2388    }
2389
2390    /// Whether the tree is empty.
2391    ///
2392    #[inline]
2393    pub fn is_empty(&self) -> bool {
2394        self.handler.is_empty()
2395    }
2396
2397    /// Get the last move id of the target node.
2398    pub fn get_last_move_id(&self, target: &TreeID) -> Option<ID> {
2399        self.handler.get_last_move_id(target)
2400    }
2401}
2402
2403impl Default for LoroTree {
2404    fn default() -> Self {
2405        Self::new()
2406    }
2407}
2408
2409/// [LoroMovableList container](https://loro.dev/docs/tutorial/list)
2410///
2411/// It is used to model movable ordered lists.
2412///
2413/// Using a combination of insert and delete operations, one can simulate set and move
2414/// operations on a List. However, this approach fails in concurrent editing scenarios.
2415/// For example, if the same element is set or moved concurrently, the simulation would
2416/// result in the deletion of the original element and the insertion of two new elements,
2417/// which does not meet expectations.
2418#[derive(Clone, Debug)]
2419pub struct LoroMovableList {
2420    handler: InnerMovableListHandler,
2421}
2422
2423impl SealedTrait for LoroMovableList {}
2424impl ContainerTrait for LoroMovableList {
2425    type Handler = InnerMovableListHandler;
2426
2427    fn to_container(&self) -> Container {
2428        Container::MovableList(self.clone())
2429    }
2430
2431    fn to_handler(&self) -> Self::Handler {
2432        self.handler.clone()
2433    }
2434
2435    fn from_handler(handler: Self::Handler) -> Self {
2436        Self { handler }
2437    }
2438
2439    fn try_from_container(container: Container) -> Option<Self>
2440    where
2441        Self: Sized,
2442    {
2443        match container {
2444            Container::MovableList(x) => Some(x),
2445            _ => None,
2446        }
2447    }
2448
2449    fn is_attached(&self) -> bool {
2450        self.handler.is_attached()
2451    }
2452
2453    fn get_attached(&self) -> Option<Self>
2454    where
2455        Self: Sized,
2456    {
2457        self.handler.get_attached().map(Self::from_handler)
2458    }
2459
2460    fn is_deleted(&self) -> bool {
2461        self.handler.is_deleted()
2462    }
2463    fn doc(&self) -> Option<LoroDoc> {
2464        self.handler.doc().map(LoroDoc::_new)
2465    }
2466}
2467
2468impl LoroMovableList {
2469    /// Create a new container that is detached from the document.
2470    ///
2471    /// The edits on a detached container will not be persisted.
2472    /// To attach the container to the document, please insert it into an attached container.
2473    pub fn new() -> LoroMovableList {
2474        Self {
2475            handler: InnerMovableListHandler::new_detached(),
2476        }
2477    }
2478
2479    /// Get the container id.
2480    pub fn id(&self) -> ContainerID {
2481        self.handler.id().clone()
2482    }
2483
2484    /// Whether the container is attached to a document
2485    ///
2486    /// The edits on a detached container will not be persisted.
2487    /// To attach the container to the document, please insert it into an attached container.
2488    pub fn is_attached(&self) -> bool {
2489        self.handler.is_attached()
2490    }
2491
2492    /// Insert a value at the given position.
2493    pub fn insert(&self, pos: usize, v: impl Into<LoroValue>) -> LoroResult<()> {
2494        self.handler.insert(pos, v)
2495    }
2496
2497    /// Delete the value at the given position.
2498    pub fn delete(&self, pos: usize, len: usize) -> LoroResult<()> {
2499        self.handler.delete(pos, len)
2500    }
2501
2502    /// Get the value at the given position.
2503    pub fn get(&self, index: usize) -> Option<ValueOrContainer> {
2504        self.handler.get_(index).map(ValueOrContainer::from)
2505    }
2506
2507    /// Get the length of the list.
2508    pub fn len(&self) -> usize {
2509        self.handler.len()
2510    }
2511
2512    /// Whether the list is empty.
2513    #[must_use]
2514    pub fn is_empty(&self) -> bool {
2515        self.len() == 0
2516    }
2517
2518    /// Get the shallow value of the list.
2519    ///
2520    /// It will not convert the state of sub-containers, but represent them as [LoroValue::Container].
2521    pub fn get_value(&self) -> LoroValue {
2522        self.handler.get_value()
2523    }
2524
2525    /// Get the deep value of the list.
2526    ///
2527    /// It will convert the state of sub-containers into a nested JSON value.
2528    pub fn get_deep_value(&self) -> LoroValue {
2529        self.handler.get_deep_value()
2530    }
2531
2532    /// Pop the last element of the list.
2533    pub fn pop(&self) -> LoroResult<Option<ValueOrContainer>> {
2534        let ans = self.handler.pop_()?.map(ValueOrContainer::from);
2535        Ok(ans)
2536    }
2537
2538    /// Push a value to the end of the list.
2539    pub fn push(&self, v: impl Into<LoroValue>) -> LoroResult<()> {
2540        self.handler.push(v.into())
2541    }
2542
2543    /// Push a container to the end of the list.
2544    pub fn push_container<C: ContainerTrait>(&self, child: C) -> LoroResult<C> {
2545        let pos = self.handler.len();
2546        Ok(C::from_handler(
2547            self.handler.insert_container(pos, child.to_handler())?,
2548        ))
2549    }
2550
2551    /// Set the value at the given position.
2552    pub fn set(&self, pos: usize, value: impl Into<LoroValue>) -> LoroResult<()> {
2553        self.handler.set(pos, value.into())
2554    }
2555
2556    /// Move the value at the given position to the given position.
2557    pub fn mov(&self, from: usize, to: usize) -> LoroResult<()> {
2558        self.handler.mov(from, to)
2559    }
2560
2561    /// Insert a container at the given position.
2562    pub fn insert_container<C: ContainerTrait>(&self, pos: usize, child: C) -> LoroResult<C> {
2563        Ok(C::from_handler(
2564            self.handler.insert_container(pos, child.to_handler())?,
2565        ))
2566    }
2567
2568    /// Set the container at the given position.
2569    pub fn set_container<C: ContainerTrait>(&self, pos: usize, child: C) -> LoroResult<C> {
2570        Ok(C::from_handler(
2571            self.handler.set_container(pos, child.to_handler())?,
2572        ))
2573    }
2574
2575    /// Log the internal state of the list.
2576    pub fn log_internal_state(&self) {
2577        info!(
2578            "movable_list internal state: {}",
2579            self.handler.log_internal_state()
2580        )
2581    }
2582
2583    /// Get the cursor at the given position.
2584    ///
2585    /// Using "index" to denote cursor positions can be unstable, as positions may
2586    /// shift with document edits. To reliably represent a position or range within
2587    /// a document, it is more effective to leverage the unique ID of each item/character
2588    /// in a List CRDT or Text CRDT.
2589    ///
2590    /// Loro optimizes State metadata by not storing the IDs of deleted elements. This
2591    /// approach complicates tracking cursors since they rely on these IDs. The solution
2592    /// recalculates position by replaying relevant history to update stable positions
2593    /// accurately. To minimize the performance impact of history replay, the system
2594    /// updates cursor info to reference only the IDs of currently present elements,
2595    /// thereby reducing the need for replay.
2596    ///
2597    /// # Example
2598    ///
2599    /// ```
2600    /// use loro::LoroDoc;
2601    /// use loro_internal::cursor::Side;
2602    ///
2603    /// let doc = LoroDoc::new();
2604    /// let list = doc.get_movable_list("list");
2605    /// list.insert(0, 0).unwrap();
2606    /// let cursor = list.get_cursor(0, Side::Middle).unwrap();
2607    /// assert_eq!(doc.get_cursor_pos(&cursor).unwrap().current.pos, 0);
2608    /// list.insert(0, 0).unwrap();
2609    /// assert_eq!(doc.get_cursor_pos(&cursor).unwrap().current.pos, 1);
2610    /// list.insert(0, 0).unwrap();
2611    /// list.insert(0, 0).unwrap();
2612    /// assert_eq!(doc.get_cursor_pos(&cursor).unwrap().current.pos, 3);
2613    /// list.insert(4, 0).unwrap();
2614    /// assert_eq!(doc.get_cursor_pos(&cursor).unwrap().current.pos, 3);
2615    /// ```
2616    pub fn get_cursor(&self, pos: usize, side: Side) -> Option<Cursor> {
2617        self.handler.get_cursor(pos, side)
2618    }
2619
2620    /// Get the elements of the list as a vector of LoroValues.
2621    ///
2622    /// This method returns a vector containing all the elements in the list as LoroValues.
2623    /// It provides a convenient way to access the entire contents of the LoroMovableList
2624    /// as a standard Rust vector.
2625    ///
2626    /// # Returns
2627    ///
2628    /// A `Vec<LoroValue>` containing all elements of the list.
2629    ///
2630    /// # Example
2631    ///
2632    /// ```
2633    /// use loro::LoroDoc;
2634    ///
2635    /// let doc = LoroDoc::new();
2636    /// let list = doc.get_movable_list("mylist");
2637    /// list.insert(0, 1).unwrap();
2638    /// list.insert(1, "hello").unwrap();
2639    /// list.insert(2, true).unwrap();
2640    ///
2641    /// let vec = list.to_vec();
2642    /// assert_eq!(vec.len(), 3);
2643    /// assert_eq!(vec[0], 1.into());
2644    /// assert_eq!(vec[1], "hello".into());
2645    /// assert_eq!(vec[2], true.into());
2646    /// ```
2647    pub fn to_vec(&self) -> Vec<LoroValue> {
2648        self.get_value().into_list().unwrap().unwrap()
2649    }
2650
2651    /// Delete all elements in the list.
2652    pub fn clear(&self) -> LoroResult<()> {
2653        self.handler.clear()
2654    }
2655
2656    /// Iterate over the elements of the list.
2657    pub fn for_each<I>(&self, mut f: I)
2658    where
2659        I: FnMut(ValueOrContainer),
2660    {
2661        self.handler.for_each(&mut |v| {
2662            f(ValueOrContainer::from(v));
2663        })
2664    }
2665
2666    /// Get the creator of the list item at the given position.
2667    pub fn get_creator_at(&self, pos: usize) -> Option<PeerID> {
2668        self.handler.get_creator_at(pos)
2669    }
2670
2671    /// Get the last mover of the list item at the given position.
2672    pub fn get_last_mover_at(&self, pos: usize) -> Option<PeerID> {
2673        self.handler.get_last_mover_at(pos)
2674    }
2675
2676    /// Get the last editor of the list item at the given position.
2677    pub fn get_last_editor_at(&self, pos: usize) -> Option<PeerID> {
2678        self.handler.get_last_editor_at(pos)
2679    }
2680}
2681
2682impl Default for LoroMovableList {
2683    fn default() -> Self {
2684        Self::new()
2685    }
2686}
2687
2688/// Unknown container.
2689#[derive(Clone, Debug)]
2690pub struct LoroUnknown {
2691    handler: InnerUnknownHandler,
2692}
2693
2694impl LoroUnknown {
2695    /// Get the container id.
2696    pub fn id(&self) -> ContainerID {
2697        self.handler.id().clone()
2698    }
2699}
2700
2701impl SealedTrait for LoroUnknown {}
2702impl ContainerTrait for LoroUnknown {
2703    type Handler = InnerUnknownHandler;
2704
2705    fn to_container(&self) -> Container {
2706        Container::Unknown(self.clone())
2707    }
2708
2709    fn to_handler(&self) -> Self::Handler {
2710        self.handler.clone()
2711    }
2712
2713    fn from_handler(handler: Self::Handler) -> Self {
2714        Self { handler }
2715    }
2716
2717    fn try_from_container(container: Container) -> Option<Self>
2718    where
2719        Self: Sized,
2720    {
2721        match container {
2722            Container::Unknown(x) => Some(x),
2723            _ => None,
2724        }
2725    }
2726
2727    fn is_attached(&self) -> bool {
2728        self.handler.is_attached()
2729    }
2730
2731    fn get_attached(&self) -> Option<Self>
2732    where
2733        Self: Sized,
2734    {
2735        self.handler.get_attached().map(Self::from_handler)
2736    }
2737
2738    fn is_deleted(&self) -> bool {
2739        self.handler.is_deleted()
2740    }
2741    fn doc(&self) -> Option<LoroDoc> {
2742        self.handler.doc().map(LoroDoc::_new)
2743    }
2744}
2745
2746use enum_as_inner::EnumAsInner;
2747
2748/// All the CRDT containers supported by Loro.
2749#[derive(Clone, Debug, EnumAsInner)]
2750pub enum Container {
2751    /// [LoroList container](https://loro.dev/docs/tutorial/list)
2752    List(LoroList),
2753    /// [LoroMap container](https://loro.dev/docs/tutorial/map)
2754    Map(LoroMap),
2755    /// [LoroText container](https://loro.dev/docs/tutorial/text)
2756    Text(LoroText),
2757    /// [LoroTree container]
2758    Tree(LoroTree),
2759    /// [LoroMovableList container](https://loro.dev/docs/tutorial/list)
2760    MovableList(LoroMovableList),
2761    #[cfg(feature = "counter")]
2762    /// [LoroCounter container]
2763    Counter(counter::LoroCounter),
2764    /// Unknown container
2765    Unknown(LoroUnknown),
2766}
2767
2768impl SealedTrait for Container {}
2769impl ContainerTrait for Container {
2770    type Handler = loro_internal::handler::Handler;
2771
2772    fn to_container(&self) -> Container {
2773        self.clone()
2774    }
2775
2776    fn to_handler(&self) -> Self::Handler {
2777        match self {
2778            Container::List(x) => Self::Handler::List(x.to_handler()),
2779            Container::Map(x) => Self::Handler::Map(x.to_handler()),
2780            Container::Text(x) => Self::Handler::Text(x.to_handler()),
2781            Container::Tree(x) => Self::Handler::Tree(x.to_handler()),
2782            Container::MovableList(x) => Self::Handler::MovableList(x.to_handler()),
2783            #[cfg(feature = "counter")]
2784            Container::Counter(x) => Self::Handler::Counter(x.to_handler()),
2785            Container::Unknown(x) => Self::Handler::Unknown(x.to_handler()),
2786        }
2787    }
2788
2789    fn from_handler(handler: Self::Handler) -> Self {
2790        match handler {
2791            InnerHandler::Text(x) => Container::Text(LoroText { handler: x }),
2792            InnerHandler::Map(x) => Container::Map(LoroMap { handler: x }),
2793            InnerHandler::List(x) => Container::List(LoroList { handler: x }),
2794            InnerHandler::MovableList(x) => Container::MovableList(LoroMovableList { handler: x }),
2795            InnerHandler::Tree(x) => Container::Tree(LoroTree { handler: x }),
2796            #[cfg(feature = "counter")]
2797            InnerHandler::Counter(x) => Container::Counter(counter::LoroCounter { handler: x }),
2798            InnerHandler::Unknown(x) => Container::Unknown(LoroUnknown { handler: x }),
2799        }
2800    }
2801
2802    fn is_attached(&self) -> bool {
2803        match self {
2804            Container::List(x) => x.is_attached(),
2805            Container::Map(x) => x.is_attached(),
2806            Container::Text(x) => x.is_attached(),
2807            Container::Tree(x) => x.is_attached(),
2808            Container::MovableList(x) => x.is_attached(),
2809            #[cfg(feature = "counter")]
2810            Container::Counter(x) => x.is_attached(),
2811            Container::Unknown(x) => x.is_attached(),
2812        }
2813    }
2814
2815    fn get_attached(&self) -> Option<Self> {
2816        match self {
2817            Container::List(x) => x.get_attached().map(Container::List),
2818            Container::MovableList(x) => x.get_attached().map(Container::MovableList),
2819            Container::Map(x) => x.get_attached().map(Container::Map),
2820            Container::Text(x) => x.get_attached().map(Container::Text),
2821            Container::Tree(x) => x.get_attached().map(Container::Tree),
2822            #[cfg(feature = "counter")]
2823            Container::Counter(x) => x.get_attached().map(Container::Counter),
2824            Container::Unknown(x) => x.get_attached().map(Container::Unknown),
2825        }
2826    }
2827
2828    fn try_from_container(container: Container) -> Option<Self>
2829    where
2830        Self: Sized,
2831    {
2832        Some(container)
2833    }
2834
2835    fn is_deleted(&self) -> bool {
2836        match self {
2837            Container::List(x) => x.is_deleted(),
2838            Container::Map(x) => x.is_deleted(),
2839            Container::Text(x) => x.is_deleted(),
2840            Container::Tree(x) => x.is_deleted(),
2841            Container::MovableList(x) => x.is_deleted(),
2842            #[cfg(feature = "counter")]
2843            Container::Counter(x) => x.is_deleted(),
2844            Container::Unknown(x) => x.is_deleted(),
2845        }
2846    }
2847    fn doc(&self) -> Option<LoroDoc> {
2848        match self {
2849            Container::List(x) => x.doc(),
2850            Container::Map(x) => x.doc(),
2851            Container::Text(x) => x.doc(),
2852            Container::Tree(x) => x.doc(),
2853            Container::MovableList(x) => x.doc(),
2854            #[cfg(feature = "counter")]
2855            Container::Counter(x) => x.doc(),
2856            Container::Unknown(x) => x.doc(),
2857        }
2858    }
2859}
2860
2861impl Container {
2862    /// Create a detached container of the given type.
2863    ///
2864    /// A detached container is a container that is not attached to a document.
2865    /// The edits on a detached container will not be persisted.
2866    /// To attach the container to the document, please insert it into an attached container.
2867    pub fn new(kind: ContainerType) -> Self {
2868        match kind {
2869            ContainerType::List => Container::List(LoroList::new()),
2870            ContainerType::MovableList => Container::MovableList(LoroMovableList::new()),
2871            ContainerType::Map => Container::Map(LoroMap::new()),
2872            ContainerType::Text => Container::Text(LoroText::new()),
2873            ContainerType::Tree => Container::Tree(LoroTree::new()),
2874            #[cfg(feature = "counter")]
2875            ContainerType::Counter => Container::Counter(counter::LoroCounter::new()),
2876            ContainerType::Unknown(_) => unreachable!(),
2877        }
2878    }
2879
2880    /// Get the type of the container.
2881    pub fn get_type(&self) -> ContainerType {
2882        match self {
2883            Container::List(_) => ContainerType::List,
2884            Container::MovableList(_) => ContainerType::MovableList,
2885            Container::Map(_) => ContainerType::Map,
2886            Container::Text(_) => ContainerType::Text,
2887            Container::Tree(_) => ContainerType::Tree,
2888            #[cfg(feature = "counter")]
2889            Container::Counter(_) => ContainerType::Counter,
2890            Container::Unknown(x) => x.handler.id().container_type(),
2891        }
2892    }
2893
2894    /// Get the id of the container.
2895    pub fn id(&self) -> ContainerID {
2896        match self {
2897            Container::List(x) => x.id(),
2898            Container::MovableList(x) => x.id(),
2899            Container::Map(x) => x.id(),
2900            Container::Text(x) => x.id(),
2901            Container::Tree(x) => x.id(),
2902            #[cfg(feature = "counter")]
2903            Container::Counter(x) => x.id(),
2904            Container::Unknown(x) => x.handler.id(),
2905        }
2906    }
2907}
2908
2909impl From<InnerHandler> for Container {
2910    fn from(value: InnerHandler) -> Self {
2911        match value {
2912            InnerHandler::Text(x) => Container::Text(LoroText { handler: x }),
2913            InnerHandler::Map(x) => Container::Map(LoroMap { handler: x }),
2914            InnerHandler::List(x) => Container::List(LoroList { handler: x }),
2915            InnerHandler::Tree(x) => Container::Tree(LoroTree { handler: x }),
2916            InnerHandler::MovableList(x) => Container::MovableList(LoroMovableList { handler: x }),
2917            #[cfg(feature = "counter")]
2918            InnerHandler::Counter(x) => Container::Counter(counter::LoroCounter { handler: x }),
2919            InnerHandler::Unknown(x) => Container::Unknown(LoroUnknown { handler: x }),
2920        }
2921    }
2922}
2923
2924/// It's a type that can be either a value or a container.
2925#[derive(Debug, Clone, EnumAsInner)]
2926pub enum ValueOrContainer {
2927    /// A value.
2928    Value(LoroValue),
2929    /// A container.
2930    Container(Container),
2931}
2932
2933impl ValueOrContainer {
2934    /// Get the deep value of the value or container.
2935    pub fn get_deep_value(&self) -> LoroValue {
2936        match self {
2937            ValueOrContainer::Value(v) => v.clone(),
2938            ValueOrContainer::Container(c) => match c {
2939                Container::List(c) => c.get_deep_value(),
2940                Container::Map(c) => c.get_deep_value(),
2941                Container::Text(c) => c.to_string().into(),
2942                Container::Tree(c) => c.get_value(),
2943                Container::MovableList(c) => c.get_deep_value(),
2944                #[cfg(feature = "counter")]
2945                Container::Counter(c) => c.get_value().into(),
2946                Container::Unknown(_) => LoroValue::Null,
2947            },
2948        }
2949    }
2950
2951    pub(crate) fn into_value_or_handler(self) -> ValueOrHandler {
2952        match self {
2953            ValueOrContainer::Value(v) => ValueOrHandler::Value(v),
2954            ValueOrContainer::Container(c) => ValueOrHandler::Handler(c.to_handler()),
2955        }
2956    }
2957}
2958
2959/// UndoManager can be used to undo and redo the changes made to the document with a certain peer.
2960#[derive(Debug)]
2961#[repr(transparent)]
2962pub struct UndoManager(InnerUndoManager);
2963
2964impl UndoManager {
2965    /// Create a new UndoManager.
2966    pub fn new(doc: &LoroDoc) -> Self {
2967        let mut inner = InnerUndoManager::new(&doc.doc);
2968        inner.set_max_undo_steps(100);
2969        Self(inner)
2970    }
2971
2972    /// Undo the last change made by the peer.
2973    pub fn undo(&mut self) -> LoroResult<bool> {
2974        self.0.undo()
2975    }
2976
2977    /// Redo the last change made by the peer.
2978    pub fn redo(&mut self) -> LoroResult<bool> {
2979        self.0.redo()
2980    }
2981
2982    /// Record a new checkpoint.
2983    pub fn record_new_checkpoint(&mut self) -> LoroResult<()> {
2984        self.0.record_new_checkpoint()
2985    }
2986
2987    /// Whether the undo manager can undo.
2988    pub fn can_undo(&self) -> bool {
2989        self.0.can_undo()
2990    }
2991
2992    /// Whether the undo manager can redo.
2993    pub fn can_redo(&self) -> bool {
2994        self.0.can_redo()
2995    }
2996
2997    /// If a local event's origin matches the given prefix, it will not be recorded in the
2998    /// undo stack.
2999    pub fn add_exclude_origin_prefix(&mut self, prefix: &str) {
3000        self.0.add_exclude_origin_prefix(prefix)
3001    }
3002
3003    /// Set the maximum number of undo steps. The default value is 100.
3004    pub fn set_max_undo_steps(&mut self, size: usize) {
3005        self.0.set_max_undo_steps(size)
3006    }
3007
3008    /// Set the merge interval in ms. The default value is 0, which means no merge.
3009    pub fn set_merge_interval(&mut self, interval: i64) {
3010        self.0.set_merge_interval(interval)
3011    }
3012
3013    /// Set the listener for push events.
3014    /// The listener will be called when a new undo/redo item is pushed into the stack.
3015    pub fn set_on_push(&mut self, on_push: Option<OnPush>) {
3016        if let Some(on_push) = on_push {
3017            self.0.set_on_push(Some(Box::new(move |u, c, e| {
3018                on_push(u, c, e.map(|x| x.into()))
3019            })));
3020        } else {
3021            self.0.set_on_push(None);
3022        }
3023    }
3024
3025    /// Set the listener for pop events.
3026    /// The listener will be called when an undo/redo item is popped from the stack.
3027    pub fn set_on_pop(&mut self, on_pop: Option<OnPop>) {
3028        self.0.set_on_pop(on_pop);
3029    }
3030
3031    /// Clear the undo stack and the redo stack
3032    pub fn clear(&self) {
3033        self.0.clear();
3034    }
3035}
3036/// When a undo/redo item is pushed, the undo manager will call the on_push callback to get the meta data of the undo item.
3037/// The returned cursors will be recorded for a new pushed undo item.
3038pub type OnPush =
3039    Box<dyn for<'a> Fn(UndoOrRedo, CounterSpan, Option<DiffEvent>) -> UndoItemMeta + Send + Sync>;