loro_ffi/container/
movable_list.rs

1use std::sync::Arc;
2
3use loro::{cursor::Side, ContainerTrait, LoroResult, PeerID};
4
5use crate::{
6    ContainerID, DiffEvent, LoroDoc, LoroValue, LoroValueLike, Subscriber, Subscription,
7    ValueOrContainer,
8};
9
10use super::{Cursor, LoroCounter, LoroList, LoroMap, LoroText, LoroTree};
11
12#[derive(Debug, Clone)]
13pub struct LoroMovableList {
14    pub(crate) inner: loro::LoroMovableList,
15}
16
17impl LoroMovableList {
18    pub fn new() -> Self {
19        Self {
20            inner: loro::LoroMovableList::new(),
21        }
22    }
23
24    /// Get the container id.
25    pub fn id(&self) -> ContainerID {
26        self.inner.id().into()
27    }
28
29    /// Whether the container is attached to a document
30    ///
31    /// The edits on a detached container will not be persisted.
32    /// To attach the container to the document, please insert it into an attached container.
33    pub fn is_attached(&self) -> bool {
34        self.inner.is_attached()
35    }
36
37    /// If a detached container is attached, this method will return its corresponding attached handler.
38    pub fn get_attached(&self) -> Option<Arc<LoroMovableList>> {
39        self.inner
40            .get_attached()
41            .map(|x| Arc::new(LoroMovableList { inner: x }))
42    }
43
44    /// Insert a value at the given position.
45    pub fn insert(&self, pos: u32, v: Arc<dyn LoroValueLike>) -> LoroResult<()> {
46        self.inner.insert(pos as usize, v.as_loro_value())
47    }
48
49    /// Delete values at the given position.
50    #[inline]
51    pub fn delete(&self, pos: u32, len: u32) -> LoroResult<()> {
52        self.inner.delete(pos as usize, len as usize)
53    }
54
55    /// Get the value at the given position.
56    #[inline]
57    pub fn get(&self, index: u32) -> Option<Arc<dyn ValueOrContainer>> {
58        self.inner
59            .get(index as usize)
60            .map(|v| Arc::new(v) as Arc<dyn ValueOrContainer>)
61    }
62
63    /// Get the length of the list.
64    pub fn len(&self) -> u32 {
65        self.inner.len() as u32
66    }
67
68    /// Whether the list is empty.
69    #[must_use]
70    pub fn is_empty(&self) -> bool {
71        self.len() == 0
72    }
73
74    /// Get the shallow value of the list.
75    ///
76    /// It will not convert the state of sub-containers, but represent them as [LoroValue::Container].
77    pub fn get_value(&self) -> LoroValue {
78        self.inner.get_value().into()
79    }
80
81    /// Get the deep value of the list.
82    ///
83    /// It will convert the state of sub-containers into a nested JSON value.
84    pub fn get_deep_value(&self) -> LoroValue {
85        self.inner.get_deep_value().into()
86    }
87
88    /// Pop the last element of the list.
89    #[inline]
90    pub fn pop(&self) -> LoroResult<Option<Arc<dyn ValueOrContainer>>> {
91        self.inner
92            .pop()
93            .map(|v| v.map(|v| Arc::new(v) as Arc<dyn ValueOrContainer>))
94    }
95
96    #[inline]
97    pub fn push(&self, v: Arc<dyn LoroValueLike>) -> LoroResult<()> {
98        self.inner.push(v.as_loro_value())
99    }
100
101    #[inline]
102    pub fn insert_list_container(
103        &self,
104        pos: u32,
105        child: Arc<LoroList>,
106    ) -> LoroResult<Arc<LoroList>> {
107        let c = self
108            .inner
109            .insert_container(pos as usize, child.as_ref().clone().inner)?;
110        Ok(Arc::new(LoroList { inner: c }))
111    }
112
113    #[inline]
114    pub fn insert_map_container(&self, pos: u32, child: Arc<LoroMap>) -> LoroResult<Arc<LoroMap>> {
115        let c = self
116            .inner
117            .insert_container(pos as usize, child.as_ref().clone().inner)?;
118        Ok(Arc::new(LoroMap { inner: c }))
119    }
120
121    #[inline]
122    pub fn insert_text_container(
123        &self,
124        pos: u32,
125        child: Arc<LoroText>,
126    ) -> LoroResult<Arc<LoroText>> {
127        let c = self
128            .inner
129            .insert_container(pos as usize, child.as_ref().clone().inner)?;
130        Ok(Arc::new(LoroText { inner: c }))
131    }
132
133    #[inline]
134    pub fn insert_tree_container(
135        &self,
136        pos: u32,
137        child: Arc<LoroTree>,
138    ) -> LoroResult<Arc<LoroTree>> {
139        let c = self
140            .inner
141            .insert_container(pos as usize, child.as_ref().clone().inner)?;
142        Ok(Arc::new(LoroTree { inner: c }))
143    }
144
145    #[inline]
146    pub fn insert_movable_list_container(
147        &self,
148        pos: u32,
149        child: Arc<LoroMovableList>,
150    ) -> LoroResult<Arc<LoroMovableList>> {
151        let c = self
152            .inner
153            .insert_container(pos as usize, child.as_ref().clone().inner)?;
154        Ok(Arc::new(LoroMovableList { inner: c }))
155    }
156
157    #[inline]
158    pub fn insert_counter_container(
159        &self,
160        pos: u32,
161        child: Arc<LoroCounter>,
162    ) -> LoroResult<Arc<LoroCounter>> {
163        let c = self
164            .inner
165            .insert_container(pos as usize, child.as_ref().clone().inner)?;
166        Ok(Arc::new(LoroCounter { inner: c }))
167    }
168
169    #[inline]
170    pub fn set_list_container(&self, pos: u32, child: Arc<LoroList>) -> LoroResult<Arc<LoroList>> {
171        let c = self
172            .inner
173            .set_container(pos as usize, child.as_ref().clone().inner)?;
174        Ok(Arc::new(LoroList { inner: c }))
175    }
176
177    #[inline]
178    pub fn set_map_container(&self, pos: u32, child: Arc<LoroMap>) -> LoroResult<Arc<LoroMap>> {
179        let c = self
180            .inner
181            .set_container(pos as usize, child.as_ref().clone().inner)?;
182        Ok(Arc::new(LoroMap { inner: c }))
183    }
184
185    #[inline]
186    pub fn set_text_container(&self, pos: u32, child: Arc<LoroText>) -> LoroResult<Arc<LoroText>> {
187        let c = self
188            .inner
189            .set_container(pos as usize, child.as_ref().clone().inner)?;
190        Ok(Arc::new(LoroText { inner: c }))
191    }
192
193    #[inline]
194    pub fn set_tree_container(&self, pos: u32, child: Arc<LoroTree>) -> LoroResult<Arc<LoroTree>> {
195        let c = self
196            .inner
197            .set_container(pos as usize, child.as_ref().clone().inner)?;
198        Ok(Arc::new(LoroTree { inner: c }))
199    }
200
201    #[inline]
202    pub fn set_movable_list_container(
203        &self,
204        pos: u32,
205        child: Arc<LoroMovableList>,
206    ) -> LoroResult<Arc<LoroMovableList>> {
207        let c = self
208            .inner
209            .set_container(pos as usize, child.as_ref().clone().inner)?;
210        Ok(Arc::new(LoroMovableList { inner: c }))
211    }
212
213    #[inline]
214    pub fn set_counter_container(
215        &self,
216        pos: u32,
217        child: Arc<LoroCounter>,
218    ) -> LoroResult<Arc<LoroCounter>> {
219        let c = self
220            .inner
221            .set_container(pos as usize, child.as_ref().clone().inner)?;
222        Ok(Arc::new(LoroCounter { inner: c }))
223    }
224
225    /// Set the value at the given position.
226    pub fn set(&self, pos: u32, value: Arc<dyn LoroValueLike>) -> LoroResult<()> {
227        self.inner.set(pos as usize, value.as_loro_value())
228    }
229
230    /// Move the value at the given position to the given position.
231    pub fn mov(&self, from: u32, to: u32) -> LoroResult<()> {
232        self.inner.mov(from as usize, to as usize)
233    }
234
235    /// Get the cursor at the given position.
236    ///
237    /// Using "index" to denote cursor positions can be unstable, as positions may
238    /// shift with document edits. To reliably represent a position or range within
239    /// a document, it is more effective to leverage the unique ID of each item/character
240    /// in a List CRDT or Text CRDT.
241    ///
242    /// Loro optimizes State metadata by not storing the IDs of deleted elements. This
243    /// approach complicates tracking cursors since they rely on these IDs. The solution
244    /// recalculates position by replaying relevant history to update stable positions
245    /// accurately. To minimize the performance impact of history replay, the system
246    /// updates cursor info to reference only the IDs of currently present elements,
247    /// thereby reducing the need for replay.
248    pub fn get_cursor(&self, pos: u32, side: Side) -> Option<Arc<Cursor>> {
249        self.inner
250            .get_cursor(pos as usize, side)
251            .map(|v| Arc::new(v.into()))
252    }
253
254    pub fn to_vec(&self) -> Vec<LoroValue> {
255        self.inner.to_vec().into_iter().map(|v| v.into()).collect()
256    }
257
258    pub fn clear(&self) -> LoroResult<()> {
259        self.inner.clear()
260    }
261
262    pub fn is_deleted(&self) -> bool {
263        self.inner.is_deleted()
264    }
265
266    pub fn get_creator_at(&self, index: u32) -> Option<PeerID> {
267        self.inner.get_creator_at(index as usize)
268    }
269
270    pub fn get_last_mover_at(&self, index: u32) -> Option<PeerID> {
271        self.inner.get_last_mover_at(index as usize)
272    }
273
274    pub fn get_last_editor_at(&self, index: u32) -> Option<PeerID> {
275        self.inner.get_last_editor_at(index as usize)
276    }
277
278    pub fn doc(&self) -> Option<Arc<LoroDoc>> {
279        self.inner.doc().map(|x| Arc::new(LoroDoc { doc: x }))
280    }
281
282    pub fn subscribe(&self, subscriber: Arc<dyn Subscriber>) -> Option<Arc<Subscription>> {
283        self.inner
284            .subscribe(Arc::new(move |e| {
285                subscriber.on_diff(DiffEvent::from(e));
286            }))
287            .map(|x| Arc::new(x.into()))
288    }
289}
290
291impl Default for LoroMovableList {
292    fn default() -> Self {
293        Self::new()
294    }
295}