Skip to main content

loro_internal/
state.rs

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