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