loro_internal/
lib.rs

1//! loro-internal is a CRDT framework.
2//!
3//!
4//!
5//!
6#![deny(clippy::undocumented_unsafe_blocks)]
7#![warn(rustdoc::broken_intra_doc_links)]
8#![warn(missing_debug_implementations)]
9
10pub mod arena;
11pub mod diff;
12pub mod diff_calc;
13pub mod handler;
14pub mod sync;
15use crate::sync::AtomicBool;
16use std::sync::Arc;
17mod change_meta;
18pub(crate) mod lock;
19use arena::SharedArena;
20use configure::Configure;
21use diff_calc::DiffCalculator;
22use lock::LoroMutex;
23
24pub use change_meta::ChangeMeta;
25pub use event::{ContainerDiff, DiffEvent, DocDiff, ListDiff, ListDiffInsertItem, ListDiffItem};
26pub use fxhash::FxHashMap;
27pub use handler::{
28    BasicHandler, HandlerTrait, ListHandler, MapHandler, MovableListHandler, TextHandler,
29    TreeHandler, UnknownHandler,
30};
31pub use loro_common;
32pub use oplog::OpLog;
33use pre_commit::{
34    FirstCommitFromPeerCallback, FirstCommitFromPeerPayload, PreCommitCallback,
35    PreCommitCallbackPayload,
36};
37pub use state::DocState;
38pub use state::{TreeNode, TreeNodeWithChildren, TreeParentId};
39use subscription::{LocalUpdateCallback, Observer, PeerIdUpdateCallback};
40use txn::Transaction;
41pub use undo::UndoManager;
42use utils::subscription::SubscriberSetWithQueue;
43pub use utils::subscription::Subscription;
44pub mod allocation;
45pub mod awareness;
46pub mod change;
47pub mod configure;
48pub mod container;
49pub mod cursor;
50pub mod dag;
51pub mod encoding;
52pub(crate) mod fork;
53pub mod id;
54#[cfg(feature = "jsonpath")]
55pub mod jsonpath;
56pub mod kv_store;
57pub mod loro;
58pub mod op;
59pub mod oplog;
60pub mod subscription;
61pub mod txn;
62pub mod version;
63
64mod error;
65#[cfg(feature = "test_utils")]
66pub mod fuzz;
67mod parent;
68pub mod pre_commit;
69mod span;
70#[cfg(test)]
71pub mod tests;
72mod utils;
73pub use utils::string_slice::StringSlice;
74
75pub mod delta;
76pub use loro_delta;
77pub mod event;
78
79pub mod estimated_size;
80pub(crate) mod history_cache;
81pub(crate) mod macros;
82pub(crate) mod state;
83pub mod undo;
84pub(crate) mod value;
85
86// TODO: rename as Key?
87pub(crate) use loro_common::InternalString;
88
89pub use container::ContainerType;
90pub use encoding::json_schema::json;
91pub use fractional_index::FractionalIndex;
92pub use loro_common::{loro_value, to_value};
93pub use loro_common::{
94    Counter, CounterSpan, IdLp, IdSpan, IdSpanVector, Lamport, LoroEncodeError, LoroError,
95    LoroResult, LoroTreeError, PeerID, TreeID, ID,
96};
97pub use loro_common::{LoroBinaryValue, LoroListValue, LoroMapValue, LoroStringValue};
98#[cfg(feature = "wasm")]
99pub use value::wasm;
100pub use value::{ApplyDiff, LoroValue, ToJson};
101pub use version::VersionVector;
102
103/// [`LoroDoc`] serves as the library's primary entry point.
104/// It's constituted by an [OpLog] and an [DocState].
105///
106/// - [OpLog] encompasses all operations, signifying the document history.
107/// - [DocState] signifies the current document state.
108///
109/// They will share a [super::arena::SharedArena]
110///
111/// # Detached Mode
112///
113/// This mode enables separate usage of [OpLog] and [DocState].
114/// It facilitates temporal navigation. [DocState] can be reverted to
115/// any version contained within the [OpLog].
116///
117/// `LoroDoc::detach()` separates [DocState] from [OpLog]. In this mode,
118/// updates to [OpLog] won't affect [DocState], while updates to [DocState]
119/// will continue to affect [OpLog].
120#[derive(Debug, Clone)]
121#[repr(transparent)]
122pub struct LoroDoc {
123    inner: Arc<LoroDocInner>,
124}
125
126impl LoroDoc {
127    pub(crate) fn from_inner(inner: Arc<LoroDocInner>) -> Self {
128        Self { inner }
129    }
130}
131
132impl std::ops::Deref for LoroDoc {
133    type Target = LoroDocInner;
134
135    fn deref(&self) -> &Self::Target {
136        &self.inner
137    }
138}
139
140pub struct LoroDocInner {
141    oplog: Arc<LoroMutex<OpLog>>,
142    state: Arc<LoroMutex<DocState>>,
143    arena: SharedArena,
144    config: Configure,
145    observer: Arc<Observer>,
146    diff_calculator: Arc<LoroMutex<DiffCalculator>>,
147    /// When dropping the doc, the txn will be committed
148    ///
149    /// # Internal Notes
150    ///
151    /// Txn can be accessed by different threads. But for certain methods we need to lock the txn and ensure it's empty:
152    ///
153    /// - `import`
154    /// - `export`
155    /// - `checkout`
156    /// - `checkout_to_latest`
157    /// - ...
158    ///
159    /// We need to lock txn and keep it None because otherwise the DocState may change due to a parallel edit on a new Txn,
160    /// which may break the invariants of `import`, `export` and `checkout`.
161    txn: Arc<LoroMutex<Option<Transaction>>>,
162    auto_commit: AtomicBool,
163    detached: AtomicBool,
164    local_update_subs: SubscriberSetWithQueue<(), LocalUpdateCallback, Vec<u8>>,
165    peer_id_change_subs: SubscriberSetWithQueue<(), PeerIdUpdateCallback, ID>,
166    first_commit_from_peer_subs:
167        SubscriberSetWithQueue<(), FirstCommitFromPeerCallback, FirstCommitFromPeerPayload>,
168    pre_commit_subs: SubscriberSetWithQueue<(), PreCommitCallback, PreCommitCallbackPayload>,
169}
170
171/// The version of the loro crate
172pub const LORO_VERSION: &str = include_str!("../VERSION");
173
174impl Drop for LoroDoc {
175    fn drop(&mut self) {
176        if Arc::strong_count(&self.inner) == 1 {
177            let _ = self.commit_then_stop();
178        }
179    }
180}