loro_ffi/container/
tree.rs

1use std::sync::Arc;
2
3use loro::{ContainerTrait, LoroError, LoroResult, LoroTreeError, TreeID, ID};
4
5use crate::{ContainerID, DiffEvent, LoroDoc, LoroValue, Subscriber, Subscription};
6
7use super::LoroMap;
8
9pub enum TreeParentId {
10    Node { id: TreeID },
11    Root,
12    Deleted,
13    Unexist,
14}
15
16#[derive(Debug, Clone)]
17pub struct LoroTree {
18    pub(crate) inner: loro::LoroTree,
19}
20
21impl LoroTree {
22    pub fn new() -> Self {
23        Self {
24            inner: loro::LoroTree::new(),
25        }
26    }
27
28    /// Whether the container is attached to a document
29    ///
30    /// The edits on a detached container will not be persisted.
31    /// To attach the container to the document, please insert it into an attached container.
32    pub fn is_attached(&self) -> bool {
33        self.inner.is_attached()
34    }
35
36    /// If a detached container is attached, this method will return its corresponding attached handler.
37    pub fn get_attached(&self) -> Option<Arc<LoroTree>> {
38        self.inner
39            .get_attached()
40            .map(|x| Arc::new(LoroTree { inner: x }))
41    }
42
43    /// Create a new tree node and return the [`TreeID`].
44    ///
45    /// If the `parent` is `None`, the created node is the root of a tree.
46    /// Otherwise, the created node is a child of the parent tree node.
47    ///
48    /// # Example
49    ///
50    /// ```rust
51    /// use loro::LoroDoc;
52    ///
53    /// let doc = LoroDoc::new();
54    /// let tree = doc.get_tree("tree");
55    /// // create a root
56    /// let root = tree.create(None).unwrap();
57    /// // create a new child
58    /// let child = tree.create(root).unwrap();
59    /// ```
60    pub fn create(&self, parent: TreeParentId) -> LoroResult<TreeID> {
61        self.inner.create(parent)
62    }
63
64    /// Create a new tree node at the given index and return the [`TreeID`].
65    ///
66    /// If the `parent` is `None`, the created node is the root of a tree.
67    /// If the `index` is greater than the number of children of the parent, error will be returned.
68    pub fn create_at(&self, parent: TreeParentId, index: u32) -> LoroResult<TreeID> {
69        self.inner.create_at(parent, index as usize)
70    }
71
72    pub fn roots(&self) -> Vec<TreeID> {
73        self.inner.roots()
74    }
75
76    /// Move the `target` node to be a child of the `parent` node.
77    ///
78    /// If the `parent` is `None`, the `target` node will be a root.
79    ///
80    /// # Example
81    ///
82    /// ```rust
83    /// use loro::LoroDoc;
84    ///
85    /// let doc = LoroDoc::new();
86    /// let tree = doc.get_tree("tree");
87    /// let root = tree.create(None).unwrap();
88    /// let root2 = tree.create(None).unwrap();
89    /// // move `root2` to be a child of `root`.
90    /// tree.mov(root2, root).unwrap();
91    /// ```
92    pub fn mov(&self, target: TreeID, parent: TreeParentId) -> LoroResult<()> {
93        self.inner.mov(target, parent)
94    }
95
96    /// Move the `target` node to be a child of the `parent` node at the given index.
97    /// If the `parent` is `None`, the `target` node will be a root.
98    pub fn mov_to(&self, target: TreeID, parent: TreeParentId, to: u32) -> LoroResult<()> {
99        self.inner.mov_to(target, parent, to as usize)
100    }
101
102    /// Move the `target` node to be a child after the `after` node with the same parent.
103    pub fn mov_after(&self, target: TreeID, after: TreeID) -> LoroResult<()> {
104        self.inner.mov_after(target, after)
105    }
106
107    /// Move the `target` node to be a child before the `before` node with the same parent.
108    pub fn mov_before(&self, target: TreeID, before: TreeID) -> LoroResult<()> {
109        self.inner.mov_before(target, before)
110    }
111
112    /// Delete a tree node.
113    ///
114    /// Note: If the deleted node has children, the children do not appear in the state
115    /// rather than actually being deleted.
116    ///
117    /// # Example
118    ///
119    /// ```rust
120    /// use loro::LoroDoc;
121    ///
122    /// let doc = LoroDoc::new();
123    /// let tree = doc.get_tree("tree");
124    /// let root = tree.create(None).unwrap();
125    /// tree.delete(root).unwrap();
126    /// ```
127    pub fn delete(&self, target: TreeID) -> LoroResult<()> {
128        self.inner.delete(target)
129    }
130
131    /// Get the associated metadata map handler of a tree node.
132    ///
133    /// # Example
134    /// ```rust
135    /// use loro::LoroDoc;
136    ///
137    /// let doc = LoroDoc::new();
138    /// let tree = doc.get_tree("tree");
139    /// let root = tree.create(None).unwrap();
140    /// let root_meta = tree.get_meta(root).unwrap();
141    /// root_meta.insert("color", "red");
142    /// ```
143    pub fn get_meta(&self, target: TreeID) -> LoroResult<Arc<LoroMap>> {
144        self.inner
145            .get_meta(target)
146            .map(|h| Arc::new(LoroMap { inner: h }))
147    }
148
149    /// Return the parent of target node.
150    ///
151    /// - If the target node does not exist, throws Error.
152    /// - If the target node is a root node, return `None`.
153    pub fn parent(&self, target: TreeID) -> LoroResult<TreeParentId> {
154        if let Some(p) = self.inner.parent(target) {
155            Ok(p.into())
156        } else {
157            Err(LoroError::TreeError(LoroTreeError::TreeNodeNotExist(
158                target,
159            )))
160        }
161    }
162
163    /// Return whether target node exists.
164    pub fn contains(&self, target: TreeID) -> bool {
165        self.inner.contains(target)
166    }
167
168    /// Return whether target node is deleted.
169    ///
170    /// # Errors
171    ///
172    /// - If the target node does not exist, return `LoroTreeError::TreeNodeNotExist`.
173    pub fn is_node_deleted(&self, target: TreeID) -> LoroResult<bool> {
174        self.inner.is_node_deleted(&target)
175    }
176
177    /// Return all nodes, including deleted nodes
178    pub fn nodes(&self) -> Vec<TreeID> {
179        self.inner.nodes()
180    }
181
182    /// Return all children of the target node.
183    ///
184    /// If the parent node does not exist, return `None`.
185    pub fn children(&self, parent: TreeParentId) -> Option<Vec<TreeID>> {
186        self.inner.children(parent)
187    }
188
189    /// Return the number of children of the target node.
190    pub fn children_num(&self, parent: TreeParentId) -> Option<u32> {
191        self.inner.children_num(parent).map(|v| v as u32)
192    }
193
194    /// Return container id of the tree.
195    pub fn id(&self) -> ContainerID {
196        self.inner.id().into()
197    }
198
199    /// Return the fractional index of the target node with hex format.
200    pub fn fractional_index(&self, target: TreeID) -> Option<String> {
201        self.inner.fractional_index(target)
202    }
203
204    /// Return the flat array of the forest.
205    ///
206    /// Note: the metadata will be not resolved. So if you don't only care about hierarchy
207    /// but also the metadata, you should use [TreeHandler::get_value_with_meta()].
208    pub fn get_value(&self) -> LoroValue {
209        self.inner.get_value().into()
210    }
211
212    /// Return the flat array of the forest, each node is with metadata.
213    pub fn get_value_with_meta(&self) -> LoroValue {
214        self.inner.get_value_with_meta().into()
215    }
216
217    /// Whether the fractional index is enabled.
218    pub fn is_fractional_index_enabled(&self) -> bool {
219        self.inner.is_fractional_index_enabled()
220    }
221
222    /// Enable fractional index for Tree Position.
223    ///
224    /// The jitter is used to avoid conflicts when multiple users are creating the node at the same position.
225    /// value 0 is default, which means no jitter, any value larger than 0 will enable jitter.
226    ///
227    /// Generally speaking, jitter will affect the growth rate of document size.
228    /// [Read more about it](https://www.loro.dev/blog/movable-tree#implementation-and-encoding-size)
229    #[inline]
230    pub fn enable_fractional_index(&self, jitter: u8) {
231        self.inner.enable_fractional_index(jitter);
232    }
233
234    /// Disable the fractional index generation for Tree Position when
235    /// you don't need the Tree's siblings to be sorted. The fractional index will be always default.
236    #[inline]
237    pub fn disable_fractional_index(&self) {
238        self.inner.disable_fractional_index();
239    }
240
241    pub fn is_deleted(&self) -> bool {
242        self.inner.is_deleted()
243    }
244
245    pub fn get_last_move_id(&self, target: &TreeID) -> Option<ID> {
246        self.inner.get_last_move_id(target)
247    }
248
249    pub fn doc(&self) -> Option<Arc<LoroDoc>> {
250        self.inner.doc().map(|x| Arc::new(LoroDoc { doc: x }))
251    }
252
253    pub fn subscribe(&self, subscriber: Arc<dyn Subscriber>) -> Option<Arc<Subscription>> {
254        self.inner
255            .subscribe(Arc::new(move |e| {
256                subscriber.on_diff(DiffEvent::from(e));
257            }))
258            .map(|x| Arc::new(x.into()))
259    }
260}
261
262impl Default for LoroTree {
263    fn default() -> Self {
264        Self::new()
265    }
266}
267
268impl From<loro::TreeParentId> for TreeParentId {
269    fn from(value: loro::TreeParentId) -> Self {
270        match value {
271            loro::TreeParentId::Node(id) => TreeParentId::Node { id },
272            loro::TreeParentId::Root => TreeParentId::Root,
273            loro::TreeParentId::Deleted => TreeParentId::Deleted,
274            loro::TreeParentId::Unexist => TreeParentId::Unexist,
275        }
276    }
277}
278
279impl From<TreeParentId> for loro::TreeParentId {
280    fn from(value: TreeParentId) -> Self {
281        match value {
282            TreeParentId::Node { id } => loro::TreeParentId::Node(id),
283            TreeParentId::Root => loro::TreeParentId::Root,
284            TreeParentId::Deleted => loro::TreeParentId::Deleted,
285            TreeParentId::Unexist => loro::TreeParentId::Unexist,
286        }
287    }
288}