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