1use super::{state::DocState, txn::Transaction};
2use crate::sync::Mutex;
3use crate::{
4 container::{
5 idx::ContainerIdx,
6 list::list_op::{DeleteSpan, DeleteSpanWithId, ListOp},
7 richtext::{richtext_state::PosType, RichtextState, StyleOp, TextStyleInfoFlag},
8 },
9 cursor::{Cursor, Side},
10 delta::{DeltaItem, Meta, StyleMeta, TreeExternalDiff},
11 diff::{diff, diff_impl::UpdateTimeoutError, OperateProxy},
12 event::{Diff, TextDiff, TextDiffItem, TextMeta},
13 op::ListSlice,
14 state::{IndexType, State, TreeParentId},
15 txn::EventHint,
16 utils::{string_slice::StringSlice, utf16::count_utf16_len},
17 LoroDoc, LoroDocInner,
18};
19use append_only_bytes::BytesSlice;
20use enum_as_inner::EnumAsInner;
21use fxhash::FxHashMap;
22use generic_btree::rle::HasLength;
23use loro_common::{
24 ContainerID, ContainerType, IdFull, InternalString, LoroError, LoroResult, LoroValue, PeerID,
25 TreeID, ID,
26};
27use serde::{Deserialize, Serialize};
28use std::{borrow::Cow, cmp::Reverse, collections::BinaryHeap, fmt::Debug, ops::Deref, sync::Arc};
29use tracing::{error, info, instrument};
30
31pub use crate::diff::diff_impl::UpdateOptions;
32pub use tree::TreeHandler;
33mod movable_list_apply_delta;
34mod tree;
35
36const INSERT_CONTAINER_VALUE_ARG_ERROR: &str =
37 "Cannot insert a LoroValue::Container directly. To create child container, use insert_container";
38
39mod text_update;
40
41pub trait HandlerTrait: Clone + Sized {
42 fn is_attached(&self) -> bool;
43 fn attached_handler(&self) -> Option<&BasicHandler>;
44 fn get_value(&self) -> LoroValue;
45 fn get_deep_value(&self) -> LoroValue;
46 fn kind(&self) -> ContainerType;
47 fn to_handler(&self) -> Handler;
48 fn from_handler(h: Handler) -> Option<Self>;
49 fn doc(&self) -> Option<LoroDoc>;
50 fn attach(
52 &self,
53 txn: &mut Transaction,
54 parent: &BasicHandler,
55 self_id: ContainerID,
56 ) -> LoroResult<Self>;
57 fn get_attached(&self) -> Option<Self>;
59
60 fn parent(&self) -> Option<Handler> {
61 self.attached_handler().and_then(|x| x.parent())
62 }
63
64 fn idx(&self) -> ContainerIdx {
65 self.attached_handler()
66 .map(|x| x.container_idx)
67 .unwrap_or_else(|| ContainerIdx::from_index_and_type(u32::MAX, self.kind()))
68 }
69
70 fn id(&self) -> ContainerID {
71 self.attached_handler()
72 .map(|x| x.id.clone())
73 .unwrap_or_else(|| ContainerID::new_normal(ID::NONE_ID, self.kind()))
74 }
75
76 fn with_state<R>(&self, f: impl FnOnce(&mut State) -> LoroResult<R>) -> LoroResult<R> {
77 let inner = self
78 .attached_handler()
79 .ok_or(LoroError::MisuseDetachedContainer {
80 method: "with_state",
81 })?;
82 let state = inner.doc.state.clone();
83 let mut guard = state.lock().unwrap();
84 guard.with_state_mut(inner.container_idx, f)
85 }
86}
87
88fn create_handler(inner: &BasicHandler, id: ContainerID) -> Handler {
89 Handler::new_attached(id, inner.doc.clone())
90}
91
92#[derive(Clone, Debug)]
94pub struct BasicHandler {
95 id: ContainerID,
96 container_idx: ContainerIdx,
97 doc: LoroDoc,
98}
99
100struct DetachedInner<T> {
101 value: T,
102 attached: Option<BasicHandler>,
104}
105
106impl<T> DetachedInner<T> {
107 fn new(v: T) -> Self {
108 Self {
109 value: v,
110 attached: None,
111 }
112 }
113}
114
115enum MaybeDetached<T> {
116 Detached(Arc<Mutex<DetachedInner<T>>>),
117 Attached(BasicHandler),
118}
119
120impl<T> Clone for MaybeDetached<T> {
121 fn clone(&self) -> Self {
122 match self {
123 MaybeDetached::Detached(a) => MaybeDetached::Detached(Arc::clone(a)),
124 MaybeDetached::Attached(a) => MaybeDetached::Attached(a.clone()),
125 }
126 }
127}
128
129impl<T> MaybeDetached<T> {
130 fn new_detached(v: T) -> Self {
131 MaybeDetached::Detached(Arc::new(Mutex::new(DetachedInner::new(v))))
132 }
133
134 fn is_attached(&self) -> bool {
135 match self {
136 MaybeDetached::Detached(_) => false,
137 MaybeDetached::Attached(_) => true,
138 }
139 }
140
141 fn attached_handler(&self) -> Option<&BasicHandler> {
142 match self {
143 MaybeDetached::Detached(_) => None,
144 MaybeDetached::Attached(a) => Some(a),
145 }
146 }
147
148 fn try_attached_state(&self) -> LoroResult<&BasicHandler> {
149 match self {
150 MaybeDetached::Detached(_) => Err(LoroError::MisuseDetachedContainer {
151 method: "inner_state",
152 }),
153 MaybeDetached::Attached(a) => Ok(a),
154 }
155 }
156}
157
158impl<T> From<BasicHandler> for MaybeDetached<T> {
159 fn from(a: BasicHandler) -> Self {
160 MaybeDetached::Attached(a)
161 }
162}
163
164impl BasicHandler {
165 pub(crate) fn doc(&self) -> LoroDoc {
166 self.doc.clone()
167 }
168
169 #[inline]
170 fn with_doc_state<R>(&self, f: impl FnOnce(&mut DocState) -> R) -> R {
171 let state = self.doc.state.clone();
172 let mut guard = state.lock().unwrap();
173 f(&mut guard)
174 }
175
176 fn with_txn<R>(
177 &self,
178 f: impl FnOnce(&mut Transaction) -> Result<R, LoroError>,
179 ) -> Result<R, LoroError> {
180 with_txn(&self.doc, f)
181 }
182
183 fn get_parent(&self) -> Option<Handler> {
184 let parent_idx = self.doc.arena.get_parent(self.container_idx)?;
185 let parent_id = self.doc.arena.get_container_id(parent_idx).unwrap();
186 {
187 let kind = parent_id.container_type();
188 let handler = BasicHandler {
189 container_idx: parent_idx,
190 id: parent_id,
191 doc: self.doc.clone(),
192 };
193
194 Some(match kind {
195 ContainerType::Map => Handler::Map(MapHandler {
196 inner: handler.into(),
197 }),
198 ContainerType::List => Handler::List(ListHandler {
199 inner: handler.into(),
200 }),
201 ContainerType::Tree => Handler::Tree(TreeHandler {
202 inner: handler.into(),
203 }),
204 ContainerType::Text => Handler::Text(TextHandler {
205 inner: handler.into(),
206 }),
207 ContainerType::MovableList => Handler::MovableList(MovableListHandler {
208 inner: handler.into(),
209 }),
210 #[cfg(feature = "counter")]
211 ContainerType::Counter => Handler::Counter(counter::CounterHandler {
212 inner: handler.into(),
213 }),
214 ContainerType::Unknown(_) => unreachable!(),
215 })
216 }
217 }
218
219 pub fn get_value(&self) -> LoroValue {
220 tracing::trace!("get_value");
221 self.doc
222 .state
223 .lock()
224 .unwrap()
225 .get_value_by_idx(self.container_idx)
226 }
227
228 pub fn get_deep_value(&self) -> LoroValue {
229 self.doc
230 .state
231 .lock()
232 .unwrap()
233 .get_container_deep_value(self.container_idx)
234 }
235
236 fn with_state<R>(&self, f: impl FnOnce(&mut State) -> R) -> R {
237 let mut guard = self.doc.state.lock().unwrap();
238 guard.with_state_mut(self.container_idx, f)
239 }
240
241 pub fn parent(&self) -> Option<Handler> {
242 self.get_parent()
243 }
244
245 fn is_deleted(&self) -> bool {
246 self.doc
247 .state
248 .lock()
249 .unwrap()
250 .is_deleted(self.container_idx)
251 }
252}
253
254#[derive(Clone)]
256pub struct TextHandler {
257 inner: MaybeDetached<RichtextState>,
258}
259
260impl HandlerTrait for TextHandler {
261 fn to_handler(&self) -> Handler {
262 Handler::Text(self.clone())
263 }
264
265 fn attach(
266 &self,
267 txn: &mut Transaction,
268 parent: &BasicHandler,
269 self_id: ContainerID,
270 ) -> LoroResult<Self> {
271 match &self.inner {
272 MaybeDetached::Detached(t) => {
273 let mut t = t.lock().unwrap();
274 let inner = create_handler(parent, self_id);
275 let text = inner.into_text().unwrap();
276 let mut delta: Vec<TextDelta> = Vec::new();
277 for span in t.value.iter() {
278 delta.push(TextDelta::Insert {
279 insert: span.text.to_string(),
280 attributes: span.attributes.to_option_map(),
281 });
282 }
283
284 text.apply_delta_with_txn(txn, &delta)?;
285 t.attached = text.attached_handler().cloned();
286 Ok(text)
287 }
288 MaybeDetached::Attached(a) => {
289 let new_inner = create_handler(a, self_id);
290 let ans = new_inner.into_text().unwrap();
291
292 let delta = self.get_delta();
293 ans.apply_delta_with_txn(txn, &delta).unwrap();
294 Ok(ans)
295 }
296 }
297 }
298
299 fn attached_handler(&self) -> Option<&BasicHandler> {
300 self.inner.attached_handler()
301 }
302
303 fn get_value(&self) -> LoroValue {
304 match &self.inner {
305 MaybeDetached::Detached(t) => {
306 let t = t.lock().unwrap();
307 LoroValue::String((t.value.to_string()).into())
308 }
309 MaybeDetached::Attached(a) => a.get_value(),
310 }
311 }
312
313 fn get_deep_value(&self) -> LoroValue {
314 self.get_value()
315 }
316
317 fn is_attached(&self) -> bool {
318 matches!(&self.inner, MaybeDetached::Attached(..))
319 }
320
321 fn kind(&self) -> ContainerType {
322 ContainerType::Text
323 }
324
325 fn get_attached(&self) -> Option<Self> {
326 match &self.inner {
327 MaybeDetached::Detached(d) => d.lock().unwrap().attached.clone().map(|x| Self {
328 inner: MaybeDetached::Attached(x),
329 }),
330 MaybeDetached::Attached(_a) => Some(self.clone()),
331 }
332 }
333
334 fn from_handler(h: Handler) -> Option<Self> {
335 match h {
336 Handler::Text(x) => Some(x),
337 _ => None,
338 }
339 }
340
341 fn doc(&self) -> Option<LoroDoc> {
342 match &self.inner {
343 MaybeDetached::Detached(_) => None,
344 MaybeDetached::Attached(a) => Some(a.doc()),
345 }
346 }
347}
348
349impl std::fmt::Debug for TextHandler {
350 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
351 match &self.inner {
352 MaybeDetached::Detached(_) => {
353 write!(f, "TextHandler(Unattached)")
354 }
355 MaybeDetached::Attached(a) => {
356 write!(f, "TextHandler({:?})", &a.id)
357 }
358 }
359 }
360}
361
362#[derive(Debug, Clone, EnumAsInner, Deserialize, Serialize, PartialEq)]
363#[serde(untagged)]
364pub enum TextDelta {
365 Retain {
366 retain: usize,
367 attributes: Option<FxHashMap<String, LoroValue>>,
368 },
369 Insert {
370 insert: String,
371 attributes: Option<FxHashMap<String, LoroValue>>,
372 },
373 Delete {
374 delete: usize,
375 },
376}
377
378impl TextDelta {
379 pub fn from_text_diff<'a>(diff: impl Iterator<Item = &'a TextDiffItem>) -> Vec<TextDelta> {
380 let mut ans = Vec::with_capacity(diff.size_hint().0);
381 for iter in diff {
382 match iter {
383 loro_delta::DeltaItem::Retain { len, attr } => {
384 ans.push(TextDelta::Retain {
385 retain: *len,
386 attributes: if attr.0.is_empty() {
387 None
388 } else {
389 Some(attr.0.clone())
390 },
391 });
392 }
393 loro_delta::DeltaItem::Replace {
394 value,
395 attr,
396 delete,
397 } => {
398 if value.rle_len() > 0 {
399 ans.push(TextDelta::Insert {
400 insert: value.to_string(),
401 attributes: if attr.0.is_empty() {
402 None
403 } else {
404 Some(attr.0.clone())
405 },
406 });
407 }
408 if *delete > 0 {
409 ans.push(TextDelta::Delete { delete: *delete });
410 }
411 }
412 }
413 }
414
415 ans
416 }
417
418 pub fn into_text_diff(vec: impl Iterator<Item = Self>) -> TextDiff {
419 let mut delta = TextDiff::new();
420 for item in vec {
421 match item {
422 TextDelta::Retain { retain, attributes } => {
423 delta.push_retain(retain, TextMeta(attributes.unwrap_or_default().clone()));
424 }
425 TextDelta::Insert { insert, attributes } => {
426 delta.push_insert(
427 StringSlice::from(insert.as_str()),
428 TextMeta(attributes.unwrap_or_default()),
429 );
430 }
431 TextDelta::Delete { delete } => {
432 delta.push_delete(delete);
433 }
434 }
435 }
436
437 delta
438 }
439}
440
441impl From<&DeltaItem<StringSlice, StyleMeta>> for TextDelta {
442 fn from(value: &DeltaItem<StringSlice, StyleMeta>) -> Self {
443 match value {
444 crate::delta::DeltaItem::Retain { retain, attributes } => TextDelta::Retain {
445 retain: *retain,
446 attributes: attributes.to_option_map(),
447 },
448 crate::delta::DeltaItem::Insert { insert, attributes } => TextDelta::Insert {
449 insert: insert.to_string(),
450 attributes: attributes.to_option_map(),
451 },
452 crate::delta::DeltaItem::Delete {
453 delete,
454 attributes: _,
455 } => TextDelta::Delete { delete: *delete },
456 }
457 }
458}
459
460#[derive(Clone)]
461pub struct MapHandler {
462 inner: MaybeDetached<FxHashMap<String, ValueOrHandler>>,
463}
464
465impl HandlerTrait for MapHandler {
466 fn is_attached(&self) -> bool {
467 matches!(&self.inner, MaybeDetached::Attached(..))
468 }
469
470 fn attached_handler(&self) -> Option<&BasicHandler> {
471 match &self.inner {
472 MaybeDetached::Detached(_) => None,
473 MaybeDetached::Attached(a) => Some(a),
474 }
475 }
476
477 fn get_value(&self) -> LoroValue {
478 match &self.inner {
479 MaybeDetached::Detached(m) => {
480 let m = m.lock().unwrap();
481 let mut map = FxHashMap::default();
482 for (k, v) in m.value.iter() {
483 map.insert(k.to_string(), v.to_value());
484 }
485 LoroValue::Map(map.into())
486 }
487 MaybeDetached::Attached(a) => a.get_value(),
488 }
489 }
490
491 fn get_deep_value(&self) -> LoroValue {
492 match &self.inner {
493 MaybeDetached::Detached(m) => {
494 let m = m.lock().unwrap();
495 let mut map = FxHashMap::default();
496 for (k, v) in m.value.iter() {
497 map.insert(k.to_string(), v.to_deep_value());
498 }
499 LoroValue::Map(map.into())
500 }
501 MaybeDetached::Attached(a) => a.get_deep_value(),
502 }
503 }
504
505 fn kind(&self) -> ContainerType {
506 ContainerType::Map
507 }
508
509 fn to_handler(&self) -> Handler {
510 Handler::Map(self.clone())
511 }
512
513 fn attach(
514 &self,
515 txn: &mut Transaction,
516 parent: &BasicHandler,
517 self_id: ContainerID,
518 ) -> LoroResult<Self> {
519 match &self.inner {
520 MaybeDetached::Detached(m) => {
521 let mut m = m.lock().unwrap();
522 let inner = create_handler(parent, self_id);
523 let map = inner.into_map().unwrap();
524 for (k, v) in m.value.iter() {
525 match v {
526 ValueOrHandler::Value(v) => {
527 map.insert_with_txn(txn, k, v.clone())?;
528 }
529 ValueOrHandler::Handler(h) => {
530 map.insert_container_with_txn(txn, k, h.clone())?;
531 }
532 }
533 }
534 m.attached = map.attached_handler().cloned();
535 Ok(map)
536 }
537 MaybeDetached::Attached(a) => {
538 let new_inner = create_handler(a, self_id);
539 let ans = new_inner.into_map().unwrap();
540
541 for (k, v) in self.get_value().into_map().unwrap().iter() {
542 if let LoroValue::Container(id) = v {
543 ans.insert_container_with_txn(txn, k, create_handler(a, id.clone()))
544 .unwrap();
545 } else {
546 ans.insert_with_txn(txn, k, v.clone()).unwrap();
547 }
548 }
549
550 Ok(ans)
551 }
552 }
553 }
554
555 fn get_attached(&self) -> Option<Self> {
556 match &self.inner {
557 MaybeDetached::Detached(d) => d.lock().unwrap().attached.clone().map(|x| Self {
558 inner: MaybeDetached::Attached(x),
559 }),
560 MaybeDetached::Attached(_a) => Some(self.clone()),
561 }
562 }
563
564 fn from_handler(h: Handler) -> Option<Self> {
565 match h {
566 Handler::Map(x) => Some(x),
567 _ => None,
568 }
569 }
570
571 fn doc(&self) -> Option<LoroDoc> {
572 match &self.inner {
573 MaybeDetached::Detached(_) => None,
574 MaybeDetached::Attached(a) => Some(a.doc()),
575 }
576 }
577}
578
579impl std::fmt::Debug for MapHandler {
580 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
581 match &self.inner {
582 MaybeDetached::Detached(_) => write!(f, "MapHandler Detached"),
583 MaybeDetached::Attached(a) => write!(f, "MapHandler {}", a.id),
584 }
585 }
586}
587
588#[derive(Clone)]
589pub struct ListHandler {
590 inner: MaybeDetached<Vec<ValueOrHandler>>,
591}
592
593#[derive(Clone)]
594pub struct MovableListHandler {
595 inner: MaybeDetached<Vec<ValueOrHandler>>,
596}
597
598impl HandlerTrait for MovableListHandler {
599 fn is_attached(&self) -> bool {
600 matches!(&self.inner, MaybeDetached::Attached(..))
601 }
602
603 fn attached_handler(&self) -> Option<&BasicHandler> {
604 match &self.inner {
605 MaybeDetached::Detached(_) => None,
606 MaybeDetached::Attached(a) => Some(a),
607 }
608 }
609
610 fn get_value(&self) -> LoroValue {
611 match &self.inner {
612 MaybeDetached::Detached(a) => {
613 let a = a.lock().unwrap();
614 LoroValue::List(a.value.iter().map(|v| v.to_value()).collect())
615 }
616 MaybeDetached::Attached(a) => a.get_value(),
617 }
618 }
619
620 fn get_deep_value(&self) -> LoroValue {
621 match &self.inner {
622 MaybeDetached::Detached(a) => {
623 let a = a.lock().unwrap();
624 LoroValue::List(a.value.iter().map(|v| v.to_deep_value()).collect())
625 }
626 MaybeDetached::Attached(a) => a.get_deep_value(),
627 }
628 }
629
630 fn kind(&self) -> ContainerType {
631 ContainerType::MovableList
632 }
633
634 fn to_handler(&self) -> Handler {
635 Handler::MovableList(self.clone())
636 }
637
638 fn from_handler(h: Handler) -> Option<Self> {
639 match h {
640 Handler::MovableList(x) => Some(x),
641 _ => None,
642 }
643 }
644
645 fn attach(
646 &self,
647 txn: &mut Transaction,
648 parent: &BasicHandler,
649 self_id: ContainerID,
650 ) -> LoroResult<Self> {
651 match &self.inner {
652 MaybeDetached::Detached(l) => {
653 let mut l = l.lock().unwrap();
654 let inner = create_handler(parent, self_id);
655 let list = inner.into_movable_list().unwrap();
656 for (index, v) in l.value.iter().enumerate() {
657 match v {
658 ValueOrHandler::Value(v) => {
659 list.insert_with_txn(txn, index, v.clone())?;
660 }
661 ValueOrHandler::Handler(h) => {
662 list.insert_container_with_txn(txn, index, h.clone())?;
663 }
664 }
665 }
666 l.attached = list.attached_handler().cloned();
667 Ok(list)
668 }
669 MaybeDetached::Attached(a) => {
670 let new_inner = create_handler(a, self_id);
671 let ans = new_inner.into_movable_list().unwrap();
672
673 for (i, v) in self.get_value().into_list().unwrap().iter().enumerate() {
674 if let LoroValue::Container(id) = v {
675 ans.insert_container_with_txn(txn, i, create_handler(a, id.clone()))
676 .unwrap();
677 } else {
678 ans.insert_with_txn(txn, i, v.clone()).unwrap();
679 }
680 }
681
682 Ok(ans)
683 }
684 }
685 }
686
687 fn get_attached(&self) -> Option<Self> {
688 match &self.inner {
689 MaybeDetached::Detached(d) => d.lock().unwrap().attached.clone().map(|x| Self {
690 inner: MaybeDetached::Attached(x),
691 }),
692 MaybeDetached::Attached(_a) => Some(self.clone()),
693 }
694 }
695
696 fn doc(&self) -> Option<LoroDoc> {
697 match &self.inner {
698 MaybeDetached::Detached(_) => None,
699 MaybeDetached::Attached(a) => Some(a.doc()),
700 }
701 }
702}
703
704impl std::fmt::Debug for MovableListHandler {
705 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
706 write!(f, "MovableListHandler {}", self.id())
707 }
708}
709
710impl std::fmt::Debug for ListHandler {
711 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
712 match &self.inner {
713 MaybeDetached::Detached(_) => write!(f, "ListHandler Detached"),
714 MaybeDetached::Attached(a) => write!(f, "ListHandler {}", a.id),
715 }
716 }
717}
718
719impl HandlerTrait for ListHandler {
720 fn is_attached(&self) -> bool {
721 self.inner.is_attached()
722 }
723
724 fn attached_handler(&self) -> Option<&BasicHandler> {
725 self.inner.attached_handler()
726 }
727
728 fn get_value(&self) -> LoroValue {
729 match &self.inner {
730 MaybeDetached::Detached(a) => {
731 let a = a.lock().unwrap();
732 LoroValue::List(a.value.iter().map(|v| v.to_value()).collect())
733 }
734 MaybeDetached::Attached(a) => a.get_value(),
735 }
736 }
737
738 fn get_deep_value(&self) -> LoroValue {
739 match &self.inner {
740 MaybeDetached::Detached(a) => {
741 let a = a.lock().unwrap();
742 LoroValue::List(a.value.iter().map(|v| v.to_deep_value()).collect())
743 }
744 MaybeDetached::Attached(a) => a.get_deep_value(),
745 }
746 }
747
748 fn kind(&self) -> ContainerType {
749 ContainerType::List
750 }
751
752 fn to_handler(&self) -> Handler {
753 Handler::List(self.clone())
754 }
755
756 fn attach(
757 &self,
758 txn: &mut Transaction,
759 parent: &BasicHandler,
760 self_id: ContainerID,
761 ) -> LoroResult<Self> {
762 match &self.inner {
763 MaybeDetached::Detached(l) => {
764 let mut l = l.lock().unwrap();
765 let inner = create_handler(parent, self_id);
766 let list = inner.into_list().unwrap();
767 for (index, v) in l.value.iter().enumerate() {
768 match v {
769 ValueOrHandler::Value(v) => {
770 list.insert_with_txn(txn, index, v.clone())?;
771 }
772 ValueOrHandler::Handler(h) => {
773 list.insert_container_with_txn(txn, index, h.clone())?;
774 }
775 }
776 }
777 l.attached = list.attached_handler().cloned();
778 Ok(list)
779 }
780 MaybeDetached::Attached(a) => {
781 let new_inner = create_handler(a, self_id);
782 let ans = new_inner.into_list().unwrap();
783
784 for (i, v) in self.get_value().into_list().unwrap().iter().enumerate() {
785 if let LoroValue::Container(id) = v {
786 ans.insert_container_with_txn(txn, i, create_handler(a, id.clone()))
787 .unwrap();
788 } else {
789 ans.insert_with_txn(txn, i, v.clone()).unwrap();
790 }
791 }
792
793 Ok(ans)
794 }
795 }
796 }
797
798 fn get_attached(&self) -> Option<Self> {
799 match &self.inner {
800 MaybeDetached::Detached(d) => d.lock().unwrap().attached.clone().map(|x| Self {
801 inner: MaybeDetached::Attached(x),
802 }),
803 MaybeDetached::Attached(_a) => Some(self.clone()),
804 }
805 }
806
807 fn from_handler(h: Handler) -> Option<Self> {
808 match h {
809 Handler::List(x) => Some(x),
810 _ => None,
811 }
812 }
813
814 fn doc(&self) -> Option<LoroDoc> {
815 match &self.inner {
816 MaybeDetached::Detached(_) => None,
817 MaybeDetached::Attached(a) => Some(a.doc()),
818 }
819 }
820}
821
822#[derive(Clone)]
823pub struct UnknownHandler {
824 inner: BasicHandler,
825}
826
827impl Debug for UnknownHandler {
828 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
829 write!(f, "UnknownHandler")
830 }
831}
832
833impl UnknownHandler {
834 pub fn is_deleted(&self) -> bool {
835 self.inner.is_deleted()
836 }
837}
838
839impl HandlerTrait for UnknownHandler {
840 fn is_attached(&self) -> bool {
841 true
842 }
843
844 fn attached_handler(&self) -> Option<&BasicHandler> {
845 Some(&self.inner)
846 }
847
848 fn get_value(&self) -> LoroValue {
849 todo!()
850 }
851
852 fn get_deep_value(&self) -> LoroValue {
853 todo!()
854 }
855
856 fn kind(&self) -> ContainerType {
857 self.inner.id.container_type()
858 }
859
860 fn to_handler(&self) -> Handler {
861 Handler::Unknown(self.clone())
862 }
863
864 fn from_handler(h: Handler) -> Option<Self> {
865 match h {
866 Handler::Unknown(x) => Some(x),
867 _ => None,
868 }
869 }
870
871 fn attach(
872 &self,
873 _txn: &mut Transaction,
874 _parent: &BasicHandler,
875 self_id: ContainerID,
876 ) -> LoroResult<Self> {
877 let new_inner = create_handler(&self.inner, self_id);
878 let ans = new_inner.into_unknown().unwrap();
879 Ok(ans)
880 }
881
882 fn get_attached(&self) -> Option<Self> {
883 Some(self.clone())
884 }
885
886 fn doc(&self) -> Option<LoroDoc> {
887 Some(self.inner.doc())
888 }
889}
890
891#[derive(Clone, EnumAsInner, Debug)]
892pub enum Handler {
893 Text(TextHandler),
894 Map(MapHandler),
895 List(ListHandler),
896 MovableList(MovableListHandler),
897 Tree(TreeHandler),
898 #[cfg(feature = "counter")]
899 Counter(counter::CounterHandler),
900 Unknown(UnknownHandler),
901}
902
903impl HandlerTrait for Handler {
904 fn is_attached(&self) -> bool {
905 match self {
906 Self::Text(x) => x.is_attached(),
907 Self::Map(x) => x.is_attached(),
908 Self::List(x) => x.is_attached(),
909 Self::Tree(x) => x.is_attached(),
910 Self::MovableList(x) => x.is_attached(),
911 #[cfg(feature = "counter")]
912 Self::Counter(x) => x.is_attached(),
913 Self::Unknown(x) => x.is_attached(),
914 }
915 }
916
917 fn attached_handler(&self) -> Option<&BasicHandler> {
918 match self {
919 Self::Text(x) => x.attached_handler(),
920 Self::Map(x) => x.attached_handler(),
921 Self::List(x) => x.attached_handler(),
922 Self::MovableList(x) => x.attached_handler(),
923 Self::Tree(x) => x.attached_handler(),
924 #[cfg(feature = "counter")]
925 Self::Counter(x) => x.attached_handler(),
926 Self::Unknown(x) => x.attached_handler(),
927 }
928 }
929
930 fn get_value(&self) -> LoroValue {
931 match self {
932 Self::Text(x) => x.get_value(),
933 Self::Map(x) => x.get_value(),
934 Self::List(x) => x.get_value(),
935 Self::MovableList(x) => x.get_value(),
936 Self::Tree(x) => x.get_value(),
937 #[cfg(feature = "counter")]
938 Self::Counter(x) => x.get_value(),
939 Self::Unknown(x) => x.get_value(),
940 }
941 }
942
943 fn get_deep_value(&self) -> LoroValue {
944 match self {
945 Self::Text(x) => x.get_deep_value(),
946 Self::Map(x) => x.get_deep_value(),
947 Self::List(x) => x.get_deep_value(),
948 Self::MovableList(x) => x.get_deep_value(),
949 Self::Tree(x) => x.get_deep_value(),
950 #[cfg(feature = "counter")]
951 Self::Counter(x) => x.get_deep_value(),
952 Self::Unknown(x) => x.get_deep_value(),
953 }
954 }
955
956 fn kind(&self) -> ContainerType {
957 match self {
958 Self::Text(x) => x.kind(),
959 Self::Map(x) => x.kind(),
960 Self::List(x) => x.kind(),
961 Self::MovableList(x) => x.kind(),
962 Self::Tree(x) => x.kind(),
963 #[cfg(feature = "counter")]
964 Self::Counter(x) => x.kind(),
965 Self::Unknown(x) => x.kind(),
966 }
967 }
968
969 fn to_handler(&self) -> Handler {
970 match self {
971 Self::Text(x) => x.to_handler(),
972 Self::Map(x) => x.to_handler(),
973 Self::List(x) => x.to_handler(),
974 Self::MovableList(x) => x.to_handler(),
975 Self::Tree(x) => x.to_handler(),
976 #[cfg(feature = "counter")]
977 Self::Counter(x) => x.to_handler(),
978 Self::Unknown(x) => x.to_handler(),
979 }
980 }
981
982 fn attach(
983 &self,
984 txn: &mut Transaction,
985 parent: &BasicHandler,
986 self_id: ContainerID,
987 ) -> LoroResult<Self> {
988 match self {
989 Self::Text(x) => Ok(Handler::Text(x.attach(txn, parent, self_id)?)),
990 Self::Map(x) => Ok(Handler::Map(x.attach(txn, parent, self_id)?)),
991 Self::List(x) => Ok(Handler::List(x.attach(txn, parent, self_id)?)),
992 Self::MovableList(x) => Ok(Handler::MovableList(x.attach(txn, parent, self_id)?)),
993 Self::Tree(x) => Ok(Handler::Tree(x.attach(txn, parent, self_id)?)),
994 #[cfg(feature = "counter")]
995 Self::Counter(x) => Ok(Handler::Counter(x.attach(txn, parent, self_id)?)),
996 Self::Unknown(x) => Ok(Handler::Unknown(x.attach(txn, parent, self_id)?)),
997 }
998 }
999
1000 fn get_attached(&self) -> Option<Self> {
1001 match self {
1002 Self::Text(x) => x.get_attached().map(Handler::Text),
1003 Self::Map(x) => x.get_attached().map(Handler::Map),
1004 Self::List(x) => x.get_attached().map(Handler::List),
1005 Self::MovableList(x) => x.get_attached().map(Handler::MovableList),
1006 Self::Tree(x) => x.get_attached().map(Handler::Tree),
1007 #[cfg(feature = "counter")]
1008 Self::Counter(x) => x.get_attached().map(Handler::Counter),
1009 Self::Unknown(x) => x.get_attached().map(Handler::Unknown),
1010 }
1011 }
1012
1013 fn from_handler(h: Handler) -> Option<Self> {
1014 Some(h)
1015 }
1016
1017 fn doc(&self) -> Option<LoroDoc> {
1018 match self {
1019 Self::Text(x) => x.doc(),
1020 Self::Map(x) => x.doc(),
1021 Self::List(x) => x.doc(),
1022 Self::MovableList(x) => x.doc(),
1023 Self::Tree(x) => x.doc(),
1024 #[cfg(feature = "counter")]
1025 Self::Counter(x) => x.doc(),
1026 Self::Unknown(x) => x.doc(),
1027 }
1028 }
1029}
1030
1031impl Handler {
1032 pub(crate) fn new_attached(id: ContainerID, doc: LoroDoc) -> Self {
1033 let kind = id.container_type();
1034 let handler = BasicHandler {
1035 container_idx: doc.arena.register_container(&id),
1036 id,
1037 doc,
1038 };
1039
1040 match kind {
1041 ContainerType::Map => Self::Map(MapHandler {
1042 inner: handler.into(),
1043 }),
1044 ContainerType::List => Self::List(ListHandler {
1045 inner: handler.into(),
1046 }),
1047 ContainerType::Tree => Self::Tree(TreeHandler {
1048 inner: handler.into(),
1049 }),
1050 ContainerType::Text => Self::Text(TextHandler {
1051 inner: handler.into(),
1052 }),
1053 ContainerType::MovableList => Self::MovableList(MovableListHandler {
1054 inner: handler.into(),
1055 }),
1056 #[cfg(feature = "counter")]
1057 ContainerType::Counter => Self::Counter(counter::CounterHandler {
1058 inner: handler.into(),
1059 }),
1060 ContainerType::Unknown(_) => Self::Unknown(UnknownHandler { inner: handler }),
1061 }
1062 }
1063
1064 #[allow(unused)]
1065 pub(crate) fn new_unattached(kind: ContainerType) -> Self {
1066 match kind {
1067 ContainerType::Text => Self::Text(TextHandler::new_detached()),
1068 ContainerType::Map => Self::Map(MapHandler::new_detached()),
1069 ContainerType::List => Self::List(ListHandler::new_detached()),
1070 ContainerType::Tree => Self::Tree(TreeHandler::new_detached()),
1071 ContainerType::MovableList => Self::MovableList(MovableListHandler::new_detached()),
1072 #[cfg(feature = "counter")]
1073 ContainerType::Counter => Self::Counter(counter::CounterHandler::new_detached()),
1074 ContainerType::Unknown(_) => unreachable!(),
1075 }
1076 }
1077
1078 pub fn id(&self) -> ContainerID {
1079 match self {
1080 Self::Map(x) => x.id(),
1081 Self::List(x) => x.id(),
1082 Self::Text(x) => x.id(),
1083 Self::Tree(x) => x.id(),
1084 Self::MovableList(x) => x.id(),
1085 #[cfg(feature = "counter")]
1086 Self::Counter(x) => x.id(),
1087 Self::Unknown(x) => x.id(),
1088 }
1089 }
1090
1091 pub(crate) fn container_idx(&self) -> ContainerIdx {
1092 match self {
1093 Self::Map(x) => x.idx(),
1094 Self::List(x) => x.idx(),
1095 Self::Text(x) => x.idx(),
1096 Self::Tree(x) => x.idx(),
1097 Self::MovableList(x) => x.idx(),
1098 #[cfg(feature = "counter")]
1099 Self::Counter(x) => x.idx(),
1100 Self::Unknown(x) => x.idx(),
1101 }
1102 }
1103
1104 pub fn c_type(&self) -> ContainerType {
1105 match self {
1106 Self::Map(_) => ContainerType::Map,
1107 Self::List(_) => ContainerType::List,
1108 Self::Text(_) => ContainerType::Text,
1109 Self::Tree(_) => ContainerType::Tree,
1110 Self::MovableList(_) => ContainerType::MovableList,
1111 #[cfg(feature = "counter")]
1112 Self::Counter(_) => ContainerType::Counter,
1113 Self::Unknown(x) => x.id().container_type(),
1114 }
1115 }
1116
1117 fn get_deep_value(&self) -> LoroValue {
1118 match self {
1119 Self::Map(x) => x.get_deep_value(),
1120 Self::List(x) => x.get_deep_value(),
1121 Self::MovableList(x) => x.get_deep_value(),
1122 Self::Text(x) => x.get_deep_value(),
1123 Self::Tree(x) => x.get_deep_value(),
1124 #[cfg(feature = "counter")]
1125 Self::Counter(x) => x.get_deep_value(),
1126 Self::Unknown(x) => x.get_deep_value(),
1127 }
1128 }
1129
1130 pub(crate) fn apply_diff(
1131 &self,
1132 diff: Diff,
1133 container_remap: &mut FxHashMap<ContainerID, ContainerID>,
1134 ) -> LoroResult<()> {
1135 let on_container_remap = &mut |old_id, new_id| {
1138 container_remap.insert(old_id, new_id);
1139 };
1140 match self {
1141 Self::Map(x) => {
1142 let diff = diff.into_map().unwrap();
1143 for (key, value) in diff.updated.into_iter() {
1144 match value.value {
1145 Some(ValueOrHandler::Handler(h)) => {
1146 let old_id = h.id();
1147 let new_h = x.insert_container(
1148 &key,
1149 Handler::new_unattached(old_id.container_type()),
1150 )?;
1151 let new_id = new_h.id();
1152 on_container_remap(old_id, new_id);
1153 }
1154 Some(ValueOrHandler::Value(LoroValue::Container(old_id))) => {
1155 let new_h = x.insert_container(
1156 &key,
1157 Handler::new_unattached(old_id.container_type()),
1158 )?;
1159 let new_id = new_h.id();
1160 on_container_remap(old_id, new_id);
1161 }
1162 Some(ValueOrHandler::Value(v)) => {
1163 x.insert_without_skipping(&key, v)?;
1164 }
1165 None => {
1166 x.delete(&key)?;
1167 }
1168 }
1169 }
1170 }
1171 Self::Text(x) => {
1172 let delta = diff.into_text().unwrap();
1173 x.apply_delta(&TextDelta::from_text_diff(delta.iter()))?;
1174 }
1175 Self::List(x) => {
1176 let delta = diff.into_list().unwrap();
1177 x.apply_delta(delta, on_container_remap)?;
1178 }
1179 Self::MovableList(x) => {
1180 let delta = diff.into_list().unwrap();
1181 x.apply_delta(delta, container_remap)?;
1182 }
1183 Self::Tree(x) => {
1184 fn remap_tree_id(
1185 id: &mut TreeID,
1186 container_remap: &FxHashMap<ContainerID, ContainerID>,
1187 ) {
1188 let mut remapped = false;
1189 let mut map_id = id.associated_meta_container();
1190 while let Some(rid) = container_remap.get(&map_id) {
1191 remapped = true;
1192 map_id = rid.clone();
1193 }
1194 if remapped {
1195 *id = TreeID::new(
1196 *map_id.as_normal().unwrap().0,
1197 *map_id.as_normal().unwrap().1,
1198 )
1199 }
1200 }
1201 for diff in diff.into_tree().unwrap().diff {
1202 let mut target = diff.target;
1203 match diff.action {
1204 TreeExternalDiff::Create {
1205 mut parent,
1206 index: _,
1207 position,
1208 } => {
1209 if let TreeParentId::Node(p) = &mut parent {
1210 remap_tree_id(p, container_remap)
1211 }
1212 remap_tree_id(&mut target, container_remap);
1213 if !x.is_node_unexist(&target) && !x.is_node_deleted(&target)? {
1214 x.move_at_with_target_for_apply_diff(parent, position, target)?;
1227 } else {
1228 let new_target = x.__internal__next_tree_id();
1229 if x.create_at_with_target_for_apply_diff(
1230 parent, position, new_target,
1231 )? {
1232 container_remap.insert(
1233 target.associated_meta_container(),
1234 new_target.associated_meta_container(),
1235 );
1236 }
1237 }
1238 }
1239 TreeExternalDiff::Move {
1240 mut parent,
1241 index: _,
1242 position,
1243 old_parent: _,
1244 old_index: _,
1245 } => {
1246 if let TreeParentId::Node(p) = &mut parent {
1247 remap_tree_id(p, container_remap)
1248 }
1249 remap_tree_id(&mut target, container_remap);
1250 if x.is_node_unexist(&target) || x.is_node_deleted(&target).unwrap() {
1252 let new_target = x.__internal__next_tree_id();
1254 if x.create_at_with_target_for_apply_diff(
1255 parent, position, new_target,
1256 )? {
1257 container_remap.insert(
1258 target.associated_meta_container(),
1259 new_target.associated_meta_container(),
1260 );
1261 }
1262 } else {
1263 x.move_at_with_target_for_apply_diff(parent, position, target)?;
1264 }
1265 }
1266 TreeExternalDiff::Delete { .. } => {
1267 remap_tree_id(&mut target, container_remap);
1268 if !x.is_node_deleted(&target).unwrap() {
1269 x.delete(target)?;
1270 }
1271 }
1272 }
1273 }
1274 }
1275 #[cfg(feature = "counter")]
1276 Self::Counter(x) => {
1277 let delta = diff.into_counter().unwrap();
1278 x.increment(delta)?;
1279 }
1280 Self::Unknown(_) => {
1281 }
1283 }
1284 Ok(())
1285 }
1286}
1287
1288#[derive(Clone, EnumAsInner, Debug)]
1289pub enum ValueOrHandler {
1290 Value(LoroValue),
1291 Handler(Handler),
1292}
1293
1294impl ValueOrHandler {
1295 pub(crate) fn from_value(value: LoroValue, doc: &Arc<LoroDocInner>) -> Self {
1296 if let LoroValue::Container(c) = value {
1297 ValueOrHandler::Handler(Handler::new_attached(c, LoroDoc::from_inner(doc.clone())))
1298 } else {
1299 ValueOrHandler::Value(value)
1300 }
1301 }
1302
1303 pub(crate) fn to_value(&self) -> LoroValue {
1304 match self {
1305 Self::Value(v) => v.clone(),
1306 Self::Handler(h) => LoroValue::Container(h.id().clone()),
1307 }
1308 }
1309
1310 pub(crate) fn to_deep_value(&self) -> LoroValue {
1311 match self {
1312 Self::Value(v) => v.clone(),
1313 Self::Handler(h) => h.get_deep_value(),
1314 }
1315 }
1316}
1317
1318impl From<LoroValue> for ValueOrHandler {
1319 fn from(value: LoroValue) -> Self {
1320 ValueOrHandler::Value(value)
1321 }
1322}
1323
1324impl TextHandler {
1325 pub fn new_detached() -> Self {
1330 Self {
1331 inner: MaybeDetached::new_detached(RichtextState::default()),
1332 }
1333 }
1334
1335 pub fn version_id(&self) -> Option<usize> {
1339 match &self.inner {
1340 MaybeDetached::Detached(_) => None,
1341 MaybeDetached::Attached(a) => {
1342 Some(a.with_state(|state| state.as_richtext_state_mut().unwrap().get_version_id()))
1343 }
1344 }
1345 }
1346
1347 pub fn get_richtext_value(&self) -> LoroValue {
1348 match &self.inner {
1349 MaybeDetached::Detached(t) => {
1350 let t = t.lock().unwrap();
1351 t.value.get_richtext_value()
1352 }
1353 MaybeDetached::Attached(a) => {
1354 a.with_state(|state| state.as_richtext_state_mut().unwrap().get_richtext_value())
1355 }
1356 }
1357 }
1358
1359 pub fn is_empty(&self) -> bool {
1360 match &self.inner {
1361 MaybeDetached::Detached(t) => t.lock().unwrap().value.is_empty(),
1362 MaybeDetached::Attached(a) => {
1363 a.with_state(|state| state.as_richtext_state_mut().unwrap().is_empty())
1364 }
1365 }
1366 }
1367
1368 pub fn len_utf8(&self) -> usize {
1369 match &self.inner {
1370 MaybeDetached::Detached(t) => {
1371 let t = t.lock().unwrap();
1372 t.value.len_utf8()
1373 }
1374 MaybeDetached::Attached(a) => {
1375 a.with_state(|state| state.as_richtext_state_mut().unwrap().len_utf8())
1376 }
1377 }
1378 }
1379
1380 pub fn len_utf16(&self) -> usize {
1381 match &self.inner {
1382 MaybeDetached::Detached(t) => {
1383 let t = t.lock().unwrap();
1384 t.value.len_utf16()
1385 }
1386 MaybeDetached::Attached(a) => {
1387 a.with_state(|state| state.as_richtext_state_mut().unwrap().len_utf16())
1388 }
1389 }
1390 }
1391
1392 pub fn len_unicode(&self) -> usize {
1393 match &self.inner {
1394 MaybeDetached::Detached(t) => {
1395 let t = t.lock().unwrap();
1396 t.value.len_unicode()
1397 }
1398 MaybeDetached::Attached(a) => {
1399 a.with_state(|state| state.as_richtext_state_mut().unwrap().len_unicode())
1400 }
1401 }
1402 }
1403
1404 pub fn len_event(&self) -> usize {
1407 if cfg!(feature = "wasm") {
1408 self.len_utf16()
1409 } else {
1410 self.len_unicode()
1411 }
1412 }
1413
1414 pub fn diagnose(&self) {
1415 match &self.inner {
1416 MaybeDetached::Detached(t) => {
1417 let t = t.lock().unwrap();
1418 t.value.diagnose();
1419 }
1420 MaybeDetached::Attached(a) => {
1421 a.with_state(|state| state.as_richtext_state_mut().unwrap().diagnose());
1422 }
1423 }
1424 }
1425
1426 pub fn iter(&self, mut callback: impl FnMut(&str) -> bool) {
1427 match &self.inner {
1428 MaybeDetached::Detached(t) => {
1429 let t = t.lock().unwrap();
1430 for span in t.value.iter() {
1431 if !callback(span.text.as_str()) {
1432 return;
1433 }
1434 }
1435 }
1436 MaybeDetached::Attached(a) => {
1437 a.with_state(|state| {
1438 state.as_richtext_state_mut().unwrap().iter(callback);
1439 });
1440 }
1441 }
1442 }
1443
1444 pub fn char_at(&self, pos: usize) -> LoroResult<char> {
1449 if pos >= self.len_event() {
1450 return Err(LoroError::OutOfBound {
1451 pos,
1452 len: self.len_event(),
1453 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1454 });
1455 }
1456 if let Ok(c) = match &self.inner {
1457 MaybeDetached::Detached(t) => {
1458 let t = t.lock().unwrap();
1459 t.value.get_char_by_event_index(pos)
1460 }
1461 MaybeDetached::Attached(a) => a.with_state(|state| {
1462 state
1463 .as_richtext_state_mut()
1464 .unwrap()
1465 .get_char_by_event_index(pos)
1466 }),
1467 } {
1468 Ok(c)
1469 } else {
1470 Err(LoroError::OutOfBound {
1471 pos,
1472 len: self.len_event(),
1473 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1474 })
1475 }
1476 }
1477
1478 pub fn slice(&self, start_index: usize, end_index: usize) -> LoroResult<String> {
1484 if end_index < start_index {
1485 return Err(LoroError::EndIndexLessThanStartIndex {
1486 start: start_index,
1487 end: end_index,
1488 });
1489 }
1490 match &self.inner {
1491 MaybeDetached::Detached(t) => {
1492 let t = t.lock().unwrap();
1493 t.value
1494 .get_text_slice_by_event_index(start_index, end_index - start_index)
1495 }
1496 MaybeDetached::Attached(a) => a.with_state(|state| {
1497 state
1498 .as_richtext_state_mut()
1499 .unwrap()
1500 .get_text_slice_by_event_index(start_index, end_index - start_index)
1501 }),
1502 }
1503 }
1504
1505 pub fn splice(&self, pos: usize, len: usize, s: &str) -> LoroResult<String> {
1512 let x = self.slice(pos, pos + len)?;
1513 self.delete(pos, len)?;
1514 self.insert(pos, s)?;
1515 Ok(x)
1516 }
1517
1518 pub fn splice_utf8(&self, pos: usize, len: usize, s: &str) -> LoroResult<()> {
1519 self.delete_utf8(pos, len)?;
1521 self.insert_utf8(pos, s)?;
1522 Ok(())
1523 }
1524
1525 pub fn insert(&self, pos: usize, s: &str) -> LoroResult<()> {
1532 match &self.inner {
1533 MaybeDetached::Detached(t) => {
1534 let mut t = t.lock().unwrap();
1535 let (index, _) = t
1536 .value
1537 .get_entity_index_for_text_insert(pos, PosType::Event)
1538 .unwrap();
1539 t.value.insert_at_entity_index(
1540 index,
1541 BytesSlice::from_bytes(s.as_bytes()),
1542 IdFull::NONE_ID,
1543 );
1544 Ok(())
1545 }
1546 MaybeDetached::Attached(a) => a.with_txn(|txn| self.insert_with_txn(txn, pos, s)),
1547 }
1548 }
1549
1550 pub fn insert_utf8(&self, pos: usize, s: &str) -> LoroResult<()> {
1551 match &self.inner {
1552 MaybeDetached::Detached(t) => {
1553 let mut t = t.lock().unwrap();
1554 let (index, _) = t
1555 .value
1556 .get_entity_index_for_text_insert(pos, PosType::Bytes)
1557 .unwrap();
1558 t.value.insert_at_entity_index(
1559 index,
1560 BytesSlice::from_bytes(s.as_bytes()),
1561 IdFull::NONE_ID,
1562 );
1563 Ok(())
1564 }
1565 MaybeDetached::Attached(a) => a.with_txn(|txn| self.insert_with_txn_utf8(txn, pos, s)),
1566 }
1567 }
1568
1569 pub fn insert_unicode(&self, pos: usize, s: &str) -> LoroResult<()> {
1570 match &self.inner {
1571 MaybeDetached::Detached(t) => {
1572 let mut t = t.lock().unwrap();
1573 let (index, _) = t
1574 .value
1575 .get_entity_index_for_text_insert(pos, PosType::Unicode)
1576 .unwrap();
1577 t.value.insert_at_entity_index(
1578 index,
1579 BytesSlice::from_bytes(s.as_bytes()),
1580 IdFull::NONE_ID,
1581 );
1582 Ok(())
1583 }
1584 MaybeDetached::Attached(a) => a.with_txn(|txn| {
1585 self.insert_with_txn_and_attr(txn, pos, s, None, PosType::Unicode)?;
1586 Ok(())
1587 }),
1588 }
1589 }
1590
1591 pub fn insert_with_txn(&self, txn: &mut Transaction, pos: usize, s: &str) -> LoroResult<()> {
1596 self.insert_with_txn_and_attr(txn, pos, s, None, PosType::Event)?;
1597 Ok(())
1598 }
1599
1600 pub fn insert_with_txn_utf8(
1601 &self,
1602 txn: &mut Transaction,
1603 pos: usize,
1604 s: &str,
1605 ) -> LoroResult<()> {
1606 self.insert_with_txn_and_attr(txn, pos, s, None, PosType::Bytes)?;
1607 Ok(())
1608 }
1609
1610 pub fn delete(&self, pos: usize, len: usize) -> LoroResult<()> {
1617 match &self.inner {
1618 MaybeDetached::Detached(t) => {
1619 let mut t = t.lock().unwrap();
1620 let ranges = t
1621 .value
1622 .get_text_entity_ranges(pos, len, PosType::Event)
1623 .unwrap();
1624 for range in ranges.iter().rev() {
1625 t.value
1626 .drain_by_entity_index(range.entity_start, range.entity_len(), None);
1627 }
1628 Ok(())
1629 }
1630 MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, pos, len)),
1631 }
1632 }
1633
1634 pub fn delete_utf8(&self, pos: usize, len: usize) -> LoroResult<()> {
1635 match &self.inner {
1636 MaybeDetached::Detached(t) => {
1637 let mut t = t.lock().unwrap();
1638 let ranges = t.value.get_text_entity_ranges(pos, len, PosType::Bytes)?;
1639 for range in ranges.iter().rev() {
1640 t.value
1641 .drain_by_entity_index(range.entity_start, range.entity_len(), None);
1642 }
1643 Ok(())
1644 }
1645 MaybeDetached::Attached(a) => {
1646 a.with_txn(|txn| self.delete_with_txn_inline(txn, pos, len, PosType::Bytes))
1647 }
1648 }
1649 }
1650
1651 pub fn delete_unicode(&self, pos: usize, len: usize) -> LoroResult<()> {
1652 match &self.inner {
1653 MaybeDetached::Detached(t) => {
1654 let mut t = t.lock().unwrap();
1655 let ranges = t.value.get_text_entity_ranges(pos, len, PosType::Unicode)?;
1656 for range in ranges.iter().rev() {
1657 t.value
1658 .drain_by_entity_index(range.entity_start, range.entity_len(), None);
1659 }
1660 Ok(())
1661 }
1662 MaybeDetached::Attached(a) => {
1663 a.with_txn(|txn| self.delete_with_txn_inline(txn, pos, len, PosType::Unicode))
1664 }
1665 }
1666 }
1667
1668 fn insert_with_txn_and_attr(
1671 &self,
1672 txn: &mut Transaction,
1673 pos: usize,
1674 s: &str,
1675 attr: Option<&FxHashMap<String, LoroValue>>,
1676 pos_type: PosType,
1677 ) -> Result<Vec<(InternalString, LoroValue)>, LoroError> {
1678 if s.is_empty() {
1679 return Ok(Vec::new());
1680 }
1681
1682 match pos_type {
1683 PosType::Event => {
1684 if pos > self.len_event() {
1685 return Err(LoroError::OutOfBound {
1686 pos,
1687 len: self.len_event(),
1688 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1689 });
1690 }
1691 }
1692 PosType::Bytes => {
1693 if pos > self.len_utf8() {
1694 return Err(LoroError::OutOfBound {
1695 pos,
1696 len: self.len_utf8(),
1697 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1698 });
1699 }
1700 }
1701 PosType::Unicode => {
1702 if pos > self.len_unicode() {
1703 return Err(LoroError::OutOfBound {
1704 pos,
1705 len: self.len_unicode(),
1706 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1707 });
1708 }
1709 }
1710 PosType::Entity => {}
1711 PosType::Utf16 => {
1712 if pos > self.len_utf16() {
1713 return Err(LoroError::OutOfBound {
1714 pos,
1715 len: self.len_utf16(),
1716 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1717 });
1718 }
1719 }
1720 }
1721
1722 let inner = self.inner.try_attached_state()?;
1723 let (entity_index, event_index, styles) = inner.with_state(|state| {
1724 let richtext_state = state.as_richtext_state_mut().unwrap();
1725 let ret = richtext_state.get_entity_index_for_text_insert(pos, pos_type);
1726 let (entity_index, cursor) = match ret {
1727 Err(_) => match pos_type {
1728 PosType::Bytes => {
1729 return (
1730 Err(LoroError::UTF8InUnicodeCodePoint { pos }),
1731 0,
1732 StyleMeta::empty(),
1733 );
1734 }
1735 PosType::Utf16 | PosType::Event => {
1736 return (
1737 Err(LoroError::UTF16InUnicodeCodePoint { pos }),
1738 0,
1739 StyleMeta::empty(),
1740 );
1741 }
1742 _ => unreachable!(),
1743 },
1744 Ok(x) => x,
1745 };
1746 let event_index = if let Some(cursor) = cursor {
1747 if pos_type == PosType::Event {
1748 debug_assert_eq!(
1749 richtext_state.get_event_index_by_cursor(cursor),
1750 pos,
1751 "pos={} cursor={:?} state={:#?}",
1752 pos,
1753 cursor,
1754 &richtext_state
1755 );
1756 pos
1757 } else {
1758 richtext_state.get_event_index_by_cursor(cursor)
1759 }
1760 } else {
1761 assert_eq!(entity_index, 0);
1762 0
1763 };
1764 let styles = richtext_state.get_styles_at_entity_index(entity_index);
1765 (Ok(entity_index), event_index, styles)
1766 });
1767
1768 let entity_index = match entity_index {
1769 Err(x) => return Err(x),
1770 _ => entity_index.unwrap(),
1771 };
1772
1773 let mut override_styles = Vec::new();
1774 if let Some(attr) = attr {
1775 let map: FxHashMap<_, _> = styles.iter().map(|x| (x.0.clone(), x.1.data)).collect();
1777 for (key, style) in map.iter() {
1778 match attr.get(key.deref()) {
1779 Some(v) if v == style => {}
1780 new_style_value => {
1781 let new_style_value = new_style_value.cloned().unwrap_or(LoroValue::Null);
1783 override_styles.push((key.clone(), new_style_value));
1784 }
1785 }
1786 }
1787
1788 for (key, style) in attr.iter() {
1789 let key = key.as_str().into();
1790 if !map.contains_key(&key) {
1791 override_styles.push((key, style.clone()));
1792 }
1793 }
1794 }
1795
1796 let unicode_len = s.chars().count();
1797 let event_len = if cfg!(feature = "wasm") {
1798 count_utf16_len(s.as_bytes())
1799 } else {
1800 unicode_len
1801 };
1802
1803 txn.apply_local_op(
1804 inner.container_idx,
1805 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
1806 slice: ListSlice::RawStr {
1807 str: Cow::Borrowed(s),
1808 unicode_len,
1809 },
1810 pos: entity_index,
1811 }),
1812 EventHint::InsertText {
1813 pos: event_index as u32,
1814 styles,
1815 unicode_len: unicode_len as u32,
1816 event_len: event_len as u32,
1817 },
1818 &inner.doc,
1819 )?;
1820
1821 Ok(override_styles)
1822 }
1823
1824 pub fn delete_with_txn(&self, txn: &mut Transaction, pos: usize, len: usize) -> LoroResult<()> {
1829 self.delete_with_txn_inline(txn, pos, len, PosType::Event)
1830 }
1831
1832 fn delete_with_txn_inline(
1833 &self,
1834 txn: &mut Transaction,
1835 pos: usize,
1836 len: usize,
1837 pos_type: PosType,
1838 ) -> LoroResult<()> {
1839 if len == 0 {
1840 return Ok(());
1841 }
1842
1843 match pos_type {
1844 PosType::Event => {
1845 if pos + len > self.len_event() {
1846 error!("pos={} len={} len_event={}", pos, len, self.len_event());
1847 return Err(LoroError::OutOfBound {
1848 pos: pos + len,
1849 len: self.len_event(),
1850 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1851 });
1852 }
1853 }
1854 PosType::Bytes => {
1855 if pos + len > self.len_utf8() {
1856 error!("pos={} len={} len_bytes={}", pos, len, self.len_utf8());
1857 return Err(LoroError::OutOfBound {
1858 pos: pos + len,
1859 len: self.len_utf8(),
1860 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1861 });
1862 }
1863 }
1864 _ => (),
1865 }
1866
1867 let inner = self.inner.try_attached_state()?;
1868 let s = tracing::span!(tracing::Level::INFO, "delete", "pos={} len={}", pos, len);
1869 let _e = s.enter();
1870 let mut event_pos = 0;
1871 let mut event_len = 0;
1872 let ranges = inner.with_state(|state| {
1873 let richtext_state = state.as_richtext_state_mut().unwrap();
1874 event_pos = richtext_state.index_to_event_index(pos, pos_type);
1875 let event_end = richtext_state.index_to_event_index(pos + len, pos_type);
1876 event_len = event_end - event_pos;
1877
1878 richtext_state.get_text_entity_ranges_in_event_index_range(event_pos, event_len)
1879 })?;
1880
1881 let pos = event_pos as isize;
1883 let len = event_len as isize;
1884 let mut event_end = pos + len;
1885 for range in ranges.iter().rev() {
1886 let event_start = event_end - range.event_len as isize;
1887 txn.apply_local_op(
1888 inner.container_idx,
1889 crate::op::RawOpContent::List(ListOp::Delete(DeleteSpanWithId::new(
1890 range.id_start,
1891 range.entity_start as isize,
1892 range.entity_len() as isize,
1893 ))),
1894 EventHint::DeleteText {
1895 span: DeleteSpan {
1896 pos: event_start,
1897 signed_len: range.event_len as isize,
1898 },
1899 unicode_len: range.entity_len(),
1900 },
1901 &inner.doc,
1902 )?;
1903 event_end = event_start;
1904 }
1905
1906 Ok(())
1907 }
1908
1909 pub fn mark(
1916 &self,
1917 start: usize,
1918 end: usize,
1919 key: impl Into<InternalString>,
1920 value: LoroValue,
1921 ) -> LoroResult<()> {
1922 match &self.inner {
1923 MaybeDetached::Detached(t) => {
1924 let mut g = t.lock().unwrap();
1925 self.mark_for_detached(&mut g.value, key, &value, start, end, false)
1926 }
1927 MaybeDetached::Attached(a) => {
1928 a.with_txn(|txn| self.mark_with_txn(txn, start, end, key, value, false))
1929 }
1930 }
1931 }
1932
1933 fn mark_for_detached(
1934 &self,
1935 state: &mut RichtextState,
1936 key: impl Into<InternalString>,
1937 value: &LoroValue,
1938 start: usize,
1939 end: usize,
1940 is_delete: bool,
1941 ) -> Result<(), LoroError> {
1942 let key: InternalString = key.into();
1943 let len = state.len_event();
1944 if start >= end {
1945 return Err(loro_common::LoroError::ArgErr(
1946 "Start must be less than end".to_string().into_boxed_str(),
1947 ));
1948 }
1949 if end > len {
1950 return Err(LoroError::OutOfBound {
1951 pos: end,
1952 len,
1953 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1954 });
1955 }
1956 let (entity_range, styles) =
1957 state.get_entity_range_and_text_styles_at_range(start..end, PosType::Event);
1958 if let Some(styles) = styles {
1959 if styles.has_key_value(&key, value) {
1960 return Ok(());
1962 }
1963 }
1964
1965 let style_op = Arc::new(StyleOp {
1966 lamport: 0,
1967 peer: 0,
1968 cnt: 0,
1969 key,
1970 value: value.clone(),
1971 info: if is_delete {
1973 TextStyleInfoFlag::BOLD.to_delete()
1974 } else {
1975 TextStyleInfoFlag::BOLD
1976 },
1977 });
1978 state.mark_with_entity_index(entity_range, style_op);
1979 Ok(())
1980 }
1981
1982 pub fn unmark(
1989 &self,
1990 start: usize,
1991 end: usize,
1992 key: impl Into<InternalString>,
1993 ) -> LoroResult<()> {
1994 match &self.inner {
1995 MaybeDetached::Detached(t) => self.mark_for_detached(
1996 &mut t.lock().unwrap().value,
1997 key,
1998 &LoroValue::Null,
1999 start,
2000 end,
2001 true,
2002 ),
2003 MaybeDetached::Attached(a) => {
2004 a.with_txn(|txn| self.mark_with_txn(txn, start, end, key, LoroValue::Null, true))
2005 }
2006 }
2007 }
2008
2009 pub fn mark_with_txn(
2014 &self,
2015 txn: &mut Transaction,
2016 start: usize,
2017 end: usize,
2018 key: impl Into<InternalString>,
2019 value: LoroValue,
2020 is_delete: bool,
2021 ) -> LoroResult<()> {
2022 if start >= end {
2023 return Err(loro_common::LoroError::ArgErr(
2024 "Start must be less than end".to_string().into_boxed_str(),
2025 ));
2026 }
2027
2028 let len = self.len_event();
2029 if end > len {
2030 return Err(LoroError::OutOfBound {
2031 pos: end,
2032 len,
2033 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2034 });
2035 }
2036
2037 let inner = self.inner.try_attached_state()?;
2038 let key: InternalString = key.into();
2039
2040 let mut doc_state = inner.doc.state.lock().unwrap();
2041 let (entity_range, skip) = doc_state.with_state_mut(inner.container_idx, |state| {
2042 let (entity_range, styles) = state
2043 .as_richtext_state_mut()
2044 .unwrap()
2045 .get_entity_range_and_styles_at_range(start..end, PosType::Event);
2046
2047 let skip = match styles {
2048 Some(styles) if styles.has_key_value(&key, &value) => {
2049 true
2051 }
2052 _ => false,
2053 };
2054 (entity_range, skip)
2055 });
2056
2057 if skip {
2058 return Ok(());
2059 }
2060
2061 let entity_start = entity_range.start;
2062 let entity_end = entity_range.end;
2063 let style_config = doc_state.config.text_style_config.try_read().unwrap();
2064 let flag = if is_delete {
2065 style_config
2066 .get_style_flag_for_unmark(&key)
2067 .ok_or_else(|| LoroError::StyleConfigMissing(key.clone()))?
2068 } else {
2069 style_config
2070 .get_style_flag(&key)
2071 .ok_or_else(|| LoroError::StyleConfigMissing(key.clone()))?
2072 };
2073
2074 drop(style_config);
2075 drop(doc_state);
2076 txn.apply_local_op(
2077 inner.container_idx,
2078 crate::op::RawOpContent::List(ListOp::StyleStart {
2079 start: entity_start as u32,
2080 end: entity_end as u32,
2081 key: key.clone(),
2082 value: value.clone(),
2083 info: flag,
2084 }),
2085 EventHint::Mark {
2086 start: start as u32,
2087 end: end as u32,
2088 style: crate::container::richtext::Style { key, data: value },
2089 },
2090 &inner.doc,
2091 )?;
2092
2093 txn.apply_local_op(
2094 inner.container_idx,
2095 crate::op::RawOpContent::List(ListOp::StyleEnd),
2096 EventHint::MarkEnd,
2097 &inner.doc,
2098 )?;
2099
2100 Ok(())
2101 }
2102
2103 pub fn check(&self) {
2104 match &self.inner {
2105 MaybeDetached::Detached(t) => {
2106 let t = t.lock().unwrap();
2107 t.value.check_consistency_between_content_and_style_ranges();
2108 }
2109 MaybeDetached::Attached(a) => a.with_state(|state| {
2110 state
2111 .as_richtext_state_mut()
2112 .unwrap()
2113 .check_consistency_between_content_and_style_ranges();
2114 }),
2115 }
2116 }
2117
2118 pub fn apply_delta(&self, delta: &[TextDelta]) -> LoroResult<()> {
2119 match &self.inner {
2120 MaybeDetached::Detached(t) => {
2121 let _t = t.lock().unwrap();
2122 Err(LoroError::NotImplemented(
2124 "`apply_delta` on a detached text container",
2125 ))
2126 }
2127 MaybeDetached::Attached(a) => a.with_txn(|txn| self.apply_delta_with_txn(txn, delta)),
2128 }
2129 }
2130
2131 pub fn apply_delta_with_txn(
2132 &self,
2133 txn: &mut Transaction,
2134 delta: &[TextDelta],
2135 ) -> LoroResult<()> {
2136 let mut index = 0;
2137 struct PendingMark {
2138 start: usize,
2139 end: usize,
2140 attributes: FxHashMap<InternalString, LoroValue>,
2141 }
2142 let mut marks: Vec<PendingMark> = Vec::new();
2143 for d in delta {
2144 match d {
2145 TextDelta::Insert { insert, attributes } => {
2146 let end = index + event_len(insert.as_str());
2147 let override_styles = self.insert_with_txn_and_attr(
2148 txn,
2149 index,
2150 insert.as_str(),
2151 Some(attributes.as_ref().unwrap_or(&Default::default())),
2152 PosType::Event,
2153 )?;
2154
2155 let mut pending_mark = PendingMark {
2156 start: index,
2157 end,
2158 attributes: FxHashMap::default(),
2159 };
2160 for (key, value) in override_styles {
2161 pending_mark.attributes.insert(key, value);
2162 }
2163 marks.push(pending_mark);
2164 index = end;
2165 }
2166 TextDelta::Delete { delete } => {
2167 self.delete_with_txn(txn, index, *delete)?;
2168 }
2169 TextDelta::Retain { attributes, retain } => {
2170 let end = index + *retain;
2171 match attributes {
2172 Some(attr) if !attr.is_empty() => {
2173 let mut pending_mark = PendingMark {
2174 start: index,
2175 end,
2176 attributes: FxHashMap::default(),
2177 };
2178 for (key, value) in attr {
2179 pending_mark
2180 .attributes
2181 .insert(key.deref().into(), value.clone());
2182 }
2183 marks.push(pending_mark);
2184 }
2185 _ => {}
2186 }
2187 index = end;
2188 }
2189 }
2190 }
2191
2192 let mut len = self.len_event();
2193 for pending_mark in marks {
2194 if pending_mark.start >= len {
2195 self.insert_with_txn(txn, len, &"\n".repeat(pending_mark.start - len + 1))?;
2196 len = pending_mark.start;
2197 }
2198
2199 for (key, value) in pending_mark.attributes {
2200 self.mark_with_txn(
2201 txn,
2202 pending_mark.start,
2203 pending_mark.end,
2204 key.deref(),
2205 value,
2206 false,
2207 )?;
2208 }
2209 }
2210
2211 Ok(())
2212 }
2213
2214 pub fn update(&self, text: &str, options: UpdateOptions) -> Result<(), UpdateTimeoutError> {
2215 let old_str = self.to_string();
2216 let new = text.chars().map(|x| x as u32).collect::<Vec<u32>>();
2217 let old = old_str.chars().map(|x| x as u32).collect::<Vec<u32>>();
2218 diff(
2219 &mut OperateProxy::new(text_update::DiffHook::new(self, &new)),
2220 options,
2221 &old,
2222 &new,
2223 )?;
2224 Ok(())
2225 }
2226
2227 pub fn update_by_line(
2228 &self,
2229 text: &str,
2230 options: UpdateOptions,
2231 ) -> Result<(), UpdateTimeoutError> {
2232 let hook = text_update::DiffHookForLine::new(self, text);
2233 let old_lines = hook.get_old_arr().to_vec();
2234 let new_lines = hook.get_new_arr().to_vec();
2235 diff(
2236 &mut OperateProxy::new(hook),
2237 options,
2238 &old_lines,
2239 &new_lines,
2240 )
2241 }
2242
2243 #[allow(clippy::inherent_to_string)]
2244 pub fn to_string(&self) -> String {
2245 match &self.inner {
2246 MaybeDetached::Detached(t) => t.lock().unwrap().value.to_string(),
2247 MaybeDetached::Attached(a) => a.get_value().into_string().unwrap().unwrap(),
2248 }
2249 }
2250
2251 pub fn get_cursor(&self, event_index: usize, side: Side) -> Option<Cursor> {
2252 self.get_cursor_internal(event_index, side, true)
2253 }
2254
2255 pub(crate) fn get_cursor_internal(
2257 &self,
2258 index: usize,
2259 side: Side,
2260 get_by_event_index: bool,
2261 ) -> Option<Cursor> {
2262 match &self.inner {
2263 MaybeDetached::Detached(_) => None,
2264 MaybeDetached::Attached(a) => {
2265 let (id, len, origin_pos) = a.with_state(|s| {
2266 let s = s.as_richtext_state_mut().unwrap();
2267 (
2268 s.get_stable_position(index, get_by_event_index),
2269 if get_by_event_index {
2270 s.len_event()
2271 } else {
2272 s.len_unicode()
2273 },
2274 if get_by_event_index {
2275 s.event_index_to_unicode_index(index)
2276 } else {
2277 index
2278 },
2279 )
2280 });
2281
2282 if len == 0 {
2283 return Some(Cursor {
2284 id: None,
2285 container: self.id(),
2286 side: if side == Side::Middle {
2287 Side::Left
2288 } else {
2289 side
2290 },
2291 origin_pos: 0,
2292 });
2293 }
2294
2295 if len <= index {
2296 return Some(Cursor {
2297 id: None,
2298 container: self.id(),
2299 side: Side::Right,
2300 origin_pos: len,
2301 });
2302 }
2303
2304 let id = id?;
2305 Some(Cursor {
2306 id: Some(id),
2307 container: self.id(),
2308 side,
2309 origin_pos,
2310 })
2311 }
2312 }
2313 }
2314
2315 pub(crate) fn convert_entity_index_to_event_index(&self, entity_index: usize) -> usize {
2316 match &self.inner {
2317 MaybeDetached::Detached(s) => s
2318 .lock()
2319 .unwrap()
2320 .value
2321 .entity_index_to_event_index(entity_index),
2322 MaybeDetached::Attached(a) => {
2323 let mut pos = 0;
2324 a.with_state(|s| {
2325 let s = s.as_richtext_state_mut().unwrap();
2326 pos = s.entity_index_to_event_index(entity_index);
2327 });
2328 pos
2329 }
2330 }
2331 }
2332
2333 fn get_delta(&self) -> Vec<TextDelta> {
2334 self.with_state(|state| {
2335 let state = state.as_richtext_state_mut().unwrap();
2336 Ok(state.get_delta())
2337 })
2338 .unwrap()
2339 }
2340
2341 pub fn is_deleted(&self) -> bool {
2342 match &self.inner {
2343 MaybeDetached::Detached(_) => false,
2344 MaybeDetached::Attached(a) => a.is_deleted(),
2345 }
2346 }
2347
2348 pub fn push_str(&self, s: &str) -> LoroResult<()> {
2349 self.insert_utf8(self.len_utf8(), s)
2350 }
2351}
2352
2353fn event_len(s: &str) -> usize {
2354 if cfg!(feature = "wasm") {
2355 count_utf16_len(s.as_bytes())
2356 } else {
2357 s.chars().count()
2358 }
2359}
2360
2361impl ListHandler {
2362 pub fn new_detached() -> Self {
2366 Self {
2367 inner: MaybeDetached::new_detached(Vec::new()),
2368 }
2369 }
2370
2371 pub fn insert(&self, pos: usize, v: impl Into<LoroValue>) -> LoroResult<()> {
2372 match &self.inner {
2373 MaybeDetached::Detached(l) => {
2374 let mut list = l.lock().unwrap();
2375 list.value.insert(pos, ValueOrHandler::Value(v.into()));
2376 Ok(())
2377 }
2378 MaybeDetached::Attached(a) => {
2379 a.with_txn(|txn| self.insert_with_txn(txn, pos, v.into()))
2380 }
2381 }
2382 }
2383
2384 pub fn insert_with_txn(
2385 &self,
2386 txn: &mut Transaction,
2387 pos: usize,
2388 v: LoroValue,
2389 ) -> LoroResult<()> {
2390 if pos > self.len() {
2391 return Err(LoroError::OutOfBound {
2392 pos,
2393 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2394 len: self.len(),
2395 });
2396 }
2397
2398 let inner = self.inner.try_attached_state()?;
2399 if let Some(_container) = v.as_container() {
2400 return Err(LoroError::ArgErr(
2401 INSERT_CONTAINER_VALUE_ARG_ERROR
2402 .to_string()
2403 .into_boxed_str(),
2404 ));
2405 }
2406
2407 txn.apply_local_op(
2408 inner.container_idx,
2409 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
2410 slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
2411 pos,
2412 }),
2413 EventHint::InsertList { len: 1, pos },
2414 &inner.doc,
2415 )
2416 }
2417
2418 pub fn push(&self, v: impl Into<LoroValue>) -> LoroResult<()> {
2419 match &self.inner {
2420 MaybeDetached::Detached(l) => {
2421 let mut list = l.lock().unwrap();
2422 list.value.push(ValueOrHandler::Value(v.into()));
2423 Ok(())
2424 }
2425 MaybeDetached::Attached(a) => a.with_txn(|txn| self.push_with_txn(txn, v.into())),
2426 }
2427 }
2428
2429 pub fn push_with_txn(&self, txn: &mut Transaction, v: LoroValue) -> LoroResult<()> {
2430 let pos = self.len();
2431 self.insert_with_txn(txn, pos, v)
2432 }
2433
2434 pub fn pop(&self) -> LoroResult<Option<LoroValue>> {
2435 match &self.inner {
2436 MaybeDetached::Detached(l) => {
2437 let mut list = l.lock().unwrap();
2438 Ok(list.value.pop().map(|v| v.to_value()))
2439 }
2440 MaybeDetached::Attached(a) => a.with_txn(|txn| self.pop_with_txn(txn)),
2441 }
2442 }
2443
2444 pub fn pop_with_txn(&self, txn: &mut Transaction) -> LoroResult<Option<LoroValue>> {
2445 let len = self.len();
2446 if len == 0 {
2447 return Ok(None);
2448 }
2449
2450 let v = self.get(len - 1);
2451 self.delete_with_txn(txn, len - 1, 1)?;
2452 Ok(v)
2453 }
2454
2455 pub fn insert_container<H: HandlerTrait>(&self, pos: usize, child: H) -> LoroResult<H> {
2456 match &self.inner {
2457 MaybeDetached::Detached(l) => {
2458 let mut list = l.lock().unwrap();
2459 list.value
2460 .insert(pos, ValueOrHandler::Handler(child.to_handler()));
2461 Ok(child)
2462 }
2463 MaybeDetached::Attached(a) => {
2464 a.with_txn(|txn| self.insert_container_with_txn(txn, pos, child))
2465 }
2466 }
2467 }
2468
2469 pub fn push_container<H: HandlerTrait>(&self, child: H) -> LoroResult<H> {
2470 self.insert_container(self.len(), child)
2471 }
2472
2473 pub fn insert_container_with_txn<H: HandlerTrait>(
2474 &self,
2475 txn: &mut Transaction,
2476 pos: usize,
2477 child: H,
2478 ) -> LoroResult<H> {
2479 if pos > self.len() {
2480 return Err(LoroError::OutOfBound {
2481 pos,
2482 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2483 len: self.len(),
2484 });
2485 }
2486
2487 let inner = self.inner.try_attached_state()?;
2488 let id = txn.next_id();
2489 let container_id = ContainerID::new_normal(id, child.kind());
2490 let v = LoroValue::Container(container_id.clone());
2491 txn.apply_local_op(
2492 inner.container_idx,
2493 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
2494 slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
2495 pos,
2496 }),
2497 EventHint::InsertList { len: 1, pos },
2498 &inner.doc,
2499 )?;
2500 let ans = child.attach(txn, inner, container_id)?;
2501 Ok(ans)
2502 }
2503
2504 pub fn delete(&self, pos: usize, len: usize) -> LoroResult<()> {
2505 match &self.inner {
2506 MaybeDetached::Detached(l) => {
2507 let mut list = l.lock().unwrap();
2508 list.value.drain(pos..pos + len);
2509 Ok(())
2510 }
2511 MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, pos, len)),
2512 }
2513 }
2514
2515 pub fn delete_with_txn(&self, txn: &mut Transaction, pos: usize, len: usize) -> LoroResult<()> {
2516 if len == 0 {
2517 return Ok(());
2518 }
2519
2520 if pos + len > self.len() {
2521 return Err(LoroError::OutOfBound {
2522 pos: pos + len,
2523 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2524 len: self.len(),
2525 });
2526 }
2527
2528 let inner = self.inner.try_attached_state()?;
2529 let ids: Vec<_> = inner.with_state(|state| {
2530 let list = state.as_list_state().unwrap();
2531 (pos..pos + len)
2532 .map(|i| list.get_id_at(i).unwrap())
2533 .collect()
2534 });
2535
2536 for id in ids.into_iter() {
2537 txn.apply_local_op(
2538 inner.container_idx,
2539 crate::op::RawOpContent::List(ListOp::Delete(DeleteSpanWithId::new(
2540 id.id(),
2541 pos as isize,
2542 1,
2543 ))),
2544 EventHint::DeleteList(DeleteSpan::new(pos as isize, 1)),
2545 &inner.doc,
2546 )?;
2547 }
2548
2549 Ok(())
2550 }
2551
2552 pub fn get_child_handler(&self, index: usize) -> LoroResult<Handler> {
2553 match &self.inner {
2554 MaybeDetached::Detached(l) => {
2555 let list = l.lock().unwrap();
2556 let value = list.value.get(index).ok_or(LoroError::OutOfBound {
2557 pos: index,
2558 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2559 len: list.value.len(),
2560 })?;
2561 match value {
2562 ValueOrHandler::Handler(h) => Ok(h.clone()),
2563 _ => Err(LoroError::ArgErr(
2564 format!(
2565 "Expected container at index {}, but found {:?}",
2566 index, value
2567 )
2568 .into_boxed_str(),
2569 )),
2570 }
2571 }
2572 MaybeDetached::Attached(a) => {
2573 let Some(value) = a.with_state(|state| {
2574 state.as_list_state().as_ref().unwrap().get(index).cloned()
2575 }) else {
2576 return Err(LoroError::OutOfBound {
2577 pos: index,
2578 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2579 len: a.with_state(|state| state.as_list_state().unwrap().len()),
2580 });
2581 };
2582 match value {
2583 LoroValue::Container(id) => Ok(create_handler(a, id)),
2584 _ => Err(LoroError::ArgErr(
2585 format!(
2586 "Expected container at index {}, but found {:?}",
2587 index, value
2588 )
2589 .into_boxed_str(),
2590 )),
2591 }
2592 }
2593 }
2594 }
2595
2596 pub fn len(&self) -> usize {
2597 match &self.inner {
2598 MaybeDetached::Detached(l) => l.lock().unwrap().value.len(),
2599 MaybeDetached::Attached(a) => {
2600 a.with_state(|state| state.as_list_state().unwrap().len())
2601 }
2602 }
2603 }
2604
2605 pub fn is_empty(&self) -> bool {
2606 self.len() == 0
2607 }
2608
2609 pub fn get_deep_value_with_id(&self) -> LoroResult<LoroValue> {
2610 let inner = self.inner.try_attached_state()?;
2611 Ok(inner.with_doc_state(|state| {
2612 state.get_container_deep_value_with_id(inner.container_idx, None)
2613 }))
2614 }
2615
2616 pub fn get(&self, index: usize) -> Option<LoroValue> {
2617 match &self.inner {
2618 MaybeDetached::Detached(l) => l.lock().unwrap().value.get(index).map(|x| x.to_value()),
2619 MaybeDetached::Attached(a) => a.with_state(|state| {
2620 let a = state.as_list_state().unwrap();
2621 a.get(index).cloned()
2622 }),
2623 }
2624 }
2625
2626 pub fn get_(&self, index: usize) -> Option<ValueOrHandler> {
2628 match &self.inner {
2629 MaybeDetached::Detached(l) => {
2630 let l = l.lock().unwrap();
2631 l.value.get(index).cloned()
2632 }
2633 MaybeDetached::Attached(inner) => {
2634 let value =
2635 inner.with_state(|state| state.as_list_state().unwrap().get(index).cloned());
2636 match value {
2637 Some(LoroValue::Container(container_id)) => Some(ValueOrHandler::Handler(
2638 create_handler(inner, container_id.clone()),
2639 )),
2640 Some(value) => Some(ValueOrHandler::Value(value.clone())),
2641 None => None,
2642 }
2643 }
2644 }
2645 }
2646
2647 pub fn for_each<I>(&self, mut f: I)
2648 where
2649 I: FnMut(ValueOrHandler),
2650 {
2651 match &self.inner {
2652 MaybeDetached::Detached(l) => {
2653 let l = l.lock().unwrap();
2654 for v in l.value.iter() {
2655 f(v.clone())
2656 }
2657 }
2658 MaybeDetached::Attached(inner) => {
2659 let mut temp = vec![];
2660 inner.with_state(|state| {
2661 let a = state.as_list_state().unwrap();
2662 for v in a.iter() {
2663 match v {
2664 LoroValue::Container(c) => {
2665 temp.push(ValueOrHandler::Handler(create_handler(
2666 inner,
2667 c.clone(),
2668 )));
2669 }
2670 value => {
2671 temp.push(ValueOrHandler::Value(value.clone()));
2672 }
2673 }
2674 }
2675 });
2676 for v in temp.into_iter() {
2677 f(v);
2678 }
2679 }
2680 }
2681 }
2682
2683 pub fn get_cursor(&self, pos: usize, side: Side) -> Option<Cursor> {
2684 match &self.inner {
2685 MaybeDetached::Detached(_) => None,
2686 MaybeDetached::Attached(a) => {
2687 let (id, len) = a.with_state(|s| {
2688 let l = s.as_list_state().unwrap();
2689 (l.get_id_at(pos), l.len())
2690 });
2691
2692 if len == 0 {
2693 return Some(Cursor {
2694 id: None,
2695 container: self.id(),
2696 side: if side == Side::Middle {
2697 Side::Left
2698 } else {
2699 side
2700 },
2701 origin_pos: 0,
2702 });
2703 }
2704
2705 if len <= pos {
2706 return Some(Cursor {
2707 id: None,
2708 container: self.id(),
2709 side: Side::Right,
2710 origin_pos: len,
2711 });
2712 }
2713
2714 let id = id?;
2715 Some(Cursor {
2716 id: Some(id.id()),
2717 container: self.id(),
2718 side,
2719 origin_pos: pos,
2720 })
2721 }
2722 }
2723 }
2724
2725 fn apply_delta(
2726 &self,
2727 delta: loro_delta::DeltaRope<
2728 loro_delta::array_vec::ArrayVec<ValueOrHandler, 8>,
2729 crate::event::ListDeltaMeta,
2730 >,
2731 on_container_remap: &mut dyn FnMut(ContainerID, ContainerID),
2732 ) -> LoroResult<()> {
2733 match &self.inner {
2734 MaybeDetached::Detached(_) => unimplemented!(),
2735 MaybeDetached::Attached(_) => {
2736 let mut index = 0;
2737 for item in delta.iter() {
2738 match item {
2739 loro_delta::DeltaItem::Retain { len, .. } => {
2740 index += len;
2741 }
2742 loro_delta::DeltaItem::Replace { value, delete, .. } => {
2743 if *delete > 0 {
2744 self.delete(index, *delete)?;
2745 }
2746
2747 for v in value.iter() {
2748 match v {
2749 ValueOrHandler::Value(LoroValue::Container(old_id)) => {
2750 let new_h = self.insert_container(
2751 index,
2752 Handler::new_unattached(old_id.container_type()),
2753 )?;
2754 let new_id = new_h.id();
2755 on_container_remap(old_id.clone(), new_id);
2756 }
2757 ValueOrHandler::Handler(h) => {
2758 let old_id = h.id();
2759 let new_h = self.insert_container(
2760 index,
2761 Handler::new_unattached(old_id.container_type()),
2762 )?;
2763 let new_id = new_h.id();
2764 on_container_remap(old_id, new_id);
2765 }
2766 ValueOrHandler::Value(v) => {
2767 self.insert(index, v.clone())?;
2768 }
2769 }
2770
2771 index += 1;
2772 }
2773 }
2774 }
2775 }
2776 }
2777 }
2778
2779 Ok(())
2780 }
2781
2782 pub fn is_deleted(&self) -> bool {
2783 match &self.inner {
2784 MaybeDetached::Detached(_) => false,
2785 MaybeDetached::Attached(a) => a.is_deleted(),
2786 }
2787 }
2788
2789 pub fn clear(&self) -> LoroResult<()> {
2790 match &self.inner {
2791 MaybeDetached::Detached(l) => {
2792 let mut l = l.lock().unwrap();
2793 l.value.clear();
2794 Ok(())
2795 }
2796 MaybeDetached::Attached(a) => a.with_txn(|txn| self.clear_with_txn(txn)),
2797 }
2798 }
2799
2800 pub fn clear_with_txn(&self, txn: &mut Transaction) -> LoroResult<()> {
2801 self.delete_with_txn(txn, 0, self.len())
2802 }
2803
2804 pub fn get_id_at(&self, pos: usize) -> Option<ID> {
2805 match &self.inner {
2806 MaybeDetached::Detached(_) => None,
2807 MaybeDetached::Attached(a) => a.with_state(|state| {
2808 state
2809 .as_list_state()
2810 .unwrap()
2811 .get_id_at(pos)
2812 .map(|x| x.id())
2813 }),
2814 }
2815 }
2816}
2817
2818impl MovableListHandler {
2819 pub fn insert(&self, pos: usize, v: impl Into<LoroValue>) -> LoroResult<()> {
2820 match &self.inner {
2821 MaybeDetached::Detached(d) => {
2822 let mut d = d.lock().unwrap();
2823 if pos > d.value.len() {
2824 return Err(LoroError::OutOfBound {
2825 pos,
2826 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2827 len: d.value.len(),
2828 });
2829 }
2830 d.value.insert(pos, ValueOrHandler::Value(v.into()));
2831 Ok(())
2832 }
2833 MaybeDetached::Attached(a) => {
2834 a.with_txn(|txn| self.insert_with_txn(txn, pos, v.into()))
2835 }
2836 }
2837 }
2838
2839 #[instrument(skip_all)]
2840 pub fn insert_with_txn(
2841 &self,
2842 txn: &mut Transaction,
2843 pos: usize,
2844 v: LoroValue,
2845 ) -> LoroResult<()> {
2846 if pos > self.len() {
2847 return Err(LoroError::OutOfBound {
2848 pos,
2849 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2850 len: self.len(),
2851 });
2852 }
2853
2854 if v.is_container() {
2855 return Err(LoroError::ArgErr(
2856 INSERT_CONTAINER_VALUE_ARG_ERROR
2857 .to_string()
2858 .into_boxed_str(),
2859 ));
2860 }
2861
2862 let op_index = self.with_state(|state| {
2863 let list = state.as_movable_list_state().unwrap();
2864 Ok(list
2865 .convert_index(pos, IndexType::ForUser, IndexType::ForOp)
2866 .unwrap())
2867 })?;
2868
2869 let inner = self.inner.try_attached_state()?;
2870 txn.apply_local_op(
2871 inner.container_idx,
2872 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
2873 slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
2874 pos: op_index,
2875 }),
2876 EventHint::InsertList { len: 1, pos },
2877 &inner.doc,
2878 )
2879 }
2880
2881 #[inline]
2882 pub fn mov(&self, from: usize, to: usize) -> LoroResult<()> {
2883 match &self.inner {
2884 MaybeDetached::Detached(d) => {
2885 let mut d = d.lock().unwrap();
2886 if from >= d.value.len() {
2887 return Err(LoroError::OutOfBound {
2888 pos: from,
2889 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2890 len: d.value.len(),
2891 });
2892 }
2893 if to >= d.value.len() {
2894 return Err(LoroError::OutOfBound {
2895 pos: to,
2896 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2897 len: d.value.len(),
2898 });
2899 }
2900 let v = d.value.remove(from);
2901 d.value.insert(to, v);
2902 Ok(())
2903 }
2904 MaybeDetached::Attached(a) => a.with_txn(|txn| self.move_with_txn(txn, from, to)),
2905 }
2906 }
2907
2908 #[instrument(skip_all)]
2910 pub fn move_with_txn(&self, txn: &mut Transaction, from: usize, to: usize) -> LoroResult<()> {
2911 if from == to {
2912 return Ok(());
2913 }
2914
2915 if from >= self.len() {
2916 return Err(LoroError::OutOfBound {
2917 pos: from,
2918 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2919 len: self.len(),
2920 });
2921 }
2922
2923 if to >= self.len() {
2924 return Err(LoroError::OutOfBound {
2925 pos: to,
2926 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2927 len: self.len(),
2928 });
2929 }
2930
2931 let (op_from, op_to, elem_id, value) = self.with_state(|state| {
2932 let list = state.as_movable_list_state().unwrap();
2933 let (elem_id, elem) = list
2934 .get_elem_at_given_pos(from, IndexType::ForUser)
2935 .unwrap();
2936 Ok((
2937 list.convert_index(from, IndexType::ForUser, IndexType::ForOp)
2938 .unwrap(),
2939 list.convert_index(to, IndexType::ForUser, IndexType::ForOp)
2940 .unwrap(),
2941 elem_id,
2942 elem.value().clone(),
2943 ))
2944 })?;
2945
2946 let inner = self.inner.try_attached_state()?;
2947 txn.apply_local_op(
2948 inner.container_idx,
2949 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Move {
2950 from: op_from as u32,
2951 to: op_to as u32,
2952 elem_id: elem_id.to_id(),
2953 }),
2954 EventHint::Move {
2955 value,
2956 from: from as u32,
2957 to: to as u32,
2958 },
2959 &inner.doc,
2960 )
2961 }
2962
2963 pub fn push(&self, v: LoroValue) -> LoroResult<()> {
2964 match &self.inner {
2965 MaybeDetached::Detached(d) => {
2966 let mut d = d.lock().unwrap();
2967 d.value.push(v.into());
2968 Ok(())
2969 }
2970 MaybeDetached::Attached(a) => a.with_txn(|txn| self.push_with_txn(txn, v)),
2971 }
2972 }
2973
2974 pub fn push_with_txn(&self, txn: &mut Transaction, v: LoroValue) -> LoroResult<()> {
2975 let pos = self.len();
2976 self.insert_with_txn(txn, pos, v)
2977 }
2978
2979 pub fn pop_(&self) -> LoroResult<Option<ValueOrHandler>> {
2980 match &self.inner {
2981 MaybeDetached::Detached(d) => {
2982 let mut d = d.lock().unwrap();
2983 Ok(d.value.pop())
2984 }
2985 MaybeDetached::Attached(a) => {
2986 let last = self.len() - 1;
2987 let ans = self.get_(last);
2988 a.with_txn(|txn| self.pop_with_txn(txn))?;
2989 Ok(ans)
2990 }
2991 }
2992 }
2993
2994 pub fn pop(&self) -> LoroResult<Option<LoroValue>> {
2995 match &self.inner {
2996 MaybeDetached::Detached(a) => {
2997 let mut a = a.lock().unwrap();
2998 Ok(a.value.pop().map(|x| x.to_value()))
2999 }
3000 MaybeDetached::Attached(a) => a.with_txn(|txn| self.pop_with_txn(txn)),
3001 }
3002 }
3003
3004 pub fn pop_with_txn(&self, txn: &mut Transaction) -> LoroResult<Option<LoroValue>> {
3005 let len = self.len();
3006 if len == 0 {
3007 return Ok(None);
3008 }
3009
3010 let v = self.get(len - 1);
3011 self.delete_with_txn(txn, len - 1, 1)?;
3012 Ok(v)
3013 }
3014
3015 pub fn insert_container<H: HandlerTrait>(&self, pos: usize, child: H) -> LoroResult<H> {
3016 match &self.inner {
3017 MaybeDetached::Detached(d) => {
3018 let mut d = d.lock().unwrap();
3019 if pos > d.value.len() {
3020 return Err(LoroError::OutOfBound {
3021 pos,
3022 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3023 len: d.value.len(),
3024 });
3025 }
3026 d.value
3027 .insert(pos, ValueOrHandler::Handler(child.to_handler()));
3028 Ok(child)
3029 }
3030 MaybeDetached::Attached(a) => {
3031 a.with_txn(|txn| self.insert_container_with_txn(txn, pos, child))
3032 }
3033 }
3034 }
3035
3036 pub fn push_container<H: HandlerTrait>(&self, child: H) -> LoroResult<H> {
3037 self.insert_container(self.len(), child)
3038 }
3039
3040 pub fn insert_container_with_txn<H: HandlerTrait>(
3041 &self,
3042 txn: &mut Transaction,
3043 pos: usize,
3044 child: H,
3045 ) -> LoroResult<H> {
3046 if pos > self.len() {
3047 return Err(LoroError::OutOfBound {
3048 pos,
3049 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3050 len: self.len(),
3051 });
3052 }
3053
3054 let op_index = self.with_state(|state| {
3055 let list = state.as_movable_list_state().unwrap();
3056 Ok(list
3057 .convert_index(pos, IndexType::ForUser, IndexType::ForOp)
3058 .unwrap())
3059 })?;
3060
3061 let id = txn.next_id();
3062 let container_id = ContainerID::new_normal(id, child.kind());
3063 let v = LoroValue::Container(container_id.clone());
3064 let inner = self.inner.try_attached_state()?;
3065 txn.apply_local_op(
3066 inner.container_idx,
3067 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
3068 slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
3069 pos: op_index,
3070 }),
3071 EventHint::InsertList { len: 1, pos },
3072 &inner.doc,
3073 )?;
3074 child.attach(txn, inner, container_id)
3075 }
3076
3077 pub fn set(&self, index: usize, value: impl Into<LoroValue>) -> LoroResult<()> {
3078 match &self.inner {
3079 MaybeDetached::Detached(d) => {
3080 let mut d = d.lock().unwrap();
3081 if index >= d.value.len() {
3082 return Err(LoroError::OutOfBound {
3083 pos: index,
3084 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3085 len: d.value.len(),
3086 });
3087 }
3088 d.value[index] = ValueOrHandler::Value(value.into());
3089 Ok(())
3090 }
3091 MaybeDetached::Attached(a) => {
3092 a.with_txn(|txn| self.set_with_txn(txn, index, value.into()))
3093 }
3094 }
3095 }
3096
3097 pub fn set_with_txn(
3098 &self,
3099 txn: &mut Transaction,
3100 index: usize,
3101 value: LoroValue,
3102 ) -> LoroResult<()> {
3103 if index >= self.len() {
3104 return Err(LoroError::OutOfBound {
3105 pos: index,
3106 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3107 len: self.len(),
3108 });
3109 }
3110
3111 let inner = self.inner.try_attached_state()?;
3112 let Some(elem_id) = self.with_state(|state| {
3113 let list = state.as_movable_list_state().unwrap();
3114 Ok(list.get_elem_id_at(index, IndexType::ForUser))
3115 })?
3116 else {
3117 unreachable!()
3118 };
3119
3120 let op = crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Set {
3121 elem_id: elem_id.to_id(),
3122 value: value.clone(),
3123 });
3124
3125 let hint = EventHint::SetList { index, value };
3126 txn.apply_local_op(inner.container_idx, op, hint, &inner.doc)
3127 }
3128
3129 pub fn set_container<H: HandlerTrait>(&self, pos: usize, child: H) -> LoroResult<H> {
3130 match &self.inner {
3131 MaybeDetached::Detached(d) => {
3132 let mut d = d.lock().unwrap();
3133 d.value[pos] = ValueOrHandler::Handler(child.to_handler());
3134 Ok(child)
3135 }
3136 MaybeDetached::Attached(a) => {
3137 a.with_txn(|txn| self.set_container_with_txn(txn, pos, child))
3138 }
3139 }
3140 }
3141
3142 pub fn set_container_with_txn<H: HandlerTrait>(
3143 &self,
3144 txn: &mut Transaction,
3145 pos: usize,
3146 child: H,
3147 ) -> Result<H, LoroError> {
3148 let id = txn.next_id();
3149 let container_id = ContainerID::new_normal(id, child.kind());
3150 let v = LoroValue::Container(container_id.clone());
3151 let Some(elem_id) = self.with_state(|state| {
3152 let list = state.as_movable_list_state().unwrap();
3153 Ok(list.get_elem_id_at(pos, IndexType::ForUser))
3154 })?
3155 else {
3156 unreachable!()
3157 };
3158 let inner = self.inner.try_attached_state()?;
3159 txn.apply_local_op(
3160 inner.container_idx,
3161 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Set {
3162 elem_id: elem_id.to_id(),
3163 value: v.clone(),
3164 }),
3165 EventHint::SetList {
3166 index: pos,
3167 value: v,
3168 },
3169 &inner.doc,
3170 )?;
3171
3172 child.attach(txn, inner, container_id)
3173 }
3174
3175 pub fn delete(&self, pos: usize, len: usize) -> LoroResult<()> {
3176 match &self.inner {
3177 MaybeDetached::Detached(d) => {
3178 let mut d = d.lock().unwrap();
3179 d.value.drain(pos..pos + len);
3180 Ok(())
3181 }
3182 MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, pos, len)),
3183 }
3184 }
3185
3186 #[instrument(skip_all)]
3187 pub fn delete_with_txn(&self, txn: &mut Transaction, pos: usize, len: usize) -> LoroResult<()> {
3188 if len == 0 {
3189 return Ok(());
3190 }
3191
3192 if pos + len > self.len() {
3193 return Err(LoroError::OutOfBound {
3194 pos: pos + len,
3195 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3196 len: self.len(),
3197 });
3198 }
3199
3200 let (ids, new_poses) = self.with_state(|state| {
3201 let list = state.as_movable_list_state().unwrap();
3202 let ids: Vec<_> = (pos..pos + len)
3203 .map(|i| list.get_list_id_at(i, IndexType::ForUser).unwrap())
3204 .collect();
3205 let poses: Vec<_> = (pos..pos + len)
3206 .map(|user_index| {
3208 let op_index = list
3209 .convert_index(user_index, IndexType::ForUser, IndexType::ForOp)
3210 .unwrap();
3211 assert!(op_index >= user_index);
3212 op_index - (user_index - pos)
3213 })
3214 .collect();
3215 Ok((ids, poses))
3216 })?;
3217
3218 info!(?pos, ?len, ?ids, ?new_poses, "delete_with_txn");
3219 let user_pos = pos;
3220 let inner = self.inner.try_attached_state()?;
3221 for (id, op_pos) in ids.into_iter().zip(new_poses.into_iter()) {
3222 txn.apply_local_op(
3223 inner.container_idx,
3224 crate::op::RawOpContent::List(ListOp::Delete(DeleteSpanWithId::new(
3225 id,
3226 op_pos as isize,
3227 1,
3228 ))),
3229 EventHint::DeleteList(DeleteSpan::new(user_pos as isize, 1)),
3230 &inner.doc,
3231 )?;
3232 }
3233
3234 Ok(())
3235 }
3236
3237 pub fn get_child_handler(&self, index: usize) -> LoroResult<Handler> {
3238 match &self.inner {
3239 MaybeDetached::Detached(l) => {
3240 let list = l.lock().unwrap();
3241 let value = list.value.get(index).ok_or(LoroError::OutOfBound {
3242 pos: index,
3243 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3244 len: list.value.len(),
3245 })?;
3246 match value {
3247 ValueOrHandler::Handler(h) => Ok(h.clone()),
3248 _ => Err(LoroError::ArgErr(
3249 format!(
3250 "Expected container at index {}, but found {:?}",
3251 index, value
3252 )
3253 .into_boxed_str(),
3254 )),
3255 }
3256 }
3257 MaybeDetached::Attached(a) => {
3258 let Some(value) = a.with_state(|state| {
3259 state
3260 .as_movable_list_state()
3261 .as_ref()
3262 .unwrap()
3263 .get(index, IndexType::ForUser)
3264 .cloned()
3265 }) else {
3266 return Err(LoroError::OutOfBound {
3267 pos: index,
3268 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3269 len: a.with_state(|state| state.as_list_state().unwrap().len()),
3270 });
3271 };
3272 match value {
3273 LoroValue::Container(id) => Ok(create_handler(a, id)),
3274 _ => Err(LoroError::ArgErr(
3275 format!(
3276 "Expected container at index {}, but found {:?}",
3277 index, value
3278 )
3279 .into_boxed_str(),
3280 )),
3281 }
3282 }
3283 }
3284 }
3285
3286 pub fn len(&self) -> usize {
3287 match &self.inner {
3288 MaybeDetached::Detached(d) => {
3289 let d = d.lock().unwrap();
3290 d.value.len()
3291 }
3292 MaybeDetached::Attached(a) => {
3293 a.with_state(|state| state.as_movable_list_state().unwrap().len())
3294 }
3295 }
3296 }
3297
3298 pub fn is_empty(&self) -> bool {
3299 self.len() == 0
3300 }
3301
3302 pub fn get_deep_value_with_id(&self) -> LoroValue {
3303 let inner = self.inner.try_attached_state().unwrap();
3304 inner
3305 .doc
3306 .state
3307 .lock()
3308 .unwrap()
3309 .get_container_deep_value_with_id(inner.container_idx, None)
3310 }
3311
3312 pub fn get(&self, index: usize) -> Option<LoroValue> {
3313 match &self.inner {
3314 MaybeDetached::Detached(d) => {
3315 let d = d.lock().unwrap();
3316 d.value.get(index).map(|v| v.to_value())
3317 }
3318 MaybeDetached::Attached(a) => a.with_state(|state| {
3319 let a = state.as_movable_list_state().unwrap();
3320 a.get(index, IndexType::ForUser).cloned()
3321 }),
3322 }
3323 }
3324
3325 pub fn get_(&self, index: usize) -> Option<ValueOrHandler> {
3327 match &self.inner {
3328 MaybeDetached::Detached(d) => {
3329 let d = d.lock().unwrap();
3330 d.value.get(index).cloned()
3331 }
3332 MaybeDetached::Attached(m) => m.with_state(|state| {
3333 let a = state.as_movable_list_state().unwrap();
3334 match a.get(index, IndexType::ForUser) {
3335 Some(v) => {
3336 if let LoroValue::Container(c) = v {
3337 Some(ValueOrHandler::Handler(create_handler(m, c.clone())))
3338 } else {
3339 Some(ValueOrHandler::Value(v.clone()))
3340 }
3341 }
3342 None => None,
3343 }
3344 }),
3345 }
3346 }
3347
3348 pub fn for_each<I>(&self, mut f: I)
3349 where
3350 I: FnMut(ValueOrHandler),
3351 {
3352 match &self.inner {
3353 MaybeDetached::Detached(d) => {
3354 let d = d.lock().unwrap();
3355 for v in d.value.iter() {
3356 f(v.clone());
3357 }
3358 }
3359 MaybeDetached::Attached(m) => {
3360 let mut temp = vec![];
3361 m.with_state(|state| {
3362 let a = state.as_movable_list_state().unwrap();
3363 for v in a.iter() {
3364 match v {
3365 LoroValue::Container(c) => {
3366 temp.push(ValueOrHandler::Handler(create_handler(m, c.clone())));
3367 }
3368 value => {
3369 temp.push(ValueOrHandler::Value(value.clone()));
3370 }
3371 }
3372 }
3373 });
3374
3375 for v in temp.into_iter() {
3376 f(v);
3377 }
3378 }
3379 }
3380 }
3381
3382 pub fn log_internal_state(&self) -> String {
3383 match &self.inner {
3384 MaybeDetached::Detached(d) => {
3385 let d = d.lock().unwrap();
3386 format!("{:#?}", &d.value)
3387 }
3388 MaybeDetached::Attached(a) => a.with_state(|state| {
3389 let a = state.as_movable_list_state().unwrap();
3390 format!("{:#?}", a)
3391 }),
3392 }
3393 }
3394
3395 pub fn new_detached() -> MovableListHandler {
3396 MovableListHandler {
3397 inner: MaybeDetached::new_detached(Default::default()),
3398 }
3399 }
3400
3401 pub fn get_cursor(&self, pos: usize, side: Side) -> Option<Cursor> {
3402 match &self.inner {
3403 MaybeDetached::Detached(_) => None,
3404 MaybeDetached::Attached(inner) => {
3405 let (id, len) = inner.with_state(|s| {
3406 let l = s.as_movable_list_state().unwrap();
3407 (l.get_list_item_id_at(pos), l.len())
3408 });
3409
3410 if len == 0 {
3411 return Some(Cursor {
3412 id: None,
3413 container: self.id(),
3414 side: if side == Side::Middle {
3415 Side::Left
3416 } else {
3417 side
3418 },
3419 origin_pos: 0,
3420 });
3421 }
3422
3423 if len <= pos {
3424 return Some(Cursor {
3425 id: None,
3426 container: self.id(),
3427 side: Side::Right,
3428 origin_pos: len,
3429 });
3430 }
3431
3432 let id = id?;
3433 Some(Cursor {
3434 id: Some(id.id()),
3435 container: self.id(),
3436 side,
3437 origin_pos: pos,
3438 })
3439 }
3440 }
3441 }
3442
3443 pub(crate) fn op_pos_to_user_pos(&self, new_pos: usize) -> usize {
3444 match &self.inner {
3445 MaybeDetached::Detached(_) => new_pos,
3446 MaybeDetached::Attached(inner) => {
3447 let mut pos = new_pos;
3448 inner.with_state(|s| {
3449 let l = s.as_movable_list_state().unwrap();
3450 pos = l
3451 .convert_index(new_pos, IndexType::ForOp, IndexType::ForUser)
3452 .unwrap_or(l.len());
3453 });
3454 pos
3455 }
3456 }
3457 }
3458
3459 pub fn is_deleted(&self) -> bool {
3460 match &self.inner {
3461 MaybeDetached::Detached(_) => false,
3462 MaybeDetached::Attached(a) => a.is_deleted(),
3463 }
3464 }
3465
3466 pub fn clear(&self) -> LoroResult<()> {
3467 match &self.inner {
3468 MaybeDetached::Detached(d) => {
3469 let mut d = d.lock().unwrap();
3470 d.value.clear();
3471 Ok(())
3472 }
3473 MaybeDetached::Attached(a) => a.with_txn(|txn| self.clear_with_txn(txn)),
3474 }
3475 }
3476
3477 pub fn clear_with_txn(&self, txn: &mut Transaction) -> LoroResult<()> {
3478 self.delete_with_txn(txn, 0, self.len())
3479 }
3480
3481 pub fn get_creator_at(&self, pos: usize) -> Option<PeerID> {
3482 match &self.inner {
3483 MaybeDetached::Detached(_) => None,
3484 MaybeDetached::Attached(a) => {
3485 a.with_state(|state| state.as_movable_list_state().unwrap().get_creator_at(pos))
3486 }
3487 }
3488 }
3489
3490 pub fn get_last_mover_at(&self, pos: usize) -> Option<PeerID> {
3491 match &self.inner {
3492 MaybeDetached::Detached(_) => None,
3493 MaybeDetached::Attached(a) => a.with_state(|state| {
3494 state
3495 .as_movable_list_state()
3496 .unwrap()
3497 .get_last_mover_at(pos)
3498 }),
3499 }
3500 }
3501
3502 pub fn get_last_editor_at(&self, pos: usize) -> Option<PeerID> {
3503 match &self.inner {
3504 MaybeDetached::Detached(_) => None,
3505 MaybeDetached::Attached(a) => a.with_state(|state| {
3506 state
3507 .as_movable_list_state()
3508 .unwrap()
3509 .get_last_editor_at(pos)
3510 }),
3511 }
3512 }
3513}
3514
3515impl MapHandler {
3516 pub fn new_detached() -> Self {
3520 Self {
3521 inner: MaybeDetached::new_detached(Default::default()),
3522 }
3523 }
3524
3525 pub fn insert(&self, key: &str, value: impl Into<LoroValue>) -> LoroResult<()> {
3526 match &self.inner {
3527 MaybeDetached::Detached(m) => {
3528 let mut m = m.lock().unwrap();
3529 m.value
3530 .insert(key.into(), ValueOrHandler::Value(value.into()));
3531 Ok(())
3532 }
3533 MaybeDetached::Attached(a) => {
3534 a.with_txn(|txn| self.insert_with_txn(txn, key, value.into()))
3535 }
3536 }
3537 }
3538
3539 fn insert_without_skipping(&self, key: &str, value: impl Into<LoroValue>) -> LoroResult<()> {
3541 match &self.inner {
3542 MaybeDetached::Detached(m) => {
3543 let mut m = m.lock().unwrap();
3544 m.value
3545 .insert(key.into(), ValueOrHandler::Value(value.into()));
3546 Ok(())
3547 }
3548 MaybeDetached::Attached(a) => a.with_txn(|txn| {
3549 let this = &self;
3550 let value = value.into();
3551 if let Some(_value) = value.as_container() {
3552 return Err(LoroError::ArgErr(
3553 INSERT_CONTAINER_VALUE_ARG_ERROR
3554 .to_string()
3555 .into_boxed_str(),
3556 ));
3557 }
3558
3559 let inner = this.inner.try_attached_state()?;
3560 txn.apply_local_op(
3561 inner.container_idx,
3562 crate::op::RawOpContent::Map(crate::container::map::MapSet {
3563 key: key.into(),
3564 value: Some(value.clone()),
3565 }),
3566 EventHint::Map {
3567 key: key.into(),
3568 value: Some(value.clone()),
3569 },
3570 &inner.doc,
3571 )
3572 }),
3573 }
3574 }
3575
3576 pub fn insert_with_txn(
3577 &self,
3578 txn: &mut Transaction,
3579 key: &str,
3580 value: LoroValue,
3581 ) -> LoroResult<()> {
3582 if let Some(_value) = value.as_container() {
3583 return Err(LoroError::ArgErr(
3584 INSERT_CONTAINER_VALUE_ARG_ERROR
3585 .to_string()
3586 .into_boxed_str(),
3587 ));
3588 }
3589
3590 if self.get(key).map(|x| x == value).unwrap_or(false) {
3591 return Ok(());
3593 }
3594
3595 let inner = self.inner.try_attached_state()?;
3596 txn.apply_local_op(
3597 inner.container_idx,
3598 crate::op::RawOpContent::Map(crate::container::map::MapSet {
3599 key: key.into(),
3600 value: Some(value.clone()),
3601 }),
3602 EventHint::Map {
3603 key: key.into(),
3604 value: Some(value.clone()),
3605 },
3606 &inner.doc,
3607 )
3608 }
3609
3610 pub fn insert_container<T: HandlerTrait>(&self, key: &str, handler: T) -> LoroResult<T> {
3611 match &self.inner {
3612 MaybeDetached::Detached(m) => {
3613 let mut m = m.lock().unwrap();
3614 let to_insert = handler.to_handler();
3615 m.value
3616 .insert(key.into(), ValueOrHandler::Handler(to_insert.clone()));
3617 Ok(handler)
3618 }
3619 MaybeDetached::Attached(a) => {
3620 a.with_txn(|txn| self.insert_container_with_txn(txn, key, handler))
3621 }
3622 }
3623 }
3624
3625 pub fn insert_container_with_txn<H: HandlerTrait>(
3626 &self,
3627 txn: &mut Transaction,
3628 key: &str,
3629 child: H,
3630 ) -> LoroResult<H> {
3631 let inner = self.inner.try_attached_state()?;
3632 let id = txn.next_id();
3633 let container_id = ContainerID::new_normal(id, child.kind());
3634 txn.apply_local_op(
3635 inner.container_idx,
3636 crate::op::RawOpContent::Map(crate::container::map::MapSet {
3637 key: key.into(),
3638 value: Some(LoroValue::Container(container_id.clone())),
3639 }),
3640 EventHint::Map {
3641 key: key.into(),
3642 value: Some(LoroValue::Container(container_id.clone())),
3643 },
3644 &inner.doc,
3645 )?;
3646
3647 child.attach(txn, inner, container_id)
3648 }
3649
3650 pub fn delete(&self, key: &str) -> LoroResult<()> {
3651 match &self.inner {
3652 MaybeDetached::Detached(m) => {
3653 let mut m = m.lock().unwrap();
3654 m.value.remove(key);
3655 Ok(())
3656 }
3657 MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, key)),
3658 }
3659 }
3660
3661 pub fn delete_with_txn(&self, txn: &mut Transaction, key: &str) -> LoroResult<()> {
3662 let inner = self.inner.try_attached_state()?;
3663 txn.apply_local_op(
3664 inner.container_idx,
3665 crate::op::RawOpContent::Map(crate::container::map::MapSet {
3666 key: key.into(),
3667 value: None,
3668 }),
3669 EventHint::Map {
3670 key: key.into(),
3671 value: None,
3672 },
3673 &inner.doc,
3674 )
3675 }
3676
3677 pub fn for_each<I>(&self, mut f: I)
3678 where
3679 I: FnMut(&str, ValueOrHandler),
3680 {
3681 match &self.inner {
3682 MaybeDetached::Detached(m) => {
3683 let m = m.lock().unwrap();
3684 for (k, v) in m.value.iter() {
3685 f(k, v.clone());
3686 }
3687 }
3688 MaybeDetached::Attached(inner) => {
3689 let mut temp = vec![];
3690 inner.with_state(|state| {
3691 let a = state.as_map_state().unwrap();
3692 for (k, v) in a.iter() {
3693 if let Some(v) = &v.value {
3694 match v {
3695 LoroValue::Container(c) => {
3696 temp.push((
3697 k.to_string(),
3698 ValueOrHandler::Handler(create_handler(inner, c.clone())),
3699 ));
3700 }
3701 value => {
3702 temp.push((k.to_string(), ValueOrHandler::Value(value.clone())))
3703 }
3704 }
3705 }
3706 }
3707 });
3708
3709 for (k, v) in temp.into_iter() {
3710 f(&k, v.clone());
3711 }
3712 }
3713 }
3714 }
3715
3716 pub fn get_child_handler(&self, key: &str) -> LoroResult<Handler> {
3717 match &self.inner {
3718 MaybeDetached::Detached(m) => {
3719 let m = m.lock().unwrap();
3720 let value = m.value.get(key).unwrap();
3721 match value {
3722 ValueOrHandler::Value(v) => Err(LoroError::ArgErr(
3723 format!("Expected Handler but found {:?}", v).into_boxed_str(),
3724 )),
3725 ValueOrHandler::Handler(h) => Ok(h.clone()),
3726 }
3727 }
3728 MaybeDetached::Attached(inner) => {
3729 let container_id = inner.with_state(|state| {
3730 state
3731 .as_map_state()
3732 .as_ref()
3733 .unwrap()
3734 .get(key)
3735 .unwrap()
3736 .as_container()
3737 .unwrap()
3738 .clone()
3739 });
3740 Ok(create_handler(inner, container_id))
3741 }
3742 }
3743 }
3744
3745 pub fn get_deep_value_with_id(&self) -> LoroResult<LoroValue> {
3746 match &self.inner {
3747 MaybeDetached::Detached(_) => Err(LoroError::MisuseDetachedContainer {
3748 method: "get_deep_value_with_id",
3749 }),
3750 MaybeDetached::Attached(inner) => Ok(inner.with_doc_state(|state| {
3751 state.get_container_deep_value_with_id(inner.container_idx, None)
3752 })),
3753 }
3754 }
3755
3756 pub fn get(&self, key: &str) -> Option<LoroValue> {
3757 match &self.inner {
3758 MaybeDetached::Detached(m) => {
3759 let m = m.lock().unwrap();
3760 m.value.get(key).map(|v| v.to_value())
3761 }
3762 MaybeDetached::Attached(inner) => {
3763 inner.with_state(|state| state.as_map_state().unwrap().get(key).cloned())
3764 }
3765 }
3766 }
3767
3768 pub fn get_(&self, key: &str) -> Option<ValueOrHandler> {
3770 match &self.inner {
3771 MaybeDetached::Detached(m) => {
3772 let m = m.lock().unwrap();
3773 m.value.get(key).cloned()
3774 }
3775 MaybeDetached::Attached(inner) => {
3776 let value =
3777 inner.with_state(|state| state.as_map_state().unwrap().get(key).cloned());
3778 match value {
3779 Some(LoroValue::Container(container_id)) => Some(ValueOrHandler::Handler(
3780 create_handler(inner, container_id.clone()),
3781 )),
3782 Some(value) => Some(ValueOrHandler::Value(value.clone())),
3783 None => None,
3784 }
3785 }
3786 }
3787 }
3788
3789 pub fn get_or_create_container<C: HandlerTrait>(&self, key: &str, child: C) -> LoroResult<C> {
3790 if let Some(ans) = self.get_(key) {
3791 if let ValueOrHandler::Handler(h) = ans {
3792 let kind = h.kind();
3793 return C::from_handler(h).ok_or_else(move || {
3794 LoroError::ArgErr(
3795 format!("Expected value type {} but found {:?}", child.kind(), kind)
3796 .into_boxed_str(),
3797 )
3798 });
3799 } else if let ValueOrHandler::Value(LoroValue::Null) = ans {
3800 } else {
3802 return Err(LoroError::ArgErr(
3803 format!("Expected value type {} but found {:?}", child.kind(), ans)
3804 .into_boxed_str(),
3805 ));
3806 }
3807 }
3808
3809 self.insert_container(key, child)
3810 }
3811
3812 pub fn contains_key(&self, key: &str) -> bool {
3813 self.get(key).is_some()
3814 }
3815
3816 pub fn len(&self) -> usize {
3817 match &self.inner {
3818 MaybeDetached::Detached(m) => m.lock().unwrap().value.len(),
3819 MaybeDetached::Attached(a) => a.with_state(|state| state.as_map_state().unwrap().len()),
3820 }
3821 }
3822
3823 pub fn is_empty(&self) -> bool {
3824 self.len() == 0
3825 }
3826
3827 pub fn is_deleted(&self) -> bool {
3828 match &self.inner {
3829 MaybeDetached::Detached(_) => false,
3830 MaybeDetached::Attached(a) => a.is_deleted(),
3831 }
3832 }
3833
3834 pub fn clear(&self) -> LoroResult<()> {
3835 match &self.inner {
3836 MaybeDetached::Detached(m) => {
3837 let mut m = m.lock().unwrap();
3838 m.value.clear();
3839 Ok(())
3840 }
3841 MaybeDetached::Attached(a) => a.with_txn(|txn| self.clear_with_txn(txn)),
3842 }
3843 }
3844
3845 pub fn clear_with_txn(&self, txn: &mut Transaction) -> LoroResult<()> {
3846 let keys: Vec<InternalString> = self.inner.try_attached_state()?.with_state(|state| {
3847 state
3848 .as_map_state()
3849 .unwrap()
3850 .iter()
3851 .map(|(k, _)| k.clone())
3852 .collect()
3853 });
3854
3855 for key in keys {
3856 self.delete_with_txn(txn, &key)?;
3857 }
3858
3859 Ok(())
3860 }
3861
3862 pub fn keys(&self) -> impl Iterator<Item = InternalString> + '_ {
3863 let mut keys: Vec<InternalString> = Vec::with_capacity(self.len());
3864 match &self.inner {
3865 MaybeDetached::Detached(m) => {
3866 let m = m.lock().unwrap();
3867 keys = m.value.keys().map(|x| x.as_str().into()).collect();
3868 }
3869 MaybeDetached::Attached(a) => {
3870 a.with_state(|state| {
3871 for (k, v) in state.as_map_state().unwrap().iter() {
3872 if v.value.is_some() {
3873 keys.push(k.clone());
3874 }
3875 }
3876 });
3877 }
3878 }
3879
3880 keys.into_iter()
3881 }
3882
3883 pub fn values(&self) -> impl Iterator<Item = ValueOrHandler> + '_ {
3884 let mut values: Vec<ValueOrHandler> = Vec::with_capacity(self.len());
3885 match &self.inner {
3886 MaybeDetached::Detached(m) => {
3887 let m = m.lock().unwrap();
3888 values = m.value.values().cloned().collect();
3889 }
3890 MaybeDetached::Attached(a) => {
3891 a.with_state(|state| {
3892 for (_, v) in state.as_map_state().unwrap().iter() {
3893 let value = match &v.value {
3894 Some(LoroValue::Container(container_id)) => {
3895 ValueOrHandler::Handler(create_handler(a, container_id.clone()))
3896 }
3897 Some(value) => ValueOrHandler::Value(value.clone()),
3898 None => continue,
3899 };
3900 values.push(value);
3901 }
3902 });
3903 }
3904 }
3905
3906 values.into_iter()
3907 }
3908
3909 pub fn get_last_editor(&self, key: &str) -> Option<PeerID> {
3910 match &self.inner {
3911 MaybeDetached::Detached(_) => None,
3912 MaybeDetached::Attached(a) => a.with_state(|state| {
3913 let m = state.as_map_state().unwrap();
3914 m.get_last_edit_peer(key)
3915 }),
3916 }
3917 }
3918}
3919
3920fn with_txn<R>(doc: &LoroDoc, f: impl FnOnce(&mut Transaction) -> LoroResult<R>) -> LoroResult<R> {
3921 let txn = &doc.txn;
3922 let mut txn = txn.lock().unwrap();
3923 loop {
3924 if let Some(txn) = &mut *txn {
3925 return f(txn);
3926 } else if cfg!(target_arch = "wasm32") || !doc.can_edit() {
3927 return Err(LoroError::AutoCommitNotStarted);
3928 } else {
3929 drop(txn);
3930 #[cfg(loom)]
3931 loom::thread::yield_now();
3932 doc.start_auto_commit();
3933 txn = doc.txn.lock().unwrap();
3934 }
3935 }
3936}
3937
3938#[cfg(feature = "counter")]
3939pub mod counter {
3940
3941 use loro_common::LoroResult;
3942
3943 use crate::{
3944 txn::{EventHint, Transaction},
3945 HandlerTrait,
3946 };
3947
3948 use super::{create_handler, Handler, MaybeDetached};
3949
3950 #[derive(Clone)]
3951 pub struct CounterHandler {
3952 pub(super) inner: MaybeDetached<f64>,
3953 }
3954
3955 impl CounterHandler {
3956 pub fn new_detached() -> Self {
3957 Self {
3958 inner: MaybeDetached::new_detached(0.),
3959 }
3960 }
3961
3962 pub fn increment(&self, n: f64) -> LoroResult<()> {
3963 match &self.inner {
3964 MaybeDetached::Detached(d) => {
3965 let d = &mut d.lock().unwrap().value;
3966 *d += n;
3967 Ok(())
3968 }
3969 MaybeDetached::Attached(a) => a.with_txn(|txn| self.increment_with_txn(txn, n)),
3970 }
3971 }
3972
3973 pub fn decrement(&self, n: f64) -> LoroResult<()> {
3974 match &self.inner {
3975 MaybeDetached::Detached(d) => {
3976 let d = &mut d.lock().unwrap().value;
3977 *d -= n;
3978 Ok(())
3979 }
3980 MaybeDetached::Attached(a) => a.with_txn(|txn| self.increment_with_txn(txn, -n)),
3981 }
3982 }
3983
3984 fn increment_with_txn(&self, txn: &mut Transaction, n: f64) -> LoroResult<()> {
3985 let inner = self.inner.try_attached_state()?;
3986 txn.apply_local_op(
3987 inner.container_idx,
3988 crate::op::RawOpContent::Counter(n),
3989 EventHint::Counter(n),
3990 &inner.doc,
3991 )
3992 }
3993
3994 pub fn is_deleted(&self) -> bool {
3995 match &self.inner {
3996 MaybeDetached::Detached(_) => false,
3997 MaybeDetached::Attached(a) => a.is_deleted(),
3998 }
3999 }
4000 }
4001
4002 impl std::fmt::Debug for CounterHandler {
4003 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4004 match &self.inner {
4005 MaybeDetached::Detached(_) => write!(f, "CounterHandler Detached"),
4006 MaybeDetached::Attached(a) => write!(f, "CounterHandler {}", a.id),
4007 }
4008 }
4009 }
4010
4011 impl HandlerTrait for CounterHandler {
4012 fn is_attached(&self) -> bool {
4013 matches!(&self.inner, MaybeDetached::Attached(..))
4014 }
4015
4016 fn attached_handler(&self) -> Option<&crate::BasicHandler> {
4017 self.inner.attached_handler()
4018 }
4019
4020 fn get_value(&self) -> loro_common::LoroValue {
4021 match &self.inner {
4022 MaybeDetached::Detached(t) => {
4023 let t = t.lock().unwrap();
4024 t.value.into()
4025 }
4026 MaybeDetached::Attached(a) => a.get_value(),
4027 }
4028 }
4029
4030 fn get_deep_value(&self) -> loro_common::LoroValue {
4031 self.get_value()
4032 }
4033
4034 fn kind(&self) -> loro_common::ContainerType {
4035 loro_common::ContainerType::Counter
4036 }
4037
4038 fn to_handler(&self) -> super::Handler {
4039 Handler::Counter(self.clone())
4040 }
4041
4042 fn from_handler(h: super::Handler) -> Option<Self> {
4043 match h {
4044 Handler::Counter(x) => Some(x),
4045 _ => None,
4046 }
4047 }
4048
4049 fn attach(
4050 &self,
4051 txn: &mut crate::txn::Transaction,
4052 parent: &crate::BasicHandler,
4053 self_id: loro_common::ContainerID,
4054 ) -> loro_common::LoroResult<Self> {
4055 match &self.inner {
4056 MaybeDetached::Detached(v) => {
4057 let mut v = v.lock().unwrap();
4058 let inner = create_handler(parent, self_id);
4059 let c = inner.into_counter().unwrap();
4060
4061 c.increment_with_txn(txn, v.value)?;
4062
4063 v.attached = c.attached_handler().cloned();
4064 Ok(c)
4065 }
4066 MaybeDetached::Attached(a) => {
4067 let new_inner = create_handler(a, self_id);
4068 let ans = new_inner.into_counter().unwrap();
4069 let delta = *self.get_value().as_double().unwrap();
4070 ans.increment_with_txn(txn, delta)?;
4071 Ok(ans)
4072 }
4073 }
4074 }
4075
4076 fn get_attached(&self) -> Option<Self> {
4077 match &self.inner {
4078 MaybeDetached::Attached(a) => Some(Self {
4079 inner: MaybeDetached::Attached(a.clone()),
4080 }),
4081 MaybeDetached::Detached(_) => None,
4082 }
4083 }
4084
4085 fn doc(&self) -> Option<crate::LoroDoc> {
4086 match &self.inner {
4087 MaybeDetached::Detached(_) => None,
4088 MaybeDetached::Attached(a) => Some(a.doc()),
4089 }
4090 }
4091 }
4092}
4093
4094#[cfg(test)]
4095mod test {
4096
4097 use super::{HandlerTrait, TextDelta};
4098 use crate::state::TreeParentId;
4099 use crate::version::Frontiers;
4100 use crate::LoroDoc;
4101 use crate::{fx_map, ToJson};
4102 use loro_common::ID;
4103 use serde_json::json;
4104
4105 #[test]
4106 fn import() {
4107 let loro = LoroDoc::new();
4108 loro.set_peer_id(1).unwrap();
4109 let loro2 = LoroDoc::new();
4110 loro2.set_peer_id(2).unwrap();
4111
4112 let mut txn = loro.txn().unwrap();
4113 let text = txn.get_text("hello");
4114 text.insert_with_txn(&mut txn, 0, "hello").unwrap();
4115 txn.commit().unwrap();
4116 let exported = loro.export_from(&Default::default());
4117 loro2.import(&exported).unwrap();
4118 let mut txn = loro2.txn().unwrap();
4119 let text = txn.get_text("hello");
4120 assert_eq!(&**text.get_value().as_string().unwrap(), "hello");
4121 text.insert_with_txn(&mut txn, 5, " world").unwrap();
4122 assert_eq!(&**text.get_value().as_string().unwrap(), "hello world");
4123 txn.commit().unwrap();
4124 loro.import(&loro2.export_from(&Default::default()))
4125 .unwrap();
4126 let txn = loro.txn().unwrap();
4127 let text = txn.get_text("hello");
4128 assert_eq!(&**text.get_value().as_string().unwrap(), "hello world");
4129 }
4130
4131 #[test]
4132 fn richtext_handler() {
4133 let loro = LoroDoc::new();
4134 loro.set_peer_id(1).unwrap();
4135 let loro2 = LoroDoc::new();
4136 loro2.set_peer_id(2).unwrap();
4137
4138 let mut txn = loro.txn().unwrap();
4139 let text = txn.get_text("hello");
4140 text.insert_with_txn(&mut txn, 0, "hello").unwrap();
4141 txn.commit().unwrap();
4142 let exported = loro.export_from(&Default::default());
4143
4144 loro2.import(&exported).unwrap();
4145 let mut txn = loro2.txn().unwrap();
4146 let text = txn.get_text("hello");
4147 assert_eq!(&**text.get_value().as_string().unwrap(), "hello");
4148 text.insert_with_txn(&mut txn, 5, " world").unwrap();
4149 assert_eq!(&**text.get_value().as_string().unwrap(), "hello world");
4150 txn.commit().unwrap();
4151
4152 loro.import(&loro2.export_from(&Default::default()))
4153 .unwrap();
4154 let txn = loro.txn().unwrap();
4155 let text = txn.get_text("hello");
4156 assert_eq!(&**text.get_value().as_string().unwrap(), "hello world");
4157 txn.commit().unwrap();
4158
4159 loro.checkout(&Frontiers::from_id(ID::new(2, 1))).unwrap();
4161 assert_eq!(&**text.get_value().as_string().unwrap(), "hello w");
4162 }
4163
4164 #[test]
4165 fn richtext_handler_concurrent() {
4166 let loro = LoroDoc::new();
4167 let mut txn = loro.txn().unwrap();
4168 let handler = loro.get_text("richtext");
4169 handler.insert_with_txn(&mut txn, 0, "hello").unwrap();
4170 txn.commit().unwrap();
4171 for i in 0..100 {
4172 let new_loro = LoroDoc::new();
4173 new_loro
4174 .import(&loro.export_from(&Default::default()))
4175 .unwrap();
4176 let mut txn = new_loro.txn().unwrap();
4177 let handler = new_loro.get_text("richtext");
4178 handler
4179 .insert_with_txn(&mut txn, i % 5, &i.to_string())
4180 .unwrap();
4181 txn.commit().unwrap();
4182 loro.import(&new_loro.export_from(&loro.oplog_vv()))
4183 .unwrap();
4184 }
4185 }
4186
4187 #[test]
4188 fn richtext_handler_mark() {
4189 let loro = LoroDoc::new_auto_commit();
4190 let handler = loro.get_text("richtext");
4191 handler.insert(0, "hello world").unwrap();
4192 handler.mark(0, 5, "bold", true.into()).unwrap();
4193 loro.commit_then_renew();
4194
4195 let value = handler.get_richtext_value();
4197 assert_eq!(value[0]["insert"], "hello".into());
4198 let meta = value[0]["attributes"].as_map().unwrap();
4199 assert_eq!(meta.len(), 1);
4200 meta.get("bold").unwrap();
4201
4202 let loro2 = LoroDoc::new_auto_commit();
4203 loro2
4204 .import(&loro.export_from(&Default::default()))
4205 .unwrap();
4206 let handler2 = loro2.get_text("richtext");
4207 assert_eq!(&**handler2.get_value().as_string().unwrap(), "hello world");
4208
4209 let value = handler2.get_richtext_value();
4211 assert_eq!(value[0]["insert"], "hello".into());
4212 let meta = value[0]["attributes"].as_map().unwrap();
4213 assert_eq!(meta.len(), 1);
4214 meta.get("bold").unwrap();
4215
4216 {
4218 handler2.insert(5, " new").unwrap();
4219 let value = handler2.get_richtext_value();
4220 assert_eq!(
4221 value.to_json_value(),
4222 serde_json::json!([
4223 {"insert": "hello new", "attributes": {"bold": true}},
4224 {"insert": " world"}
4225 ])
4226 );
4227 }
4228 }
4229
4230 #[test]
4231 fn richtext_snapshot() {
4232 let loro = LoroDoc::new();
4233 let mut txn = loro.txn().unwrap();
4234 let handler = loro.get_text("richtext");
4235 handler.insert_with_txn(&mut txn, 0, "hello world").unwrap();
4236 handler
4237 .mark_with_txn(&mut txn, 0, 5, "bold", true.into(), false)
4238 .unwrap();
4239 txn.commit().unwrap();
4240
4241 let loro2 = LoroDoc::new();
4242 loro2.import(&loro.export_snapshot().unwrap()).unwrap();
4243 let handler2 = loro2.get_text("richtext");
4244 assert_eq!(
4245 handler2.get_richtext_value().to_json_value(),
4246 serde_json::json!([
4247 {"insert": "hello", "attributes": {"bold": true}},
4248 {"insert": " world"}
4249 ])
4250 );
4251 }
4252
4253 #[test]
4254 fn tree_meta() {
4255 let loro = LoroDoc::new_auto_commit();
4256 loro.set_peer_id(1).unwrap();
4257 let tree = loro.get_tree("root");
4258 let id = tree.create(TreeParentId::Root).unwrap();
4259 let meta = tree.get_meta(id).unwrap();
4260 meta.insert("a", 123).unwrap();
4261 loro.commit_then_renew();
4262 let meta = tree.get_meta(id).unwrap();
4263 assert_eq!(meta.get("a").unwrap(), 123.into());
4264 assert_eq!(
4265 r#"[{"parent":null,"meta":{"a":123},"id":"0@1","index":0,"children":[],"fractional_index":"80"}]"#,
4266 tree.get_deep_value().to_json()
4267 );
4268 let bytes = loro.export_snapshot().unwrap();
4269 let loro2 = LoroDoc::new();
4270 loro2.import(&bytes).unwrap();
4271 }
4272
4273 #[test]
4274 fn tree_meta_event() {
4275 use std::sync::Arc;
4276 let loro = LoroDoc::new_auto_commit();
4277 let tree = loro.get_tree("root");
4278 let text = loro.get_text("text");
4279
4280 let id = tree.create(TreeParentId::Root).unwrap();
4281 let meta = tree.get_meta(id).unwrap();
4282 meta.insert("a", 1).unwrap();
4283 text.insert(0, "abc").unwrap();
4284 let _id2 = tree.create(TreeParentId::Root).unwrap();
4285 meta.insert("b", 2).unwrap();
4286
4287 let loro2 = LoroDoc::new_auto_commit();
4288 let _g = loro2.subscribe_root(Arc::new(|e| {
4289 println!("{} {:?} ", e.event_meta.by, e.event_meta.diff)
4290 }));
4291 loro2.import(&loro.export_from(&loro2.oplog_vv())).unwrap();
4292 assert_eq!(loro.get_deep_value(), loro2.get_deep_value());
4293 }
4294
4295 #[test]
4296 fn richtext_apply_delta() {
4297 let loro = LoroDoc::new_auto_commit();
4298 let text = loro.get_text("text");
4299 text.apply_delta(&[TextDelta::Insert {
4300 insert: "Hello World!".into(),
4301 attributes: None,
4302 }])
4303 .unwrap();
4304 dbg!(text.get_richtext_value());
4305 text.apply_delta(&[
4306 TextDelta::Retain {
4307 retain: 6,
4308 attributes: Some(fx_map!("italic".into() => loro_common::LoroValue::Bool(true))),
4309 },
4310 TextDelta::Insert {
4311 insert: "New ".into(),
4312 attributes: Some(fx_map!("bold".into() => loro_common::LoroValue::Bool(true))),
4313 },
4314 ])
4315 .unwrap();
4316 dbg!(text.get_richtext_value());
4317 loro.commit_then_renew();
4318 assert_eq!(
4319 text.get_richtext_value().to_json_value(),
4320 json!([
4321 {"insert": "Hello ", "attributes": {"italic": true}},
4322 {"insert": "New ", "attributes": {"bold": true}},
4323 {"insert": "World!"}
4324
4325 ])
4326 )
4327 }
4328}