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