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