loro_internal/
state.rs

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