loro_internal/
state.rs

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) states: FxHashMap<ContainerIdx, State>,
66    pub(super) store: ContainerStore,
67    pub(super) arena: SharedArena,
68    pub(crate) config: Configure,
69    // resolve event stuff
70    doc: Weak<LoroDocInner>,
71    // txn related stuff
72    in_txn: bool,
73    changed_idx_in_txn: FxHashSet<ContainerIdx>,
74
75    // diff related stuff
76    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    /// Convert a state to a diff, such that an empty state will be transformed into the same as this state when it's applied.
131    fn to_diff(&mut self, doc: &Weak<LoroDocInner>) -> Diff;
132
133    fn get_value(&mut self) -> LoroValue;
134
135    /// Get the index of the child container
136    #[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    /// Encode the ops and the blob that can be used to restore the state to the current state.
146    ///
147    /// State will use the provided encoder to encode the ops and export a blob.
148    /// The ops should be encoded into the snapshot as well as the blob.
149    /// The users then can use the ops and the blob to restore the state to the current state.
150    fn encode_snapshot(&self, encoder: StateSnapshotEncoder) -> Vec<u8>;
151
152    /// Restore the state to the state represented by the ops and the blob that exported by `get_snapshot_ops`
153    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        // TODO: maybe we should switch to certain version in oplog?
359
360        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    /// Take all the diffs that are recorded and convert them to events.
427    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    /// Record the next diff.
437    /// Caller should call [pre_txn] before calling this.
438    ///
439    /// # Panic
440    ///
441    /// Panic when the diff cannot be merged with the previous diff.
442    /// Caller should call [pre_txn] before calling this to avoid panic.
443    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    /// This should be called when DocState is going to apply a transaction / a diff.
462    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        // current diff batch cannot merge with the incoming diff,
476        // need to convert all the current diffs into event
477        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    /// Change the peer id of this doc state.
494    /// It changes the peer id for the future txn on this AppState
495    #[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    /// It's expected that diff only contains [`InternalDiff`]
505    ///
506    #[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        // # Revival
528        //
529        // A Container, if it is deleted from its parent Container, will still exist
530        // in the internal state of Loro;  whereas on the user side, a tree structure
531        // is maintained following Events, and at this point, the corresponding state
532        // is considered deleted.
533        //
534        // Sometimes, this "pseudo-dead" Container may be revived (for example, through
535        // backtracking or parallel editing),  and the user side should receive an Event
536        // that restores the consistency between the revived Container and the  internal
537        // state of Loro. This Event is required to restore the pseudo-dead  Container
538        // State to its current state on Loro, and we refer to this process as "revival".
539        //
540        // Revival occurs during the application of the internal diff, and this operation
541        // is necessary when it needs to be converted into an external Event.
542        //
543        // We can utilize the output of the Diff to determine which child nodes should be revived.
544        //
545        // For nodes that are to be revived, we can disregard the Events output by their
546        // round of apply_diff_and_convert,  and instead, directly convert their state into
547        // an Event once their application is complete.
548        //
549        // Suppose A is revived and B is A's child, and B also needs to be revived; therefore,
550        // we should process each level alternately.
551
552        // We need to ensure diff is processed in order
553        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                // Clear `to_revive` when we are going to process a new level
566                // so that we can process the revival of the next level
567                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                            // process bring_back before apply
622                            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        // Revive the last several layers
670        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        // set parent first, `MapContainer` will only be created for TreeID that does not contain
710        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        // TODO: we may need a better way to handle this in the future when we need to enable fully lazy loading on state
744        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    /// Ensure the container is created and will be encoded in the next `encode` call
776    #[inline]
777    pub(crate) fn ensure_container(&mut self, id: &ContainerID) {
778        self.store.ensure_container(id);
779    }
780
781    /// Ensure all alive containers are created in DocState and will be encoded in the next `encode` call
782    pub(crate) fn ensure_all_alive_containers(&mut self) -> FxHashSet<ContainerID> {
783        // TODO: PERF This can be optimized because we shouldn't need to call get_value for
784        // all the containers every time we export
785        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    /// Set the state of the container with the given container idx.
804    /// This is only used for decode.
805    ///
806    /// # Panic
807    ///
808    /// If the state is not empty.
809    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    /// id can be a str, ContainerID, or ContainerIdRaw.
891    /// if it's str it will use Root container, which will not be None
892    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    /// id can be a str, ContainerID, or ContainerIdRaw.
904    /// if it's str it will use Root container, which will not be None
905    #[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                    // Each tree node has an associated map container to represent
1120                    // the metadata of this node. When the user get the deep value,
1121                    // we need to add a field named `meta` to the tree node,
1122                    // whose value is deep value of map container.
1123                    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                    // Each tree node has an associated map container to represent
1189                    // the metadata of this node. When the user get the deep value,
1190                    // we need to add a field named `meta` to the tree node,
1191                    // whose value is deep value of map container.
1192                    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    // Because we need to calculate path based on [DocState], so we cannot extract
1224    // the event recorder to a separate module.
1225    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                    // omit event form deleted container
1240                    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                        // if we cannot find the path to the container, the container must be overwritten afterwards.
1247                        // So we can ignore the diff from it.
1248                        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                // TODO: PERF avoid this clone
1258                *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        // Sort by path length, so caller can apply the diff from the root to the leaf.
1282        // Otherwise, the caller may use a wrong path to apply the diff.
1283
1284        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    // the container may be override, so it may return None
1331    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                // this container may be deleted
1346                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    /// Check whether two [DocState]s are the same. Panic if not.
1380    ///
1381    /// Compared to check equality on `get_deep_value`, this function also checks the equality on richtext
1382    /// styles and states that are not reachable from the root.
1383    ///
1384    /// This is only used for test.
1385    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    // A batch of diffs will be converted to a event when
1761    // they cannot be merged with the next diff.
1762    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}