Skip to main content

loro_internal/
lib.rs

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