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