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 fxhash::{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 is_container_deleted: false,
588 diff: external_diff.into(),
589 diff_mode: DiffMode::Checkout,
590 });
591 }
592
593 last_depth += 1;
594 }
595
596 let idx = diff.idx;
597 let internal_diff = std::mem::take(&mut diff.diff);
598 match &internal_diff {
599 crate::event::DiffVariant::None => {
600 if is_recording {
601 let state = self.store.get_or_create_mut(diff.idx);
602 let extern_diff = state.to_diff(&self.doc);
603 trigger_on_new_container(
604 &extern_diff,
605 |cid| {
606 to_revive_in_next_layer.insert(cid);
607 },
608 &self.arena,
609 );
610 diff.diff = extern_diff.into();
611 }
612 }
613 crate::event::DiffVariant::Internal(_) => {
614 let cid = self.arena.idx_to_id(idx).unwrap();
615 info_span!("apply diff on", container_id = ?cid).in_scope(|| {
616 if self.in_txn {
617 self.changed_idx_in_txn.insert(idx);
618 }
619 let state = self.store.get_or_create_mut(idx);
620 if is_recording {
621 let external_diff =
623 if diff.bring_back || to_revive_in_this_layer.contains(&idx) {
624 state.apply_diff(
625 internal_diff.into_internal().unwrap(),
626 DiffApplyContext {
627 mode: diff.diff_mode,
628 doc: &self.doc,
629 },
630 );
631 state.to_diff(&self.doc)
632 } else {
633 state.apply_diff_and_convert(
634 internal_diff.into_internal().unwrap(),
635 DiffApplyContext {
636 mode: diff.diff_mode,
637 doc: &self.doc,
638 },
639 )
640 };
641 trigger_on_new_container(
642 &external_diff,
643 |cid| {
644 to_revive_in_next_layer.insert(cid);
645 },
646 &self.arena,
647 );
648 diff.diff = external_diff.into();
649 } else {
650 state.apply_diff(
651 internal_diff.into_internal().unwrap(),
652 DiffApplyContext {
653 mode: diff.diff_mode,
654 doc: &self.doc,
655 },
656 );
657 }
658 });
659 }
660 crate::event::DiffVariant::External(_) => unreachable!(),
661 }
662
663 to_revive_in_this_layer.remove(&idx);
664 if !diff.diff.is_empty() {
665 diffs.push(diff);
666 }
667 }
668
669 while !to_revive_in_this_layer.is_empty() || !to_revive_in_next_layer.is_empty() {
671 let to_create = std::mem::take(&mut to_revive_in_this_layer);
672 for new in to_create {
673 let state = self.store.get_or_create_mut(new);
674 if state.is_state_empty() {
675 continue;
676 }
677
678 let external_diff = state.to_diff(&self.doc);
679 trigger_on_new_container(
680 &external_diff,
681 |cid| {
682 to_revive_in_next_layer.insert(cid);
683 },
684 &self.arena,
685 );
686
687 if !external_diff.is_empty() {
688 diffs.push(InternalContainerDiff {
689 idx: new,
690 bring_back: true,
691 is_container_deleted: false,
692 diff: external_diff.into(),
693 diff_mode: DiffMode::Checkout,
694 });
695 }
696 }
697
698 to_revive_in_this_layer = std::mem::take(&mut to_revive_in_next_layer);
699 }
700
701 diff.diff = diffs.into();
702 self.frontiers = diff.new_version.clone().into_owned();
703 if self.is_recording() {
704 self.record_diff(diff)
705 }
706 }
707
708 pub fn apply_local_op(&mut self, raw_op: &RawOp, op: &Op) -> LoroResult<()> {
709 self.set_container_parent_by_raw_op(raw_op);
711 let state = self.store.get_or_create_mut(op.container);
712 if self.in_txn {
713 self.changed_idx_in_txn.insert(op.container);
714 }
715 let ret = state.apply_local_op(raw_op, op)?;
716 if !ret.deleted_containers.is_empty() {
717 self.dead_containers_cache.clear_alive();
718 }
719
720 Ok(())
721 }
722
723 pub(crate) fn start_txn(&mut self, origin: InternalString, trigger: EventTriggerKind) {
724 self.pre_txn(origin, trigger);
725 self.in_txn = true;
726 }
727
728 pub(crate) fn abort_txn(&mut self) {
729 self.in_txn = false;
730 }
731
732 pub fn iter_and_decode_all(&mut self) -> impl Iterator<Item = &mut State> {
733 self.store.iter_and_decode_all()
734 }
735
736 pub(crate) fn iter_all_containers_mut(
737 &mut self,
738 ) -> impl Iterator<Item = (&ContainerIdx, &mut ContainerWrapper)> {
739 self.store.iter_all_containers()
740 }
741
742 pub fn does_container_exist(&self, id: &ContainerID) -> bool {
743 self.arena.id_to_idx(id).is_some()
745 }
746
747 pub(crate) fn init_container(
748 &mut self,
749 cid: ContainerID,
750 decode_ctx: StateSnapshotDecodeContext,
751 ) -> LoroResult<()> {
752 let idx = self.arena.register_container(&cid);
753 let state = self.store.get_or_create_mut(idx);
754 state.import_from_snapshot_ops(decode_ctx)
755 }
756
757 pub(crate) fn init_unknown_container(&mut self, cid: ContainerID) {
758 let idx = self.arena.register_container(&cid);
759 self.store.get_or_create_imm(idx);
760 }
761
762 pub(crate) fn commit_txn(&mut self, new_frontiers: Frontiers, diff: Option<InternalDocDiff>) {
763 self.in_txn = false;
764 self.frontiers = new_frontiers;
765 if self.is_recording() {
766 self.record_diff(diff.unwrap());
767 }
768 }
769
770 #[inline]
771 pub(super) fn get_container_mut(&mut self, idx: ContainerIdx) -> Option<&mut State> {
772 self.store.get_container_mut(idx)
773 }
774
775 #[inline]
777 pub(crate) fn ensure_container(&mut self, id: &ContainerID) {
778 self.store.ensure_container(id);
779 }
780
781 pub(crate) fn ensure_all_alive_containers(&mut self) -> FxHashSet<ContainerID> {
783 let ans = self.get_all_alive_containers();
786 for id in ans.iter() {
787 self.ensure_container(id);
788 }
789
790 ans
791 }
792
793 pub(crate) fn get_value_by_idx(&mut self, container_idx: ContainerIdx) -> LoroValue {
794 tracing::trace!("get_value_by_idx");
795 let v = self
796 .store
797 .get_value(container_idx)
798 .unwrap_or_else(|| container_idx.get_type().default_value());
799 tracing::trace!("get_value_by_idx: {:?}", v);
800 v
801 }
802
803 pub(super) fn init_with_states_and_version(
810 &mut self,
811 frontiers: Frontiers,
812 oplog: &OpLog,
813 unknown_containers: Vec<ContainerIdx>,
814 need_to_register_parent: bool,
815 ) {
816 self.pre_txn(Default::default(), EventTriggerKind::Import);
817 if need_to_register_parent {
818 for state in self.store.iter_and_decode_all() {
819 let idx = state.container_idx();
820 let s = state;
821 for child_id in s.get_child_containers() {
822 let child_idx = self.arena.register_container(&child_id);
823 self.arena.set_parent(child_idx, Some(idx));
824 }
825 }
826 }
827
828 if !unknown_containers.is_empty() {
829 let mut diff_calc = DiffCalculator::new(false);
830 let stack_vv;
831 let vv = if oplog.frontiers() == &frontiers {
832 oplog.vv()
833 } else {
834 stack_vv = oplog.dag().frontiers_to_vv(&frontiers);
835 stack_vv.as_ref().unwrap()
836 };
837
838 let (unknown_diffs, _diff_mode) = diff_calc.calc_diff_internal(
839 oplog,
840 &Default::default(),
841 &Default::default(),
842 vv,
843 &frontiers,
844 Some(&|idx| !idx.is_unknown() && unknown_containers.contains(&idx)),
845 );
846 self.apply_diff(
847 InternalDocDiff {
848 origin: Default::default(),
849 by: EventTriggerKind::Import,
850 diff: unknown_diffs.into(),
851 new_version: Cow::Owned(frontiers.clone()),
852 },
853 DiffMode::Checkout,
854 )
855 }
856
857 if self.is_recording() {
858 let diff: Vec<_> = self
859 .store
860 .iter_all_containers()
861 .map(|(&idx, state)| InternalContainerDiff {
862 idx,
863 bring_back: false,
864 is_container_deleted: false,
865 diff: state
866 .get_state_mut(
867 idx,
868 ContainerCreationContext {
869 configure: &self.config,
870 peer: self.peer.load(Ordering::Relaxed),
871 },
872 )
873 .to_diff(&self.doc)
874 .into(),
875 diff_mode: DiffMode::Checkout,
876 })
877 .collect();
878
879 self.record_diff(InternalDocDiff {
880 origin: Default::default(),
881 by: EventTriggerKind::Import,
882 diff: diff.into(),
883 new_version: Cow::Borrowed(&frontiers),
884 });
885 }
886
887 self.frontiers = frontiers;
888 }
889
890 pub fn get_text<I: Into<ContainerIdRaw>>(
893 &mut self,
894 id: I,
895 ) -> Option<&mut richtext_state::RichtextState> {
896 let idx = self.id_to_idx(id, ContainerType::Text);
897 self.store
898 .get_or_create_mut(idx)
899 .as_richtext_state_mut()
900 .map(|x| &mut **x)
901 }
902
903 #[allow(unused)]
906 pub(crate) fn get_tree<I: Into<ContainerIdRaw>>(&mut self, id: I) -> Option<&mut TreeState> {
907 let idx = self.id_to_idx(id, ContainerType::Tree);
908 self.store
909 .get_or_create_mut(idx)
910 .as_tree_state_mut()
911 .map(|x| &mut **x)
912 }
913
914 fn id_to_idx<I: Into<ContainerIdRaw>>(&mut self, id: I, kind: ContainerType) -> ContainerIdx {
915 let id: ContainerIdRaw = id.into();
916 let cid;
917 let idx = match id {
918 ContainerIdRaw::Root { name } => {
919 cid = crate::container::ContainerID::Root {
920 name,
921 container_type: kind,
922 };
923 Some(self.arena.register_container(&cid))
924 }
925 ContainerIdRaw::Normal { id: _ } => {
926 cid = id.with_type(kind);
927 self.arena.id_to_idx(&cid)
928 }
929 };
930
931 idx.unwrap()
932 }
933
934 #[inline(always)]
935 #[allow(unused)]
936 pub(crate) fn with_state<F, R>(&mut self, idx: ContainerIdx, f: F) -> R
937 where
938 F: FnOnce(&State) -> R,
939 {
940 let depth = self.arena.get_depth(idx).unwrap().get() as usize;
941 let state = self.store.get_or_create_imm(idx);
942 f(state)
943 }
944
945 #[inline(always)]
946 pub(crate) fn with_state_mut<F, R>(&mut self, idx: ContainerIdx, f: F) -> R
947 where
948 F: FnOnce(&mut State) -> R,
949 {
950 let state = self.store.get_or_create_mut(idx);
951 f(state)
952 }
953
954 pub(super) fn is_in_txn(&self) -> bool {
955 self.in_txn
956 }
957
958 pub fn can_import_snapshot(&self) -> bool {
959 !self.in_txn && self.arena.can_import_snapshot() && self.store.can_import_snapshot()
960 }
961
962 pub fn get_value(&self) -> LoroValue {
963 let roots = self.arena.root_containers();
964 let ans: loro_common::LoroMapValue = roots
965 .into_iter()
966 .map(|idx| {
967 let id = self.arena.idx_to_id(idx).unwrap();
968 let ContainerID::Root {
969 name,
970 container_type: _,
971 } = &id
972 else {
973 unreachable!()
974 };
975 (name.to_string(), LoroValue::Container(id))
976 })
977 .collect();
978 LoroValue::Map(ans)
979 }
980
981 pub fn get_deep_value(&mut self) -> LoroValue {
982 let roots = self.arena.root_containers();
983 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
984 for root_idx in roots {
985 let id = self.arena.idx_to_id(root_idx).unwrap();
986 match id {
987 loro_common::ContainerID::Root { name, .. } => {
988 ans.insert(name.to_string(), self.get_container_deep_value(root_idx));
989 }
990 loro_common::ContainerID::Normal { .. } => {
991 unreachable!()
992 }
993 }
994 }
995
996 LoroValue::Map(ans.into())
997 }
998
999 pub fn get_deep_value_with_id(&mut self) -> LoroValue {
1000 let roots = self.arena.root_containers();
1001 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
1002 for root_idx in roots {
1003 let id = self.arena.idx_to_id(root_idx).unwrap();
1004 match id.clone() {
1005 loro_common::ContainerID::Root { name, .. } => {
1006 ans.insert(
1007 name.to_string(),
1008 self.get_container_deep_value_with_id(root_idx, Some(id)),
1009 );
1010 }
1011 loro_common::ContainerID::Normal { .. } => {
1012 unreachable!()
1013 }
1014 }
1015 }
1016
1017 LoroValue::Map(ans.into())
1018 }
1019
1020 pub fn get_all_container_value_flat(&mut self) -> LoroValue {
1021 let mut map = FxHashMap::default();
1022 self.store.iter_and_decode_all().for_each(|c| {
1023 let value = c.get_value();
1024 let cid = self.arena.idx_to_id(c.container_idx()).unwrap().to_string();
1025 map.insert(cid, value);
1026 });
1027
1028 LoroValue::Map(map.into())
1029 }
1030
1031 pub(crate) fn get_container_deep_value_with_id(
1032 &mut self,
1033 container: ContainerIdx,
1034 id: Option<ContainerID>,
1035 ) -> LoroValue {
1036 let id = id.unwrap_or_else(|| self.arena.idx_to_id(container).unwrap());
1037 let Some(state) = self.store.get_container_mut(container) else {
1038 return container.get_type().default_value();
1039 };
1040 let value = state.get_value();
1041 let cid_str = LoroValue::String(format!("idx:{}, id:{}", container.to_index(), id).into());
1042 match value {
1043 LoroValue::Container(_) => unreachable!(),
1044 LoroValue::List(mut list) => {
1045 if container.get_type() == ContainerType::Tree {
1046 get_meta_value(list.make_mut(), self);
1047 } else {
1048 if list.iter().all(|x| !x.is_container()) {
1049 return LoroValue::Map(
1050 (fx_map!(
1051 "cid".into() => cid_str,
1052 "value".into() => LoroValue::List(list)
1053 ))
1054 .into(),
1055 );
1056 }
1057
1058 let list_mut = list.make_mut();
1059 for item in list_mut.iter_mut() {
1060 if item.is_container() {
1061 let container = item.as_container().unwrap();
1062 let container_idx = self.arena.register_container(container);
1063 let value = self.get_container_deep_value_with_id(
1064 container_idx,
1065 Some(container.clone()),
1066 );
1067 *item = value;
1068 }
1069 }
1070 }
1071 LoroValue::Map(
1072 (fx_map!(
1073 "cid".into() => cid_str,
1074 "value".into() => LoroValue::List(list)
1075 ))
1076 .into(),
1077 )
1078 }
1079 LoroValue::Map(mut map) => {
1080 let map_mut = map.make_mut();
1081 for (_key, value) in map_mut.iter_mut() {
1082 if value.is_container() {
1083 let container = value.as_container().unwrap();
1084 let container_idx = self.arena.register_container(container);
1085 let new_value = self.get_container_deep_value_with_id(
1086 container_idx,
1087 Some(container.clone()),
1088 );
1089 *value = new_value;
1090 }
1091 }
1092
1093 LoroValue::Map(
1094 (fx_map!(
1095 "cid".into() => cid_str,
1096 "value".into() => LoroValue::Map(map)
1097 ))
1098 .into(),
1099 )
1100 }
1101 _ => LoroValue::Map(
1102 (fx_map!(
1103 "cid".into() => cid_str,
1104 "value".into() => value
1105 ))
1106 .into(),
1107 ),
1108 }
1109 }
1110
1111 pub fn get_container_deep_value(&mut self, container: ContainerIdx) -> LoroValue {
1112 let Some(value) = self.store.get_value(container) else {
1113 return container.get_type().default_value();
1114 };
1115 match value {
1116 LoroValue::Container(_) => unreachable!(),
1117 LoroValue::List(mut list) => {
1118 if container.get_type() == ContainerType::Tree {
1119 get_meta_value(list.make_mut(), self);
1124 } else {
1125 if list.iter().all(|x| !x.is_container()) {
1126 return LoroValue::List(list);
1127 }
1128
1129 let list_mut = list.make_mut();
1130 for item in list_mut.iter_mut() {
1131 if item.is_container() {
1132 let container = item.as_container().unwrap();
1133 let container_idx = self.arena.register_container(container);
1134 let value = self.get_container_deep_value(container_idx);
1135 *item = value;
1136 }
1137 }
1138 }
1139 LoroValue::List(list)
1140 }
1141 LoroValue::Map(mut map) => {
1142 if map.iter().all(|x| !x.1.is_container()) {
1143 return LoroValue::Map(map);
1144 }
1145
1146 let map_mut = map.make_mut();
1147 for (_key, value) in map_mut.iter_mut() {
1148 if value.is_container() {
1149 let container = value.as_container().unwrap();
1150 let container_idx = self.arena.register_container(container);
1151 let new_value = self.get_container_deep_value(container_idx);
1152 *value = new_value;
1153 }
1154 }
1155 LoroValue::Map(map)
1156 }
1157 _ => value,
1158 }
1159 }
1160
1161 pub(crate) fn get_all_alive_containers(&mut self) -> FxHashSet<ContainerID> {
1162 let mut ans = FxHashSet::default();
1163 let mut to_visit = self
1164 .arena
1165 .root_containers()
1166 .iter()
1167 .map(|x| self.arena.get_container_id(*x).unwrap())
1168 .collect_vec();
1169
1170 while let Some(id) = to_visit.pop() {
1171 self.get_alive_children_of(&id, &mut to_visit);
1172 ans.insert(id);
1173 }
1174
1175 ans
1176 }
1177
1178 pub(crate) fn get_alive_children_of(&mut self, id: &ContainerID, ans: &mut Vec<ContainerID>) {
1179 let idx = self.arena.register_container(id);
1180 let Some(value) = self.store.get_value(idx) else {
1181 return;
1182 };
1183
1184 match value {
1185 LoroValue::Container(_) => unreachable!(),
1186 LoroValue::List(list) => {
1187 if idx.get_type() == ContainerType::Tree {
1188 let mut list = list.unwrap();
1193 while let Some(node) = list.pop() {
1194 let map = node.as_map().unwrap();
1195 let meta = map.get("meta").unwrap();
1196 let id = meta.as_container().unwrap();
1197 ans.push(id.clone());
1198 let children = map.get("children").unwrap();
1199 let children = children.as_list().unwrap();
1200 for child in children.iter() {
1201 list.push(child.clone());
1202 }
1203 }
1204 } else {
1205 for item in list.iter() {
1206 if let LoroValue::Container(id) = item {
1207 ans.push(id.clone());
1208 }
1209 }
1210 }
1211 }
1212 LoroValue::Map(map) => {
1213 for (_key, value) in map.iter() {
1214 if let LoroValue::Container(id) = value {
1215 ans.push(id.clone());
1216 }
1217 }
1218 }
1219 _ => {}
1220 }
1221 }
1222
1223 fn diffs_to_event(&mut self, diffs: Vec<InternalDocDiff<'_>>, from: Frontiers) -> DocDiff {
1226 if diffs.is_empty() {
1227 panic!("diffs is empty");
1228 }
1229
1230 let triggered_by = diffs[0].by;
1231 debug_assert!(diffs.iter().all(|x| x.by == triggered_by));
1232 let mut containers = FxHashMap::default();
1233 let to = (*diffs.last().unwrap().new_version).to_owned();
1234 let origin = diffs[0].origin.clone();
1235 for diff in diffs {
1236 #[allow(clippy::unnecessary_to_owned)]
1237 for container_diff in diff.diff.into_owned() {
1238 if container_diff.is_container_deleted {
1239 continue;
1241 }
1242 let Some((last_container_diff, _)) = containers.get_mut(&container_diff.idx) else {
1243 if let Some(path) = self.get_path(container_diff.idx) {
1244 containers.insert(container_diff.idx, (container_diff.diff, path));
1245 } else {
1246 tracing::warn!(
1249 "⚠️ WARNING: ignore event because cannot find its path {:#?} container id:{}",
1250 &container_diff,
1251 self.arena.idx_to_id(container_diff.idx).unwrap()
1252 );
1253 }
1254
1255 continue;
1256 };
1257 *last_container_diff = last_container_diff
1259 .clone()
1260 .compose(container_diff.diff)
1261 .unwrap();
1262 }
1263 }
1264 let mut diff: Vec<_> = containers
1265 .into_iter()
1266 .map(|(container, (diff, path))| {
1267 let idx = container;
1268 let id = self.arena.get_container_id(idx).unwrap();
1269 let is_unknown = id.is_unknown();
1270
1271 ContainerDiff {
1272 id,
1273 idx,
1274 diff: diff.into_external().unwrap(),
1275 is_unknown,
1276 path,
1277 }
1278 })
1279 .collect();
1280
1281 diff.sort_by_key(|x| {
1285 (
1286 x.path.len(),
1287 match &x.id {
1288 ContainerID::Root { .. } => 0,
1289 ContainerID::Normal { counter, .. } => *counter + 1,
1290 },
1291 )
1292 });
1293 DocDiff {
1294 from,
1295 to,
1296 origin,
1297 by: triggered_by,
1298 diff,
1299 }
1300 }
1301
1302 pub(crate) fn get_reachable(&mut self, id: &ContainerID) -> bool {
1303 if matches!(id, ContainerID::Root { .. }) {
1304 return true;
1305 }
1306
1307 let Some(mut idx) = self.arena.id_to_idx(id) else {
1308 return false;
1309 };
1310 loop {
1311 let id = self.arena.idx_to_id(idx).unwrap();
1312 if let Some(parent_idx) = self.arena.get_parent(idx) {
1313 let Some(parent_state) = self.store.get_container_mut(parent_idx) else {
1314 return false;
1315 };
1316 if !parent_state.contains_child(&id) {
1317 return false;
1318 }
1319 idx = parent_idx;
1320 } else {
1321 if id.is_root() {
1322 return true;
1323 }
1324
1325 return false;
1326 }
1327 }
1328 }
1329
1330 pub(super) fn get_path(&mut self, idx: ContainerIdx) -> Option<Vec<(ContainerID, Index)>> {
1332 let mut ans = Vec::new();
1333 let mut idx = idx;
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 parent_state = self.store.get_container_mut(parent_idx)?;
1338 let Some(prop) = parent_state.get_child_index(&id) else {
1339 tracing::info!("Missing in parent children");
1340 return None;
1341 };
1342 ans.push((id, prop));
1343 idx = parent_idx;
1344 } else {
1345 let Ok(prop) = id.clone().into_root() else {
1347 let id = format!("{}", &id);
1348 tracing::info!(?id, "Missing parent - container is deleted");
1349 return None;
1350 };
1351 ans.push((id, Index::Key(prop.0)));
1352 break;
1353 }
1354 }
1355
1356 ans.reverse();
1357
1358 Some(ans)
1359 }
1360
1361 pub(crate) fn check_before_decode_snapshot(&self) -> LoroResult<()> {
1362 if self.is_in_txn() {
1363 return Err(LoroError::DecodeError(
1364 "State is in txn".to_string().into_boxed_str(),
1365 ));
1366 }
1367
1368 if !self.can_import_snapshot() {
1369 return Err(LoroError::DecodeError(
1370 "State is not empty, cannot import snapshot directly"
1371 .to_string()
1372 .into_boxed_str(),
1373 ));
1374 }
1375
1376 Ok(())
1377 }
1378
1379 pub(crate) fn check_is_the_same(&mut self, other: &mut Self) {
1386 fn get_entries_for_state(
1387 arena: &SharedArena,
1388 state: &mut State,
1389 ) -> Option<(ContainerID, (ContainerIdx, LoroValue))> {
1390 if state.is_state_empty() {
1391 return None;
1392 }
1393
1394 let id = arena.idx_to_id(state.container_idx()).unwrap();
1395 let value = match state {
1396 State::RichtextState(s) => s.get_richtext_value(),
1397 _ => state.get_value(),
1398 };
1399 if match &value {
1400 LoroValue::List(l) => l.is_empty(),
1401 LoroValue::Map(m) => m.is_empty(),
1402 _ => false,
1403 } {
1404 return None;
1405 }
1406 #[cfg(feature = "counter")]
1407 if id.container_type() == ContainerType::Counter {
1408 if let LoroValue::Double(c) = value {
1409 if c.abs() < f64::EPSILON {
1410 return None;
1411 }
1412 }
1413 }
1414
1415 Some((id, (state.container_idx(), value)))
1416 }
1417
1418 let self_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = self
1419 .store
1420 .iter_and_decode_all()
1421 .filter_map(|state: &mut State| {
1422 let arena = &self.arena;
1423 get_entries_for_state(arena, state)
1424 })
1425 .collect();
1426 let mut other_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = other
1427 .store
1428 .iter_and_decode_all()
1429 .filter_map(|state: &mut State| {
1430 let arena = &other.arena;
1431 get_entries_for_state(arena, state)
1432 })
1433 .collect();
1434 for (id, (idx, this_value)) in self_id_to_states {
1435 let (_, other_value) = match other_id_to_states.remove(&id) {
1436 Some(x) => x,
1437 None => {
1438 panic!(
1439 "id: {:?}, path: {:?} is missing, value={:?}",
1440 id,
1441 self.get_path(idx),
1442 &this_value
1443 );
1444 }
1445 };
1446
1447 pretty_assertions::assert_eq!(
1448 this_value,
1449 other_value,
1450 "[self!=other] id: {:?}, path: {:?}",
1451 id,
1452 self.get_path(idx)
1453 );
1454 }
1455
1456 if !other_id_to_states.is_empty() {
1457 panic!("other has more states {:#?}", &other_id_to_states);
1458 }
1459 }
1460
1461 pub fn log_estimated_size(&self) {
1462 let state_entries_size =
1463 self.store.len() * (std::mem::size_of::<State>() + std::mem::size_of::<ContainerIdx>());
1464 let mut state_size_sum = 0;
1465 state_size_sum += self.store.estimate_size();
1466
1467 eprintln!(
1468 "ContainerNum: {}\nEstimated state size: \nEntries: {} \nSum: {}",
1469 self.store.len(),
1470 state_entries_size,
1471 state_size_sum
1472 );
1473 }
1474
1475 pub fn create_state(&self, idx: ContainerIdx) -> State {
1476 let config = &self.config;
1477 let peer = self.peer.load(std::sync::atomic::Ordering::Relaxed);
1478 create_state_(idx, config, peer)
1479 }
1480
1481 pub fn create_unknown_state(&self, idx: ContainerIdx) -> State {
1482 State::UnknownState(UnknownState::new(idx))
1483 }
1484
1485 pub fn get_relative_position(&mut self, pos: &Cursor, use_event_index: bool) -> Option<usize> {
1486 let idx = self.arena.register_container(&pos.container);
1487 let state = self.store.get_container_mut(idx)?;
1488 if let Some(id) = pos.id {
1489 match state {
1490 State::ListState(s) => s.get_index_of_id(id),
1491 State::RichtextState(s) => s.get_text_index_of_id(id, use_event_index),
1492 State::MovableListState(s) => s.get_index_of_id(id),
1493 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
1494 #[cfg(feature = "counter")]
1495 State::CounterState(_) => unreachable!(),
1496 }
1497 } else {
1498 if matches!(pos.side, crate::cursor::Side::Left) {
1499 return Some(0);
1500 }
1501
1502 match state {
1503 State::ListState(s) => Some(s.len()),
1504 State::RichtextState(s) => Some(if use_event_index {
1505 s.len_event()
1506 } else {
1507 s.len_unicode()
1508 }),
1509 State::MovableListState(s) => Some(s.len()),
1510 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
1511 #[cfg(feature = "counter")]
1512 State::CounterState(_) => unreachable!(),
1513 }
1514 }
1515 }
1516
1517 pub fn get_value_by_path(&mut self, path: &[Index]) -> Option<LoroValue> {
1518 if path.is_empty() {
1519 return None;
1520 }
1521
1522 enum CurContainer {
1523 Container(ContainerIdx),
1524 TreeNode {
1525 tree: ContainerIdx,
1526 node: Option<TreeID>,
1527 },
1528 }
1529
1530 let mut state_idx = {
1531 let root_index = path[0].as_key()?;
1532 CurContainer::Container(self.arena.get_root_container_idx_by_key(root_index)?)
1533 };
1534
1535 if path.len() == 1 {
1536 if let CurContainer::Container(c) = state_idx {
1537 let cid = self.arena.idx_to_id(c)?;
1538 return Some(LoroValue::Container(cid));
1539 }
1540 }
1541
1542 let mut i = 1;
1543 while i < path.len() - 1 {
1544 let index = &path[i];
1545 match state_idx {
1546 CurContainer::Container(idx) => {
1547 let parent_state = self.store.get_container_mut(idx)?;
1548 match parent_state {
1549 State::ListState(l) => {
1550 let Some(LoroValue::Container(c)) = l.get(*index.as_seq()?) else {
1551 return None;
1552 };
1553 state_idx = CurContainer::Container(self.arena.register_container(c));
1554 }
1555 State::MovableListState(l) => {
1556 let Some(LoroValue::Container(c)) =
1557 l.get(*index.as_seq()?, IndexType::ForUser)
1558 else {
1559 return None;
1560 };
1561 state_idx = CurContainer::Container(self.arena.register_container(c));
1562 }
1563 State::MapState(m) => {
1564 let Some(LoroValue::Container(c)) = m.get(index.as_key()?) else {
1565 return None;
1566 };
1567 state_idx = CurContainer::Container(self.arena.register_container(c));
1568 }
1569 State::RichtextState(_) => return None,
1570 State::TreeState(_) => {
1571 state_idx = CurContainer::TreeNode {
1572 tree: idx,
1573 node: None,
1574 };
1575 continue;
1576 }
1577 #[cfg(feature = "counter")]
1578 State::CounterState(_) => return None,
1579 State::UnknownState(_) => unreachable!(),
1580 }
1581 }
1582 CurContainer::TreeNode { tree, node } => match index {
1583 Index::Key(internal_string) => {
1584 let node = node?;
1585 let idx = self
1586 .arena
1587 .register_container(&node.associated_meta_container());
1588 let map = self.store.get_container(idx)?;
1589 let Some(LoroValue::Container(c)) =
1590 map.as_map_state().unwrap().get(internal_string)
1591 else {
1592 return None;
1593 };
1594
1595 state_idx = CurContainer::Container(self.arena.register_container(c));
1596 }
1597 Index::Seq(i) => {
1598 let tree_state =
1599 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1600 let parent: TreeParentId = if let Some(node) = node {
1601 node.into()
1602 } else {
1603 TreeParentId::Root
1604 };
1605 let child = tree_state.get_children(&parent)?.nth(*i)?;
1606 state_idx = CurContainer::TreeNode {
1607 tree,
1608 node: Some(child),
1609 };
1610 }
1611 Index::Node(tree_id) => {
1612 let tree_state =
1613 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1614 if tree_state.parent(tree_id).is_some() {
1615 state_idx = CurContainer::TreeNode {
1616 tree,
1617 node: Some(*tree_id),
1618 }
1619 } else {
1620 return None;
1621 }
1622 }
1623 },
1624 }
1625 i += 1;
1626 }
1627
1628 let parent_idx = match state_idx {
1629 CurContainer::Container(container_idx) => container_idx,
1630 CurContainer::TreeNode { tree, node } => {
1631 if let Some(node) = node {
1632 self.arena
1633 .register_container(&node.associated_meta_container())
1634 } else {
1635 tree
1636 }
1637 }
1638 };
1639
1640 let parent_state = self.store.get_or_create_mut(parent_idx);
1641 let index = path.last().unwrap();
1642 let value: LoroValue = match parent_state {
1643 State::ListState(l) => l.get(*index.as_seq()?).cloned()?,
1644 State::MovableListState(l) => l.get(*index.as_seq()?, IndexType::ForUser).cloned()?,
1645 State::MapState(m) => {
1646 if let Some(key) = index.as_key() {
1647 m.get(key).cloned()?
1648 } else if let CurContainer::TreeNode { tree, node } = state_idx {
1649 match index {
1650 Index::Seq(index) => {
1651 let tree_state =
1652 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1653 let parent: TreeParentId = if let Some(node) = node {
1654 node.into()
1655 } else {
1656 TreeParentId::Root
1657 };
1658 let child = tree_state.get_children(&parent)?.nth(*index)?;
1659 child.associated_meta_container().into()
1660 }
1661 Index::Node(id) => id.associated_meta_container().into(),
1662 _ => return None,
1663 }
1664 } else {
1665 return None;
1666 }
1667 }
1668 State::RichtextState(s) => {
1669 let s = s.to_string_mut();
1670 s.chars()
1671 .nth(*index.as_seq()?)
1672 .map(|c| c.to_string().into())?
1673 }
1674 State::TreeState(_) => {
1675 let id = index.as_node()?;
1676 let cid = id.associated_meta_container();
1677 cid.into()
1678 }
1679 #[cfg(feature = "counter")]
1680 State::CounterState(_) => unreachable!(),
1681 State::UnknownState(_) => unreachable!(),
1682 };
1683
1684 Some(value)
1685 }
1686
1687 pub(crate) fn shallow_root_store(&self) -> Option<&Arc<GcStore>> {
1688 self.store.shallow_root_store()
1689 }
1690}
1691
1692fn create_state_(idx: ContainerIdx, config: &Configure, peer: u64) -> State {
1693 match idx.get_type() {
1694 ContainerType::Map => State::MapState(Box::new(MapState::new(idx))),
1695 ContainerType::List => State::ListState(Box::new(ListState::new(idx))),
1696 ContainerType::Text => State::RichtextState(Box::new(RichtextState::new(
1697 idx,
1698 config.text_style_config.clone(),
1699 ))),
1700 ContainerType::Tree => State::TreeState(Box::new(TreeState::new(idx, peer))),
1701 ContainerType::MovableList => State::MovableListState(Box::new(MovableListState::new(idx))),
1702 #[cfg(feature = "counter")]
1703 ContainerType::Counter => {
1704 State::CounterState(Box::new(counter_state::CounterState::new(idx)))
1705 }
1706 ContainerType::Unknown(_) => State::UnknownState(UnknownState::new(idx)),
1707 }
1708}
1709
1710fn trigger_on_new_container(
1711 state_diff: &Diff,
1712 mut listener: impl FnMut(ContainerIdx),
1713 arena: &SharedArena,
1714) {
1715 match state_diff {
1716 Diff::List(list) => {
1717 for delta in list.iter() {
1718 if let DeltaItem::Replace {
1719 value,
1720 attr,
1721 delete: _,
1722 } = delta
1723 {
1724 if attr.from_move {
1725 continue;
1726 }
1727
1728 for v in value.iter() {
1729 if let ValueOrHandler::Handler(h) = v {
1730 let idx = h.container_idx();
1731 listener(idx);
1732 }
1733 }
1734 }
1735 }
1736 }
1737 Diff::Map(map) => {
1738 for (_, v) in map.updated.iter() {
1739 if let Some(ValueOrHandler::Handler(h)) = &v.value {
1740 let idx = h.container_idx();
1741 listener(idx);
1742 }
1743 }
1744 }
1745 Diff::Tree(tree) => {
1746 for item in tree.iter() {
1747 if matches!(item.action, TreeExternalDiff::Create { .. }) {
1748 let id = item.target.associated_meta_container();
1749 listener(arena.id_to_idx(&id).unwrap());
1750 }
1751 }
1752 }
1753 _ => {}
1754 };
1755}
1756
1757#[derive(Default, Clone)]
1758struct EventRecorder {
1759 recording_diff: bool,
1760 diffs: Vec<InternalDocDiff<'static>>,
1763 events: Vec<DocDiff>,
1764 diff_start_version: Option<Frontiers>,
1765}
1766
1767impl EventRecorder {
1768 #[allow(unused)]
1769 pub fn new() -> Self {
1770 Self::default()
1771 }
1772}
1773
1774#[test]
1775fn test_size() {
1776 println!("Size of State = {}", std::mem::size_of::<State>());
1777 println!("Size of MapState = {}", std::mem::size_of::<MapState>());
1778 println!("Size of ListState = {}", std::mem::size_of::<ListState>());
1779 println!(
1780 "Size of TextState = {}",
1781 std::mem::size_of::<RichtextState>()
1782 );
1783 println!("Size of TreeState = {}", std::mem::size_of::<TreeState>());
1784}