1use crate::sync::{AtomicU64, Mutex};
2use std::sync::RwLock;
3use std::sync::{Arc, Weak};
4use std::{borrow::Cow, io::Write, sync::atomic::Ordering};
5
6use container_store::ContainerStore;
7use dead_containers_cache::DeadContainersCache;
8use enum_as_inner::EnumAsInner;
9use enum_dispatch::enum_dispatch;
10use rustc_hash::{FxHashMap, FxHashSet};
11use itertools::Itertools;
12use loro_common::{ContainerID, LoroError, LoroResult, TreeID};
13use loro_delta::DeltaItem;
14use tracing::{info_span, instrument, warn};
15
16use crate::{
17 configure::{Configure, DefaultRandom, SecureRandomGenerator},
18 container::{idx::ContainerIdx, richtext::config::StyleConfigMap, ContainerIdRaw},
19 cursor::Cursor,
20 delta::TreeExternalDiff,
21 diff_calc::{DiffCalculator, DiffMode},
22 encoding::{StateSnapshotDecodeContext, StateSnapshotEncoder},
23 event::{Diff, EventTriggerKind, Index, InternalContainerDiff, InternalDiff},
24 fx_map,
25 handler::ValueOrHandler,
26 id::PeerID,
27 lock::{LoroLockGroup, LoroMutex},
28 op::{Op, RawOp},
29 version::Frontiers,
30 ContainerDiff, ContainerType, DocDiff, InternalString, LoroDocInner, LoroValue, OpLog,
31};
32
33pub(crate) mod analyzer;
34pub(crate) mod container_store;
35#[cfg(feature = "counter")]
36mod counter_state;
37mod dead_containers_cache;
38mod list_state;
39mod map_state;
40mod movable_list_state;
41mod richtext_state;
42mod tree_state;
43mod unknown_state;
44
45pub(crate) use self::movable_list_state::{IndexType, MovableListState};
46pub(crate) use container_store::GcStore;
47pub(crate) use list_state::ListState;
48pub(crate) use map_state::MapState;
49pub(crate) use richtext_state::RichtextState;
50pub(crate) use tree_state::FiIfNotConfigured;
51pub(crate) use tree_state::{get_meta_value, FractionalIndexGenResult, NodePosition, TreeState};
52pub use tree_state::{TreeNode, TreeNodeWithChildren, TreeParentId};
53
54use self::{container_store::ContainerWrapper, unknown_state::UnknownState};
55
56#[cfg(feature = "counter")]
57use self::counter_state::CounterState;
58
59use super::{arena::SharedArena, event::InternalDocDiff};
60
61pub struct DocState {
62 pub(super) peer: Arc<AtomicU64>,
63
64 pub(super) frontiers: Frontiers,
65 pub(super) store: ContainerStore,
67 pub(super) arena: SharedArena,
68 pub(crate) config: Configure,
69 doc: Weak<LoroDocInner>,
71 in_txn: bool,
73 changed_idx_in_txn: FxHashSet<ContainerIdx>,
74
75 event_recorder: EventRecorder,
77
78 dead_containers_cache: DeadContainersCache,
79}
80
81impl std::fmt::Debug for DocState {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 f.debug_struct("DocState")
84 .field("peer", &self.peer)
85 .finish()
86 }
87}
88
89#[derive(Clone, Copy)]
90pub(crate) struct ContainerCreationContext<'a> {
91 pub configure: &'a Configure,
92 pub peer: PeerID,
93}
94
95pub(crate) struct DiffApplyContext<'a> {
96 pub mode: DiffMode,
97 pub doc: &'a Weak<LoroDocInner>,
98}
99
100pub(crate) trait FastStateSnapshot {
101 fn encode_snapshot_fast<W: Write>(&mut self, w: W);
102 fn decode_value(bytes: &[u8]) -> LoroResult<(LoroValue, &[u8])>;
103 fn decode_snapshot_fast(
104 idx: ContainerIdx,
105 v: (LoroValue, &[u8]),
106 ctx: ContainerCreationContext,
107 ) -> LoroResult<Self>
108 where
109 Self: Sized;
110}
111
112#[derive(Debug, Clone, Default)]
113pub(crate) struct ApplyLocalOpReturn {
114 pub deleted_containers: Vec<ContainerID>,
115}
116
117#[enum_dispatch]
118pub(crate) trait ContainerState {
119 fn container_idx(&self) -> ContainerIdx;
120 fn estimate_size(&self) -> usize;
121
122 fn is_state_empty(&self) -> bool;
123
124 #[must_use]
125 fn apply_diff_and_convert(&mut self, diff: InternalDiff, ctx: DiffApplyContext) -> Diff;
126
127 fn apply_diff(&mut self, diff: InternalDiff, ctx: DiffApplyContext);
128
129 fn apply_local_op(&mut self, raw_op: &RawOp, op: &Op) -> LoroResult<ApplyLocalOpReturn>;
130 fn to_diff(&mut self, doc: &Weak<LoroDocInner>) -> Diff;
132
133 fn get_value(&mut self) -> LoroValue;
134
135 #[allow(unused)]
137 fn get_child_index(&self, id: &ContainerID) -> Option<Index>;
138
139 #[allow(unused)]
140 fn contains_child(&self, id: &ContainerID) -> bool;
141
142 #[allow(unused)]
143 fn get_child_containers(&self) -> Vec<ContainerID>;
144
145 fn encode_snapshot(&self, encoder: StateSnapshotEncoder) -> Vec<u8>;
151
152 fn import_from_snapshot_ops(&mut self, ctx: StateSnapshotDecodeContext) -> LoroResult<()>;
154 fn fork(&self, config: &Configure) -> Self;
155}
156
157impl<T: FastStateSnapshot> FastStateSnapshot for Box<T> {
158 fn encode_snapshot_fast<W: Write>(&mut self, w: W) {
159 self.as_mut().encode_snapshot_fast(w)
160 }
161
162 fn decode_value(bytes: &[u8]) -> LoroResult<(LoroValue, &[u8])> {
163 T::decode_value(bytes)
164 }
165
166 fn decode_snapshot_fast(
167 idx: ContainerIdx,
168 v: (LoroValue, &[u8]),
169 ctx: ContainerCreationContext,
170 ) -> LoroResult<Self>
171 where
172 Self: Sized,
173 {
174 T::decode_snapshot_fast(idx, v, ctx).map(|x| Box::new(x))
175 }
176}
177
178impl<T: ContainerState> ContainerState for Box<T> {
179 fn container_idx(&self) -> ContainerIdx {
180 self.as_ref().container_idx()
181 }
182
183 fn estimate_size(&self) -> usize {
184 self.as_ref().estimate_size()
185 }
186
187 fn is_state_empty(&self) -> bool {
188 self.as_ref().is_state_empty()
189 }
190
191 fn apply_diff_and_convert(&mut self, diff: InternalDiff, ctx: DiffApplyContext) -> Diff {
192 self.as_mut().apply_diff_and_convert(diff, ctx)
193 }
194
195 fn apply_diff(&mut self, diff: InternalDiff, ctx: DiffApplyContext) {
196 self.as_mut().apply_diff(diff, ctx)
197 }
198
199 fn apply_local_op(&mut self, raw_op: &RawOp, op: &Op) -> LoroResult<ApplyLocalOpReturn> {
200 self.as_mut().apply_local_op(raw_op, op)
201 }
202
203 #[doc = r" Convert a state to a diff, such that an empty state will be transformed into the same as this state when it's applied."]
204 fn to_diff(&mut self, doc: &Weak<LoroDocInner>) -> Diff {
205 self.as_mut().to_diff(doc)
206 }
207
208 fn get_value(&mut self) -> LoroValue {
209 self.as_mut().get_value()
210 }
211
212 #[doc = r" Get the index of the child container"]
213 #[allow(unused)]
214 fn get_child_index(&self, id: &ContainerID) -> Option<Index> {
215 self.as_ref().get_child_index(id)
216 }
217
218 fn contains_child(&self, id: &ContainerID) -> bool {
219 self.as_ref().contains_child(id)
220 }
221
222 #[allow(unused)]
223 fn get_child_containers(&self) -> Vec<ContainerID> {
224 self.as_ref().get_child_containers()
225 }
226
227 #[doc = r" Encode the ops and the blob that can be used to restore the state to the current state."]
228 #[doc = r""]
229 #[doc = r" State will use the provided encoder to encode the ops and export a blob."]
230 #[doc = r" The ops should be encoded into the snapshot as well as the blob."]
231 #[doc = r" The users then can use the ops and the blob to restore the state to the current state."]
232 fn encode_snapshot(&self, encoder: StateSnapshotEncoder) -> Vec<u8> {
233 self.as_ref().encode_snapshot(encoder)
234 }
235
236 #[doc = r" Restore the state to the state represented by the ops and the blob that exported by `get_snapshot_ops`"]
237 fn import_from_snapshot_ops(&mut self, ctx: StateSnapshotDecodeContext) -> LoroResult<()> {
238 self.as_mut().import_from_snapshot_ops(ctx)
239 }
240
241 fn fork(&self, config: &Configure) -> Self {
242 Box::new(self.as_ref().fork(config))
243 }
244}
245
246#[allow(clippy::enum_variant_names)]
247#[enum_dispatch(ContainerState)]
248#[derive(EnumAsInner, Debug)]
249pub enum State {
250 ListState(Box<ListState>),
251 MovableListState(Box<MovableListState>),
252 MapState(Box<MapState>),
253 RichtextState(Box<RichtextState>),
254 TreeState(Box<TreeState>),
255 #[cfg(feature = "counter")]
256 CounterState(Box<counter_state::CounterState>),
257 UnknownState(UnknownState),
258}
259
260impl From<ListState> for State {
261 fn from(s: ListState) -> Self {
262 Self::ListState(Box::new(s))
263 }
264}
265
266impl From<RichtextState> for State {
267 fn from(s: RichtextState) -> Self {
268 Self::RichtextState(Box::new(s))
269 }
270}
271
272impl From<MovableListState> for State {
273 fn from(s: MovableListState) -> Self {
274 Self::MovableListState(Box::new(s))
275 }
276}
277
278impl From<MapState> for State {
279 fn from(s: MapState) -> Self {
280 Self::MapState(Box::new(s))
281 }
282}
283
284impl From<TreeState> for State {
285 fn from(s: TreeState) -> Self {
286 Self::TreeState(Box::new(s))
287 }
288}
289
290#[cfg(feature = "counter")]
291impl From<CounterState> for State {
292 fn from(s: CounterState) -> Self {
293 Self::CounterState(Box::new(s))
294 }
295}
296
297impl State {
298 pub fn new_list(idx: ContainerIdx) -> Self {
299 Self::ListState(Box::new(ListState::new(idx)))
300 }
301
302 pub fn new_map(idx: ContainerIdx) -> Self {
303 Self::MapState(Box::new(MapState::new(idx)))
304 }
305
306 pub fn new_richtext(idx: ContainerIdx, config: Arc<RwLock<StyleConfigMap>>) -> Self {
307 Self::RichtextState(Box::new(RichtextState::new(idx, config)))
308 }
309
310 pub fn new_tree(idx: ContainerIdx, peer: PeerID) -> Self {
311 Self::TreeState(Box::new(TreeState::new(idx, peer)))
312 }
313
314 pub fn new_unknown(idx: ContainerIdx) -> Self {
315 Self::UnknownState(UnknownState::new(idx))
316 }
317
318 pub fn encode_snapshot_fast<W: Write>(&mut self, mut w: W) {
319 match self {
320 State::ListState(s) => s.encode_snapshot_fast(&mut w),
321 State::MovableListState(s) => s.encode_snapshot_fast(&mut w),
322 State::MapState(s) => s.encode_snapshot_fast(&mut w),
323 State::RichtextState(s) => s.encode_snapshot_fast(&mut w),
324 State::TreeState(s) => s.encode_snapshot_fast(&mut w),
325 #[cfg(feature = "counter")]
326 State::CounterState(s) => s.encode_snapshot_fast(&mut w),
327 State::UnknownState(s) => s.encode_snapshot_fast(&mut w),
328 }
329 }
330
331 pub fn fork(&self, config: &Configure) -> Self {
332 match self {
333 State::ListState(list_state) => State::ListState(list_state.fork(config)),
334 State::MovableListState(movable_list_state) => {
335 State::MovableListState(movable_list_state.fork(config))
336 }
337 State::MapState(map_state) => State::MapState(map_state.fork(config)),
338 State::RichtextState(richtext_state) => {
339 State::RichtextState(richtext_state.fork(config))
340 }
341 State::TreeState(tree_state) => State::TreeState(tree_state.fork(config)),
342 #[cfg(feature = "counter")]
343 State::CounterState(counter_state) => State::CounterState(counter_state.fork(config)),
344 State::UnknownState(unknown_state) => State::UnknownState(unknown_state.fork(config)),
345 }
346 }
347}
348
349impl DocState {
350 #[inline]
351 pub fn new_arc(
352 doc: Weak<LoroDocInner>,
353 arena: SharedArena,
354 config: Configure,
355 lock_group: &LoroLockGroup,
356 ) -> Arc<LoroMutex<Self>> {
357 let peer = DefaultRandom.next_u64();
358 let peer = Arc::new(AtomicU64::new(peer));
361 Arc::new(lock_group.new_lock(
362 Self {
363 store: ContainerStore::new(arena.clone(), config.clone(), peer.clone()),
364 peer,
365 arena,
366 frontiers: Frontiers::default(),
367 doc,
368 config,
369 in_txn: false,
370 changed_idx_in_txn: FxHashSet::default(),
371 event_recorder: Default::default(),
372 dead_containers_cache: Default::default(),
373 },
374 crate::lock::LockKind::DocState,
375 ))
376 }
377
378 pub fn fork_with_new_peer_id(
379 &mut self,
380 doc: Weak<LoroDocInner>,
381 arena: SharedArena,
382 config: Configure,
383 ) -> Arc<Mutex<Self>> {
384 let peer = Arc::new(AtomicU64::new(DefaultRandom.next_u64()));
385 let store = self.store.fork(arena.clone(), peer.clone(), config.clone());
386 Arc::new(Mutex::new(Self {
387 peer,
388 frontiers: self.frontiers.clone(),
389 store,
390 arena,
391 config,
392 doc,
393 in_txn: false,
394 changed_idx_in_txn: FxHashSet::default(),
395 event_recorder: Default::default(),
396 dead_containers_cache: Default::default(),
397 }))
398 }
399
400 pub fn start_recording(&mut self) {
401 if self.is_recording() {
402 return;
403 }
404
405 self.event_recorder.recording_diff = true;
406 self.event_recorder.diff_start_version = Some(self.frontiers.clone());
407 }
408
409 #[inline(always)]
410 pub fn stop_and_clear_recording(&mut self) {
411 self.event_recorder = Default::default();
412 }
413
414 #[inline(always)]
415 pub fn is_recording(&self) -> bool {
416 self.event_recorder.recording_diff
417 }
418
419 pub fn refresh_peer_id(&mut self) {
420 self.peer.store(
421 DefaultRandom.next_u64(),
422 std::sync::atomic::Ordering::Relaxed,
423 );
424 }
425
426 pub fn take_events(&mut self) -> Vec<DocDiff> {
428 if !self.is_recording() {
429 return vec![];
430 }
431
432 self.convert_current_batch_diff_into_event();
433 std::mem::take(&mut self.event_recorder.events)
434 }
435
436 fn record_diff(&mut self, diff: InternalDocDiff) {
444 if !self.event_recorder.recording_diff || diff.diff.is_empty() {
445 return;
446 }
447
448 let Some(last_diff) = self.event_recorder.diffs.last_mut() else {
449 self.event_recorder.diffs.push(diff.into_owned());
450 return;
451 };
452
453 if last_diff.can_merge(&diff) {
454 self.event_recorder.diffs.push(diff.into_owned());
455 return;
456 }
457
458 panic!("should call pre_txn before record_diff")
459 }
460
461 fn pre_txn(&mut self, next_origin: InternalString, next_trigger: EventTriggerKind) {
463 if !self.is_recording() {
464 return;
465 }
466
467 let Some(last_diff) = self.event_recorder.diffs.last() else {
468 return;
469 };
470
471 if last_diff.origin == next_origin && last_diff.by == next_trigger {
472 return;
473 }
474
475 self.convert_current_batch_diff_into_event()
478 }
479
480 fn convert_current_batch_diff_into_event(&mut self) {
481 let recorder = &mut self.event_recorder;
482 if recorder.diffs.is_empty() {
483 return;
484 }
485
486 let diffs = std::mem::take(&mut recorder.diffs);
487 let start = recorder.diff_start_version.take().unwrap();
488 recorder.diff_start_version = Some((*diffs.last().unwrap().new_version).to_owned());
489 let event = self.diffs_to_event(diffs, start);
490 self.event_recorder.events.push(event);
491 }
492
493 #[inline]
496 pub fn set_peer_id(&mut self, peer: PeerID) {
497 self.peer.store(peer, std::sync::atomic::Ordering::Relaxed);
498 }
499
500 pub fn peer_id(&self) -> PeerID {
501 self.peer.load(std::sync::atomic::Ordering::Relaxed)
502 }
503
504 #[instrument(skip_all)]
507 pub(crate) fn apply_diff(&mut self, mut diff: InternalDocDiff<'static>, diff_mode: DiffMode) {
508 if self.in_txn {
509 panic!("apply_diff should not be called in a transaction");
510 }
511
512 match diff_mode {
513 DiffMode::Checkout => {
514 self.dead_containers_cache.clear();
515 }
516 _ => {
517 self.dead_containers_cache.clear_alive();
518 }
519 }
520
521 let is_recording = self.is_recording();
522 self.pre_txn(diff.origin.clone(), diff.by);
523 let Cow::Owned(mut diffs) = std::mem::take(&mut diff.diff) else {
524 unreachable!()
525 };
526
527 diffs.sort_by_cached_key(|diff| self.arena.get_depth(diff.idx));
554 let mut to_revive_in_next_layer: FxHashSet<ContainerIdx> = FxHashSet::default();
555 let mut to_revive_in_this_layer: FxHashSet<ContainerIdx> = FxHashSet::default();
556 let mut last_depth = 0;
557 let len = diffs.len();
558 for mut diff in std::mem::replace(&mut diffs, Vec::with_capacity(len)) {
559 let Some(depth) = self.arena.get_depth(diff.idx) else {
560 warn!("{:?} is not in arena. It could be a dangling container that was deleted before the shallow start version.", self.arena.idx_to_id(diff.idx));
561 continue;
562 };
563 let this_depth = depth.get();
564 while this_depth > last_depth {
565 let to_create = std::mem::take(&mut to_revive_in_this_layer);
568 to_revive_in_this_layer = std::mem::take(&mut to_revive_in_next_layer);
569 for new in to_create {
570 let state = self.store.get_or_create_mut(new);
571 if state.is_state_empty() {
572 continue;
573 }
574
575 let external_diff = state.to_diff(&self.doc);
576 trigger_on_new_container(
577 &external_diff,
578 |cid| {
579 to_revive_in_this_layer.insert(cid);
580 },
581 &self.arena,
582 );
583
584 diffs.push(InternalContainerDiff {
585 idx: new,
586 bring_back: true,
587 diff: external_diff.into(),
588 diff_mode: DiffMode::Checkout,
589 });
590 }
591
592 last_depth += 1;
593 }
594
595 let idx = diff.idx;
596 let internal_diff = std::mem::take(&mut diff.diff);
597 match &internal_diff {
598 crate::event::DiffVariant::None => {
599 if is_recording {
600 let state = self.store.get_or_create_mut(diff.idx);
601 let extern_diff = state.to_diff(&self.doc);
602 trigger_on_new_container(
603 &extern_diff,
604 |cid| {
605 to_revive_in_next_layer.insert(cid);
606 },
607 &self.arena,
608 );
609 diff.diff = extern_diff.into();
610 }
611 }
612 crate::event::DiffVariant::Internal(_) => {
613 let cid = self.arena.idx_to_id(idx).unwrap();
614 info_span!("apply diff on", container_id = ?cid).in_scope(|| {
615 if self.in_txn {
616 self.changed_idx_in_txn.insert(idx);
617 }
618 let state = self.store.get_or_create_mut(idx);
619 if is_recording {
620 let external_diff =
622 if diff.bring_back || to_revive_in_this_layer.contains(&idx) {
623 state.apply_diff(
624 internal_diff.into_internal().unwrap(),
625 DiffApplyContext {
626 mode: diff.diff_mode,
627 doc: &self.doc,
628 },
629 );
630 state.to_diff(&self.doc)
631 } else {
632 state.apply_diff_and_convert(
633 internal_diff.into_internal().unwrap(),
634 DiffApplyContext {
635 mode: diff.diff_mode,
636 doc: &self.doc,
637 },
638 )
639 };
640 trigger_on_new_container(
641 &external_diff,
642 |cid| {
643 to_revive_in_next_layer.insert(cid);
644 },
645 &self.arena,
646 );
647 diff.diff = external_diff.into();
648 } else {
649 state.apply_diff(
650 internal_diff.into_internal().unwrap(),
651 DiffApplyContext {
652 mode: diff.diff_mode,
653 doc: &self.doc,
654 },
655 );
656 }
657 });
658 }
659 crate::event::DiffVariant::External(_) => unreachable!(),
660 }
661
662 to_revive_in_this_layer.remove(&idx);
663 if !diff.diff.is_empty() {
664 diffs.push(diff);
665 }
666 }
667
668 while !to_revive_in_this_layer.is_empty() || !to_revive_in_next_layer.is_empty() {
670 let to_create = std::mem::take(&mut to_revive_in_this_layer);
671 for new in to_create {
672 let state = self.store.get_or_create_mut(new);
673 if state.is_state_empty() {
674 continue;
675 }
676
677 let external_diff = state.to_diff(&self.doc);
678 trigger_on_new_container(
679 &external_diff,
680 |cid| {
681 to_revive_in_next_layer.insert(cid);
682 },
683 &self.arena,
684 );
685
686 if !external_diff.is_empty() {
687 diffs.push(InternalContainerDiff {
688 idx: new,
689 bring_back: true,
690 diff: external_diff.into(),
691 diff_mode: DiffMode::Checkout,
692 });
693 }
694 }
695
696 to_revive_in_this_layer = std::mem::take(&mut to_revive_in_next_layer);
697 }
698
699 diff.diff = diffs.into();
700 self.frontiers = diff.new_version.clone().into_owned();
701 if self.is_recording() {
702 self.record_diff(diff)
703 }
704 }
705
706 pub fn apply_local_op(&mut self, raw_op: &RawOp, op: &Op) -> LoroResult<()> {
707 self.set_container_parent_by_raw_op(raw_op);
709 let state = self.store.get_or_create_mut(op.container);
710 if self.in_txn {
711 self.changed_idx_in_txn.insert(op.container);
712 }
713 let ret = state.apply_local_op(raw_op, op)?;
714 if !ret.deleted_containers.is_empty() {
715 self.dead_containers_cache.clear_alive();
716 }
717
718 Ok(())
719 }
720
721 pub(crate) fn start_txn(&mut self, origin: InternalString, trigger: EventTriggerKind) {
722 self.pre_txn(origin, trigger);
723 self.in_txn = true;
724 }
725
726 pub(crate) fn abort_txn(&mut self) {
727 self.in_txn = false;
728 }
729
730 pub fn iter_and_decode_all(&mut self) -> impl Iterator<Item = &mut State> {
731 self.store.iter_and_decode_all()
732 }
733
734 pub(crate) fn iter_all_containers_mut(
735 &mut self,
736 ) -> impl Iterator<Item = (&ContainerIdx, &mut ContainerWrapper)> {
737 self.store.iter_all_containers()
738 }
739
740 pub fn does_container_exist(&mut self, id: &ContainerID) -> bool {
741 if id.is_root() {
744 return true;
745 }
746
747 if self.arena.id_to_idx(id).is_some() {
748 return true;
749 }
750
751 self.store.contains_id(id)
752 }
753
754 pub(crate) fn init_container(
755 &mut self,
756 cid: ContainerID,
757 decode_ctx: StateSnapshotDecodeContext,
758 ) -> LoroResult<()> {
759 let idx = self.arena.register_container(&cid);
760 let state = self.store.get_or_create_mut(idx);
761 state.import_from_snapshot_ops(decode_ctx)
762 }
763
764 pub(crate) fn init_unknown_container(&mut self, cid: ContainerID) {
765 let idx = self.arena.register_container(&cid);
766 self.store.get_or_create_imm(idx);
767 }
768
769 pub(crate) fn commit_txn(&mut self, new_frontiers: Frontiers, diff: Option<InternalDocDiff>) {
770 self.in_txn = false;
771 self.frontiers = new_frontiers;
772 if self.is_recording() {
773 self.record_diff(diff.unwrap());
774 }
775 }
776
777 #[inline]
778 pub(super) fn get_container_mut(&mut self, idx: ContainerIdx) -> Option<&mut State> {
779 self.store.get_container_mut(idx)
780 }
781
782 #[inline]
784 pub(crate) fn ensure_container(&mut self, id: &ContainerID) {
785 self.store.ensure_container(id);
786 }
787
788 pub(crate) fn ensure_all_alive_containers(&mut self) -> FxHashSet<ContainerID> {
790 let ans = self.get_all_alive_containers();
793 for id in ans.iter() {
794 self.ensure_container(id);
795 }
796
797 ans
798 }
799
800 pub(crate) fn get_value_by_idx(&mut self, container_idx: ContainerIdx) -> LoroValue {
801 self.store
802 .get_value(container_idx)
803 .unwrap_or_else(|| container_idx.get_type().default_value())
804 }
805
806 pub(super) fn init_with_states_and_version(
813 &mut self,
814 frontiers: Frontiers,
815 oplog: &OpLog,
816 unknown_containers: Vec<ContainerIdx>,
817 need_to_register_parent: bool,
818 origin: InternalString,
819 ) {
820 self.pre_txn(Default::default(), EventTriggerKind::Import);
821 if need_to_register_parent {
822 for state in self.store.iter_and_decode_all() {
823 let idx = state.container_idx();
824 let s = state;
825 for child_id in s.get_child_containers() {
826 let child_idx = self.arena.register_container(&child_id);
827 self.arena.set_parent(child_idx, Some(idx));
828 }
829 }
830 }
831
832 if !unknown_containers.is_empty() {
833 let mut diff_calc = DiffCalculator::new(false);
834 let stack_vv;
835 let vv = if oplog.frontiers() == &frontiers {
836 oplog.vv()
837 } else {
838 stack_vv = oplog.dag().frontiers_to_vv(&frontiers);
839 stack_vv.as_ref().unwrap()
840 };
841
842 let (unknown_diffs, _diff_mode) = diff_calc.calc_diff_internal(
843 oplog,
844 &Default::default(),
845 &Default::default(),
846 vv,
847 &frontiers,
848 Some(&|idx| !idx.is_unknown() && unknown_containers.contains(&idx)),
849 );
850 self.apply_diff(
851 InternalDocDiff {
852 origin: origin.clone(),
853 by: EventTriggerKind::Import,
854 diff: unknown_diffs.into(),
855 new_version: Cow::Owned(frontiers.clone()),
856 },
857 DiffMode::Checkout,
858 )
859 }
860
861 if self.is_recording() {
862 let diff: Vec<_> = self
863 .store
864 .iter_all_containers()
865 .map(|(&idx, state)| InternalContainerDiff {
866 idx,
867 bring_back: false,
868 diff: state
869 .get_state_mut(
870 idx,
871 ContainerCreationContext {
872 configure: &self.config,
873 peer: self.peer.load(Ordering::Relaxed),
874 },
875 )
876 .to_diff(&self.doc)
877 .into(),
878 diff_mode: DiffMode::Checkout,
879 })
880 .collect();
881
882 self.record_diff(InternalDocDiff {
883 origin,
884 by: EventTriggerKind::Import,
885 diff: diff.into(),
886 new_version: Cow::Borrowed(&frontiers),
887 });
888 }
889
890 self.frontiers = frontiers;
891 }
892
893 pub fn get_text<I: Into<ContainerIdRaw>>(
896 &mut self,
897 id: I,
898 ) -> Option<&mut richtext_state::RichtextState> {
899 let idx = self.id_to_idx(id, ContainerType::Text);
900 self.store
901 .get_or_create_mut(idx)
902 .as_richtext_state_mut()
903 .map(|x| &mut **x)
904 }
905
906 #[allow(unused)]
909 pub(crate) fn get_tree<I: Into<ContainerIdRaw>>(&mut self, id: I) -> Option<&mut TreeState> {
910 let idx = self.id_to_idx(id, ContainerType::Tree);
911 self.store
912 .get_or_create_mut(idx)
913 .as_tree_state_mut()
914 .map(|x| &mut **x)
915 }
916
917 fn id_to_idx<I: Into<ContainerIdRaw>>(&mut self, id: I, kind: ContainerType) -> ContainerIdx {
918 let id: ContainerIdRaw = id.into();
919 let cid;
920 let idx = match id {
921 ContainerIdRaw::Root { name } => {
922 cid = crate::container::ContainerID::Root {
923 name,
924 container_type: kind,
925 };
926 Some(self.arena.register_container(&cid))
927 }
928 ContainerIdRaw::Normal { id: _ } => {
929 cid = id.with_type(kind);
930 Some(self.arena.register_container(&cid))
932 }
933 };
934
935 idx.unwrap()
936 }
937
938 #[inline(always)]
939 #[allow(unused)]
940 pub(crate) fn with_state<F, R>(&mut self, idx: ContainerIdx, f: F) -> R
941 where
942 F: FnOnce(&State) -> R,
943 {
944 let depth = self.arena.get_depth(idx).unwrap().get() as usize;
945 let state = self.store.get_or_create_imm(idx);
946 f(state)
947 }
948
949 #[inline(always)]
950 pub(crate) fn with_state_mut<F, R>(&mut self, idx: ContainerIdx, f: F) -> R
951 where
952 F: FnOnce(&mut State) -> R,
953 {
954 let state = self.store.get_or_create_mut(idx);
955 f(state)
956 }
957
958 pub(super) fn is_in_txn(&self) -> bool {
959 self.in_txn
960 }
961
962 pub fn can_import_snapshot(&self) -> bool {
963 !self.in_txn && self.arena.can_import_snapshot() && self.store.can_import_snapshot()
964 }
965
966 pub fn get_value(&mut self) -> LoroValue {
967 let flag = self.store.load_all();
968 let roots = self.arena.root_containers(flag);
969 let ans: loro_common::LoroMapValue = roots
970 .into_iter()
971 .map(|idx| {
972 let id = self.arena.idx_to_id(idx).unwrap();
973 let ContainerID::Root {
974 name,
975 container_type: _,
976 } = &id
977 else {
978 unreachable!()
979 };
980 (name.to_string(), LoroValue::Container(id))
981 })
982 .collect();
983 LoroValue::Map(ans)
984 }
985
986 pub fn get_deep_value(&mut self) -> LoroValue {
987 let flag = self.store.load_all();
988 let roots = self.arena.root_containers(flag);
989 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
990 let binding = self.config.deleted_root_containers.clone();
991 let deleted_root_container = binding.lock().unwrap();
992 let should_hide_empty_root_container = self
993 .config
994 .hide_empty_root_containers
995 .load(Ordering::Relaxed);
996 for root_idx in roots {
997 let id = self.arena.idx_to_id(root_idx).unwrap();
998 match &id {
999 loro_common::ContainerID::Root { name, .. } => {
1000 let v = self.get_container_deep_value(root_idx);
1001 if (should_hide_empty_root_container || deleted_root_container.contains(&id))
1002 && v.is_empty_collection()
1003 {
1004 continue;
1005 }
1006
1007 ans.insert(name.to_string(), v);
1008 }
1009 loro_common::ContainerID::Normal { .. } => {
1010 unreachable!()
1011 }
1012 }
1013 }
1014
1015 LoroValue::Map(ans.into())
1016 }
1017
1018 pub fn get_deep_value_with_id(&mut self) -> LoroValue {
1019 let flag = self.store.load_all();
1020 let roots = self.arena.root_containers(flag);
1021 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
1022 for root_idx in roots {
1023 let id = self.arena.idx_to_id(root_idx).unwrap();
1024 match id.clone() {
1025 loro_common::ContainerID::Root { name, .. } => {
1026 ans.insert(
1027 name.to_string(),
1028 self.get_container_deep_value_with_id(root_idx, Some(id)),
1029 );
1030 }
1031 loro_common::ContainerID::Normal { .. } => {
1032 unreachable!()
1033 }
1034 }
1035 }
1036
1037 LoroValue::Map(ans.into())
1038 }
1039
1040 pub fn get_all_container_value_flat(&mut self) -> LoroValue {
1041 let mut map = FxHashMap::default();
1042 self.store.iter_and_decode_all().for_each(|c| {
1043 let value = c.get_value();
1044 let cid = self.arena.idx_to_id(c.container_idx()).unwrap().to_string();
1045 map.insert(cid, value);
1046 });
1047
1048 LoroValue::Map(map.into())
1049 }
1050
1051 pub(crate) fn get_container_deep_value_with_id(
1052 &mut self,
1053 container: ContainerIdx,
1054 id: Option<ContainerID>,
1055 ) -> LoroValue {
1056 let id = id.unwrap_or_else(|| self.arena.idx_to_id(container).unwrap());
1057 let Some(state) = self.store.get_container_mut(container) else {
1058 return container.get_type().default_value();
1059 };
1060 let value = state.get_value();
1061 let cid_str = LoroValue::String(format!("idx:{}, id:{}", container.to_index(), id).into());
1062 match value {
1063 LoroValue::Container(_) => unreachable!(),
1064 LoroValue::List(mut list) => {
1065 if container.get_type() == ContainerType::Tree {
1066 get_meta_value(list.make_mut(), self);
1067 } else {
1068 if list.iter().all(|x| !x.is_container()) {
1069 return LoroValue::Map(
1070 (fx_map!(
1071 "cid".into() => cid_str,
1072 "value".into() => LoroValue::List(list)
1073 ))
1074 .into(),
1075 );
1076 }
1077
1078 let list_mut = list.make_mut();
1079 for item in list_mut.iter_mut() {
1080 if item.is_container() {
1081 let container = item.as_container().unwrap();
1082 let container_idx = self.arena.register_container(container);
1083 let value = self.get_container_deep_value_with_id(
1084 container_idx,
1085 Some(container.clone()),
1086 );
1087 *item = value;
1088 }
1089 }
1090 }
1091 LoroValue::Map(
1092 (fx_map!(
1093 "cid".into() => cid_str,
1094 "value".into() => LoroValue::List(list)
1095 ))
1096 .into(),
1097 )
1098 }
1099 LoroValue::Map(mut map) => {
1100 let map_mut = map.make_mut();
1101 for (_key, value) in map_mut.iter_mut() {
1102 if value.is_container() {
1103 let container = value.as_container().unwrap();
1104 let container_idx = self.arena.register_container(container);
1105 let new_value = self.get_container_deep_value_with_id(
1106 container_idx,
1107 Some(container.clone()),
1108 );
1109 *value = new_value;
1110 }
1111 }
1112
1113 LoroValue::Map(
1114 (fx_map!(
1115 "cid".into() => cid_str,
1116 "value".into() => LoroValue::Map(map)
1117 ))
1118 .into(),
1119 )
1120 }
1121 _ => LoroValue::Map(
1122 (fx_map!(
1123 "cid".into() => cid_str,
1124 "value".into() => value
1125 ))
1126 .into(),
1127 ),
1128 }
1129 }
1130
1131 pub fn get_container_deep_value(&mut self, container: ContainerIdx) -> LoroValue {
1132 let Some(value) = self.store.get_value(container) else {
1133 return container.get_type().default_value();
1134 };
1135 match value {
1136 LoroValue::Container(_) => unreachable!(),
1137 LoroValue::List(mut list) => {
1138 if container.get_type() == ContainerType::Tree {
1139 get_meta_value(list.make_mut(), self);
1144 } else {
1145 if list.iter().all(|x| !x.is_container()) {
1146 return LoroValue::List(list);
1147 }
1148
1149 let list_mut = list.make_mut();
1150 for item in list_mut.iter_mut() {
1151 if item.is_container() {
1152 let container = item.as_container().unwrap();
1153 let container_idx = self.arena.register_container(container);
1154 let value = self.get_container_deep_value(container_idx);
1155 *item = value;
1156 }
1157 }
1158 }
1159 LoroValue::List(list)
1160 }
1161 LoroValue::Map(mut map) => {
1162 if map.iter().all(|x| !x.1.is_container()) {
1163 return LoroValue::Map(map);
1164 }
1165
1166 let map_mut = map.make_mut();
1167 for (_key, value) in map_mut.iter_mut() {
1168 if value.is_container() {
1169 let container = value.as_container().unwrap();
1170 let container_idx = self.arena.register_container(container);
1171 let new_value = self.get_container_deep_value(container_idx);
1172 *value = new_value;
1173 }
1174 }
1175 LoroValue::Map(map)
1176 }
1177 _ => value,
1178 }
1179 }
1180
1181 pub(crate) fn get_all_alive_containers(&mut self) -> FxHashSet<ContainerID> {
1182 let flag = self.store.load_all();
1183 let mut ans = FxHashSet::default();
1184 let mut to_visit = self
1185 .arena
1186 .root_containers(flag)
1187 .iter()
1188 .map(|x| self.arena.get_container_id(*x).unwrap())
1189 .collect_vec();
1190
1191 while let Some(id) = to_visit.pop() {
1192 self.get_alive_children_of(&id, &mut to_visit);
1193 ans.insert(id);
1194 }
1195
1196 ans
1197 }
1198
1199 pub(crate) fn get_alive_children_of(&mut self, id: &ContainerID, ans: &mut Vec<ContainerID>) {
1200 let idx = self.arena.register_container(id);
1201 let Some(value) = self.store.get_value(idx) else {
1202 return;
1203 };
1204
1205 match value {
1206 LoroValue::Container(_) => unreachable!(),
1207 LoroValue::List(list) => {
1208 if idx.get_type() == ContainerType::Tree {
1209 let mut list = list.unwrap();
1214 while let Some(node) = list.pop() {
1215 let map = node.as_map().unwrap();
1216 let meta = map.get("meta").unwrap();
1217 let id = meta.as_container().unwrap();
1218 ans.push(id.clone());
1219 let children = map.get("children").unwrap();
1220 let children = children.as_list().unwrap();
1221 for child in children.iter() {
1222 list.push(child.clone());
1223 }
1224 }
1225 } else {
1226 for item in list.iter() {
1227 if let LoroValue::Container(id) = item {
1228 ans.push(id.clone());
1229 }
1230 }
1231 }
1232 }
1233 LoroValue::Map(map) => {
1234 for (_key, value) in map.iter() {
1235 if let LoroValue::Container(id) = value {
1236 ans.push(id.clone());
1237 }
1238 }
1239 }
1240 _ => {}
1241 }
1242 }
1243
1244 fn diffs_to_event(&mut self, diffs: Vec<InternalDocDiff<'_>>, from: Frontiers) -> DocDiff {
1247 if diffs.is_empty() {
1248 panic!("diffs is empty");
1249 }
1250
1251 let triggered_by = diffs[0].by;
1252 debug_assert!(diffs.iter().all(|x| x.by == triggered_by));
1253 let mut containers = FxHashMap::default();
1254 let to = (*diffs.last().unwrap().new_version).to_owned();
1255 let origin = diffs[0].origin.clone();
1256 for diff in diffs {
1257 #[allow(clippy::unnecessary_to_owned)]
1258 for container_diff in diff.diff.into_owned() {
1259 let Some((last_container_diff, _)) = containers.get_mut(&container_diff.idx) else {
1260 if let Some(path) = self.get_path(container_diff.idx) {
1261 containers.insert(container_diff.idx, (container_diff.diff, path));
1262 } else {
1263 loro_common::warn!(
1266 "⚠️ WARNING: ignore event because cannot find its path {:#?} container id:{}",
1267 &container_diff,
1268 self.arena.idx_to_id(container_diff.idx).unwrap()
1269 );
1270 }
1271
1272 continue;
1273 };
1274 *last_container_diff = last_container_diff
1276 .clone()
1277 .compose(container_diff.diff)
1278 .unwrap();
1279 }
1280 }
1281 let mut diff: Vec<_> = containers
1282 .into_iter()
1283 .map(|(container, (diff, path))| {
1284 let idx = container;
1285 let id = self.arena.get_container_id(idx).unwrap();
1286 let is_unknown = id.is_unknown();
1287
1288 ContainerDiff {
1289 id,
1290 idx,
1291 diff: diff.into_external().unwrap(),
1292 is_unknown,
1293 path,
1294 }
1295 })
1296 .collect();
1297
1298 diff.sort_by_key(|x| {
1302 (
1303 x.path.len(),
1304 match &x.id {
1305 ContainerID::Root { .. } => 0,
1306 ContainerID::Normal { counter, .. } => *counter + 1,
1307 },
1308 )
1309 });
1310 DocDiff {
1311 from,
1312 to,
1313 origin,
1314 by: triggered_by,
1315 diff,
1316 }
1317 }
1318
1319 pub(crate) fn get_reachable(&mut self, id: &ContainerID) -> bool {
1320 if matches!(id, ContainerID::Root { .. }) {
1321 return true;
1322 }
1323
1324 if self.arena.id_to_idx(id).is_none() {
1326 if !self.does_container_exist(id) {
1327 return false;
1328 }
1329 self.arena.register_container(id);
1331 }
1332
1333 let mut idx = self.arena.id_to_idx(id).unwrap();
1334 loop {
1335 let id = self.arena.idx_to_id(idx).unwrap();
1336 if let Some(parent_idx) = self.arena.get_parent(idx) {
1337 let Some(parent_state) = self.store.get_container_mut(parent_idx) else {
1338 return false;
1339 };
1340 if !parent_state.contains_child(&id) {
1341 return false;
1342 }
1343 idx = parent_idx;
1344 } else {
1345 if id.is_root() {
1346 return true;
1347 }
1348
1349 return false;
1350 }
1351 }
1352 }
1353
1354 pub(super) fn get_path(&mut self, idx: ContainerIdx) -> Option<Vec<(ContainerID, Index)>> {
1356 let mut ans = Vec::new();
1357 let mut idx = idx;
1358 loop {
1359 let id = self.arena.idx_to_id(idx).unwrap();
1360 if let Some(parent_idx) = self.arena.get_parent(idx) {
1361 let parent_state = self.store.get_container_mut(parent_idx)?;
1362 let Some(prop) = parent_state.get_child_index(&id) else {
1363 tracing::warn!("Missing in parent's children");
1364 return None;
1365 };
1366 ans.push((id, prop));
1367 idx = parent_idx;
1368 } else {
1369 let Ok(prop) = id.clone().into_root() else {
1371 let id = format!("{}", &id);
1372 tracing::info!(?id, "Missing parent - container is deleted");
1373 return None;
1374 };
1375 ans.push((id, Index::Key(prop.0)));
1376 break;
1377 }
1378 }
1379
1380 ans.reverse();
1381
1382 Some(ans)
1383 }
1384
1385 pub(crate) fn check_before_decode_snapshot(&self) -> LoroResult<()> {
1386 if self.is_in_txn() {
1387 return Err(LoroError::DecodeError(
1388 "State is in txn".to_string().into_boxed_str(),
1389 ));
1390 }
1391
1392 if !self.can_import_snapshot() {
1393 return Err(LoroError::DecodeError(
1394 "State is not empty, cannot import snapshot directly"
1395 .to_string()
1396 .into_boxed_str(),
1397 ));
1398 }
1399
1400 Ok(())
1401 }
1402
1403 pub(crate) fn check_is_the_same(&mut self, other: &mut Self) {
1410 fn get_entries_for_state(
1411 arena: &SharedArena,
1412 state: &mut State,
1413 ) -> Option<(ContainerID, (ContainerIdx, LoroValue))> {
1414 if state.is_state_empty() {
1415 return None;
1416 }
1417
1418 let id = arena.idx_to_id(state.container_idx()).unwrap();
1419 let value = match state {
1420 State::RichtextState(s) => s.get_richtext_value(),
1421 _ => state.get_value(),
1422 };
1423 if match &value {
1424 LoroValue::List(l) => l.is_empty(),
1425 LoroValue::Map(m) => m.is_empty(),
1426 _ => false,
1427 } {
1428 return None;
1429 }
1430 #[cfg(feature = "counter")]
1431 if id.container_type() == ContainerType::Counter {
1432 if let LoroValue::Double(c) = value {
1433 if c.abs() < f64::EPSILON {
1434 return None;
1435 }
1436 }
1437 }
1438
1439 Some((id, (state.container_idx(), value)))
1440 }
1441
1442 let self_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = self
1443 .store
1444 .iter_and_decode_all()
1445 .filter_map(|state: &mut State| {
1446 let arena = &self.arena;
1447 get_entries_for_state(arena, state)
1448 })
1449 .collect();
1450 let mut other_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = other
1451 .store
1452 .iter_and_decode_all()
1453 .filter_map(|state: &mut State| {
1454 let arena = &other.arena;
1455 get_entries_for_state(arena, state)
1456 })
1457 .collect();
1458 for (id, (idx, this_value)) in self_id_to_states {
1459 let (_, other_value) = match other_id_to_states.remove(&id) {
1460 Some(x) => x,
1461 None => {
1462 panic!(
1463 "id: {:?}, path: {:?} is missing, value={:?}",
1464 id,
1465 self.get_path(idx),
1466 &this_value
1467 );
1468 }
1469 };
1470
1471 pretty_assertions::assert_eq!(
1472 this_value,
1473 other_value,
1474 "[self!=other] id: {:?}, path: {:?}",
1475 id,
1476 self.get_path(idx)
1477 );
1478 }
1479
1480 if !other_id_to_states.is_empty() {
1481 panic!("other has more states {:#?}", &other_id_to_states);
1482 }
1483 }
1484
1485 pub fn create_state(&self, idx: ContainerIdx) -> State {
1486 let config = &self.config;
1487 let peer = self.peer.load(std::sync::atomic::Ordering::Relaxed);
1488 create_state_(idx, config, peer)
1489 }
1490
1491 pub fn create_unknown_state(&self, idx: ContainerIdx) -> State {
1492 State::UnknownState(UnknownState::new(idx))
1493 }
1494
1495 pub fn get_relative_position(&mut self, pos: &Cursor, use_event_index: bool) -> Option<usize> {
1496 let idx = self.arena.register_container(&pos.container);
1497 let state = self.store.get_container_mut(idx)?;
1498 if let Some(id) = pos.id {
1499 match state {
1500 State::ListState(s) => s.get_index_of_id(id),
1501 State::RichtextState(s) => s.get_text_index_of_id(id, use_event_index),
1502 State::MovableListState(s) => s.get_index_of_id(id),
1503 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
1504 #[cfg(feature = "counter")]
1505 State::CounterState(_) => unreachable!(),
1506 }
1507 } else {
1508 if matches!(pos.side, crate::cursor::Side::Left) {
1509 return Some(0);
1510 }
1511
1512 match state {
1513 State::ListState(s) => Some(s.len()),
1514 State::RichtextState(s) => Some(if use_event_index {
1515 s.len_event()
1516 } else {
1517 s.len_unicode()
1518 }),
1519 State::MovableListState(s) => Some(s.len()),
1520 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
1521 #[cfg(feature = "counter")]
1522 State::CounterState(_) => unreachable!(),
1523 }
1524 }
1525 }
1526
1527 pub fn get_value_by_path(&mut self, path: &[Index]) -> Option<LoroValue> {
1528 if path.is_empty() {
1529 return None;
1530 }
1531
1532 enum CurContainer {
1533 Container(ContainerIdx),
1534 TreeNode {
1535 tree: ContainerIdx,
1536 node: Option<TreeID>,
1537 },
1538 }
1539
1540 let mut state_idx = {
1541 let root_index = path[0].as_key()?;
1542 CurContainer::Container(self.arena.get_root_container_idx_by_key(root_index)?)
1543 };
1544
1545 if path.len() == 1 {
1546 if let CurContainer::Container(c) = state_idx {
1547 let cid = self.arena.idx_to_id(c)?;
1548 return Some(LoroValue::Container(cid));
1549 }
1550 }
1551
1552 let mut i = 1;
1553 while i < path.len() - 1 {
1554 let index = &path[i];
1555 match state_idx {
1556 CurContainer::Container(idx) => {
1557 let parent_state = self.store.get_container_mut(idx)?;
1558 match parent_state {
1559 State::ListState(l) => {
1560 let Some(LoroValue::Container(c)) = l.get(*index.as_seq()?) else {
1561 return None;
1562 };
1563 state_idx = CurContainer::Container(self.arena.register_container(c));
1564 }
1565 State::MovableListState(l) => {
1566 let Some(LoroValue::Container(c)) =
1567 l.get(*index.as_seq()?, IndexType::ForUser)
1568 else {
1569 return None;
1570 };
1571 state_idx = CurContainer::Container(self.arena.register_container(c));
1572 }
1573 State::MapState(m) => {
1574 let Some(LoroValue::Container(c)) = m.get(index.as_key()?) else {
1575 return None;
1576 };
1577 state_idx = CurContainer::Container(self.arena.register_container(c));
1578 }
1579 State::RichtextState(_) => return None,
1580 State::TreeState(_) => {
1581 state_idx = CurContainer::TreeNode {
1582 tree: idx,
1583 node: None,
1584 };
1585 continue;
1586 }
1587 #[cfg(feature = "counter")]
1588 State::CounterState(_) => return None,
1589 State::UnknownState(_) => unreachable!(),
1590 }
1591 }
1592 CurContainer::TreeNode { tree, node } => match index {
1593 Index::Key(internal_string) => {
1594 let node = node?;
1595 let idx = self
1596 .arena
1597 .register_container(&node.associated_meta_container());
1598 let map = self.store.get_container(idx)?;
1599 let Some(LoroValue::Container(c)) =
1600 map.as_map_state().unwrap().get(internal_string)
1601 else {
1602 return None;
1603 };
1604
1605 state_idx = CurContainer::Container(self.arena.register_container(c));
1606 }
1607 Index::Seq(i) => {
1608 let tree_state =
1609 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1610 let parent: TreeParentId = if let Some(node) = node {
1611 node.into()
1612 } else {
1613 TreeParentId::Root
1614 };
1615 let child = tree_state.get_children(&parent)?.nth(*i)?;
1616 state_idx = CurContainer::TreeNode {
1617 tree,
1618 node: Some(child),
1619 };
1620 }
1621 Index::Node(tree_id) => {
1622 let tree_state =
1623 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1624 if tree_state.parent(tree_id).is_some() {
1625 state_idx = CurContainer::TreeNode {
1626 tree,
1627 node: Some(*tree_id),
1628 }
1629 } else {
1630 return None;
1631 }
1632 }
1633 },
1634 }
1635 i += 1;
1636 }
1637
1638 let parent_idx = match state_idx {
1639 CurContainer::Container(container_idx) => container_idx,
1640 CurContainer::TreeNode { tree, node } => {
1641 if let Some(node) = node {
1642 self.arena
1643 .register_container(&node.associated_meta_container())
1644 } else {
1645 tree
1646 }
1647 }
1648 };
1649
1650 let parent_state = self.store.get_or_create_mut(parent_idx);
1651 let index = path.last().unwrap();
1652 let value: LoroValue = match parent_state {
1653 State::ListState(l) => l.get(*index.as_seq()?).cloned()?,
1654 State::MovableListState(l) => l.get(*index.as_seq()?, IndexType::ForUser).cloned()?,
1655 State::MapState(m) => {
1656 if let Some(key) = index.as_key() {
1657 m.get(key).cloned()?
1658 } else if let CurContainer::TreeNode { tree, node } = state_idx {
1659 match index {
1660 Index::Seq(index) => {
1661 let tree_state =
1662 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1663 let parent: TreeParentId = if let Some(node) = node {
1664 node.into()
1665 } else {
1666 TreeParentId::Root
1667 };
1668 let child = tree_state.get_children(&parent)?.nth(*index)?;
1669 child.associated_meta_container().into()
1670 }
1671 Index::Node(id) => id.associated_meta_container().into(),
1672 _ => return None,
1673 }
1674 } else {
1675 return None;
1676 }
1677 }
1678 State::RichtextState(s) => {
1679 let s = s.to_string_mut();
1680 s.chars()
1681 .nth(*index.as_seq()?)
1682 .map(|c| c.to_string().into())?
1683 }
1684 State::TreeState(_) => {
1685 let id = index.as_node()?;
1686 let cid = id.associated_meta_container();
1687 cid.into()
1688 }
1689 #[cfg(feature = "counter")]
1690 State::CounterState(_) => unreachable!(),
1691 State::UnknownState(_) => unreachable!(),
1692 };
1693
1694 Some(value)
1695 }
1696
1697 pub(crate) fn shallow_root_store(&self) -> Option<&Arc<GcStore>> {
1698 self.store.shallow_root_store()
1699 }
1700}
1701
1702fn create_state_(idx: ContainerIdx, config: &Configure, peer: u64) -> State {
1703 match idx.get_type() {
1704 ContainerType::Map => State::MapState(Box::new(MapState::new(idx))),
1705 ContainerType::List => State::ListState(Box::new(ListState::new(idx))),
1706 ContainerType::Text => State::RichtextState(Box::new(RichtextState::new(
1707 idx,
1708 config.text_style_config.clone(),
1709 ))),
1710 ContainerType::Tree => State::TreeState(Box::new(TreeState::new(idx, peer))),
1711 ContainerType::MovableList => State::MovableListState(Box::new(MovableListState::new(idx))),
1712 #[cfg(feature = "counter")]
1713 ContainerType::Counter => {
1714 State::CounterState(Box::new(counter_state::CounterState::new(idx)))
1715 }
1716 ContainerType::Unknown(_) => State::UnknownState(UnknownState::new(idx)),
1717 }
1718}
1719
1720fn trigger_on_new_container(
1721 state_diff: &Diff,
1722 mut listener: impl FnMut(ContainerIdx),
1723 arena: &SharedArena,
1724) {
1725 match state_diff {
1726 Diff::List(list) => {
1727 for delta in list.iter() {
1728 if let DeltaItem::Replace {
1729 value,
1730 attr,
1731 delete: _,
1732 } = delta
1733 {
1734 if attr.from_move {
1735 continue;
1736 }
1737
1738 for v in value.iter() {
1739 if let ValueOrHandler::Handler(h) = v {
1740 let idx = h.container_idx();
1741 listener(idx);
1742 }
1743 }
1744 }
1745 }
1746 }
1747 Diff::Map(map) => {
1748 for (_, v) in map.updated.iter() {
1749 if let Some(ValueOrHandler::Handler(h)) = &v.value {
1750 let idx = h.container_idx();
1751 listener(idx);
1752 }
1753 }
1754 }
1755 Diff::Tree(tree) => {
1756 for item in tree.iter() {
1757 if matches!(item.action, TreeExternalDiff::Create { .. }) {
1758 let id = item.target.associated_meta_container();
1759 listener(arena.register_container(&id));
1761 }
1762 }
1763 }
1764 _ => {}
1765 };
1766}
1767
1768#[derive(Default, Clone)]
1769struct EventRecorder {
1770 recording_diff: bool,
1771 diffs: Vec<InternalDocDiff<'static>>,
1774 events: Vec<DocDiff>,
1775 diff_start_version: Option<Frontiers>,
1776}
1777
1778impl EventRecorder {
1779 #[allow(unused)]
1780 pub fn new() -> Self {
1781 Self::default()
1782 }
1783}
1784
1785#[test]
1786fn test_size() {
1787 println!("Size of State = {}", std::mem::size_of::<State>());
1788 println!("Size of MapState = {}", std::mem::size_of::<MapState>());
1789 println!("Size of ListState = {}", std::mem::size_of::<ListState>());
1790 println!(
1791 "Size of TextState = {}",
1792 std::mem::size_of::<RichtextState>()
1793 );
1794 println!("Size of TreeState = {}", std::mem::size_of::<TreeState>());
1795}