Skip to main content

loro_internal/
state.rs

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