loro_internal/
lib.rs

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