1pub mod container_tree;
2
3use crate::sync::{AtomicU64, Mutex, RwLock};
4#[cfg(test)]
5use std::cell::Cell;
6use std::sync::{Arc, Weak};
7use std::{borrow::Cow, io::Write, sync::atomic::Ordering};
8
9use container_store::ContainerStore;
10use dead_containers_cache::DeadContainersCache;
11use enum_as_inner::EnumAsInner;
12use enum_dispatch::enum_dispatch;
13use loro_common::{ContainerID, Lamport, LoroError, LoroResult, TreeID};
14use loro_delta::DeltaItem;
15use rustc_hash::{FxHashMap, FxHashSet};
16use smallvec::SmallVec;
17use tracing::{info_span, instrument, warn};
18
19use crate::{
20 configure::{Configure, DefaultRandom, SecureRandomGenerator},
21 container::{idx::ContainerIdx, richtext::config::StyleConfigMap},
22 cursor::{Cursor, PosType},
23 delta::TreeExternalDiff,
24 diff_calc::{DiffCalculator, DiffMode},
25 event::{Diff, EventTriggerKind, Index, InternalContainerDiff, InternalDiff},
26 fx_map,
27 handler::ValueOrHandler,
28 id::PeerID,
29 lock::{LoroLockGroup, LoroMutex},
30 op::{Op, RawOp},
31 version::Frontiers,
32 ContainerDiff, ContainerType, DocDiff, InternalString, LoroDocInner, LoroValue, OpLog,
33};
34
35pub(crate) mod analyzer;
36pub(crate) mod container_store;
37#[cfg(feature = "counter")]
38mod counter_state;
39mod dead_containers_cache;
40mod list_state;
41mod map_state;
42mod mergeable;
43mod movable_list_state;
44mod richtext_state;
45mod tree_state;
46mod unknown_state;
47
48pub(crate) use self::movable_list_state::{IndexType, MovableListState};
49pub(crate) use container_store::GcStore;
50pub(crate) use list_state::ListState;
51pub(crate) use map_state::MapState;
52pub(crate) use richtext_state::{redact_dead_style_values, RichtextState};
53pub(crate) use tree_state::FiIfNotConfigured;
54pub(crate) use tree_state::{get_meta_value, FractionalIndexGenResult, NodePosition, TreeState};
55pub use tree_state::{TreeNode, TreeNodeWithChildren, TreeParentId};
56
57use self::{container_store::ContainerWrapper, unknown_state::UnknownState};
58
59#[cfg(feature = "counter")]
60use self::counter_state::CounterState;
61
62use super::{arena::SharedArena, event::InternalDocDiff};
63
64#[cfg(test)]
65thread_local! {
66 static FAIL_NEXT_IMPORT_STATE_APPLY: Cell<bool> = Cell::new(false);
67}
68
69#[cfg(test)]
70pub(crate) fn fail_next_import_state_apply_for_test() {
71 FAIL_NEXT_IMPORT_STATE_APPLY.with(|fail| fail.set(true));
72}
73
74fn visible_container_value_is_empty(kind: ContainerType, value: &LoroValue) -> bool {
75 match kind {
76 ContainerType::Text => value.as_string().is_some_and(|value| value.is_empty()),
77 ContainerType::Map | ContainerType::List | ContainerType::MovableList => {
78 value.is_empty_collection()
79 }
80 ContainerType::Tree => value.as_list().is_some_and(|value| value.is_empty()),
81 #[cfg(feature = "counter")]
82 ContainerType::Counter => false,
83 ContainerType::Unknown(_) => false,
84 }
85}
86
87fn deleted_root_container_value_is_cleared(kind: ContainerType, value: &LoroValue) -> bool {
88 match kind {
89 #[cfg(feature = "counter")]
90 ContainerType::Counter => value.as_double().is_some_and(|value| *value == 0.0),
91 _ => visible_container_value_is_empty(kind, value),
92 }
93}
94
95fn state_decode_error(message: impl Into<Box<str>>) -> LoroError {
96 LoroError::DecodeError(message.into())
97}
98
99fn decode_peer_table(bytes: &mut &[u8], context: &str) -> LoroResult<Vec<PeerID>> {
100 let peer_num = leb128::read::unsigned(bytes)
101 .map_err(|_| state_decode_error(format!("{context}: invalid peer table length")))?;
102 let peer_num = usize::try_from(peer_num)
103 .map_err(|_| state_decode_error(format!("{context}: peer table length overflow")))?;
104 let peer_bytes_len = peer_num
105 .checked_mul(std::mem::size_of::<PeerID>())
106 .ok_or_else(|| state_decode_error(format!("{context}: peer table byte length overflow")))?;
107 if bytes.len() < peer_bytes_len {
108 return Err(state_decode_error(format!(
109 "{context}: truncated peer table"
110 )));
111 }
112
113 let peer_bytes = &bytes[..peer_bytes_len];
114 let peers = peer_bytes
115 .chunks_exact(std::mem::size_of::<PeerID>())
116 .map(|chunk| {
117 let mut buf = [0u8; std::mem::size_of::<PeerID>()];
118 buf.copy_from_slice(chunk);
119 PeerID::from_le_bytes(buf)
120 })
121 .collect();
122 *bytes = &bytes[peer_bytes_len..];
123 Ok(peers)
124}
125
126fn decode_peer_from_table(peers: &[PeerID], peer_idx: usize, context: &str) -> LoroResult<PeerID> {
127 peers
128 .get(peer_idx)
129 .copied()
130 .ok_or_else(|| state_decode_error(format!("{context}: peer index out of range")))
131}
132
133fn read_state_leb_u64(bytes: &mut &[u8], context: &str) -> LoroResult<u64> {
134 leb128::read::unsigned(bytes)
135 .map_err(|_| state_decode_error(format!("{context}: invalid integer")))
136}
137
138fn decode_counter(counter: i32, context: &str) -> LoroResult<i32> {
139 if counter < 0 {
140 return Err(state_decode_error(format!("{context}: negative counter")));
141 }
142
143 Ok(counter)
144}
145
146fn decode_lamport_from_delta(
147 counter: i32,
148 lamport_sub_counter: i32,
149 context: &str,
150) -> LoroResult<Lamport> {
151 decode_counter(counter, context)?;
152 let lamport = counter
153 .checked_add(lamport_sub_counter)
154 .ok_or_else(|| state_decode_error(format!("{context}: lamport overflow")))?;
155 u32::try_from(lamport).map_err(|_| state_decode_error(format!("{context}: negative lamport")))
156}
157
158pub struct DocState {
159 pub(super) peer: Arc<AtomicU64>,
160
161 pub(super) frontiers: Frontiers,
162 pub(super) store: ContainerStore,
164 pub(super) arena: SharedArena,
165 pub(crate) config: Configure,
166 doc: Weak<LoroDocInner>,
168 in_txn: bool,
170 changed_idx_in_txn: FxHashSet<ContainerIdx>,
171
172 event_recorder: EventRecorder,
174
175 dead_containers_cache: DeadContainersCache,
176 alive_containers_cache: Option<AliveContainersCache>,
177}
178
179struct AliveContainersCache {
180 frontiers: Frontiers,
181 roots: Vec<ContainerIdx>,
182 indices: Arc<FxHashSet<ContainerIdx>>,
183}
184
185const ALIVE_CONTAINERS_CACHE_MAX_BYTES: usize = 4 * 1024 * 1024;
186
187fn estimated_alive_containers_cache_bytes(
188 roots_capacity: usize,
189 indices: &FxHashSet<ContainerIdx>,
190) -> usize {
191 roots_capacity
195 .saturating_mul(std::mem::size_of::<ContainerIdx>())
196 .saturating_add(
197 indices
198 .capacity()
199 .saturating_mul(std::mem::size_of::<ContainerIdx>() + std::mem::size_of::<usize>()),
200 )
201}
202
203impl std::fmt::Debug for DocState {
204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205 f.debug_struct("DocState")
206 .field("peer", &self.peer)
207 .finish()
208 }
209}
210
211#[derive(Clone, Copy)]
212pub(crate) struct ContainerCreationContext<'a> {
213 pub configure: &'a Configure,
214 pub peer: PeerID,
215}
216
217pub(crate) struct DiffApplyContext<'a> {
218 pub mode: DiffMode,
219 pub doc: &'a Weak<LoroDocInner>,
220}
221
222pub(crate) trait FastStateSnapshot {
223 fn encode_snapshot_fast<W: Write>(&mut self, w: W);
224 fn decode_value(bytes: &[u8]) -> LoroResult<(LoroValue, &[u8])>;
225 fn decode_snapshot_fast(
226 idx: ContainerIdx,
227 v: (LoroValue, &[u8]),
228 ctx: ContainerCreationContext,
229 ) -> LoroResult<Self>
230 where
231 Self: Sized;
232}
233
234#[derive(Debug, Clone, Default)]
235pub(crate) struct ApplyLocalOpReturn {
236 pub deleted_containers: Vec<ContainerID>,
237}
238
239#[enum_dispatch]
240pub(crate) trait ContainerState {
241 fn container_idx(&self) -> ContainerIdx;
242
243 fn is_state_empty(&self) -> bool;
244
245 #[must_use]
246 fn apply_diff_and_convert(&mut self, diff: InternalDiff, ctx: DiffApplyContext) -> Diff;
247
248 fn apply_diff(&mut self, diff: InternalDiff, ctx: DiffApplyContext) -> LoroResult<()>;
254
255 fn validate_diff(&self, _diff: &InternalDiff) -> LoroResult<()> {
259 Ok(())
260 }
261
262 fn apply_local_op(&mut self, raw_op: &RawOp, op: &Op) -> LoroResult<ApplyLocalOpReturn>;
263 fn to_diff(&mut self, doc: &Weak<LoroDocInner>) -> Diff;
265
266 fn get_value(&mut self) -> LoroValue;
267
268 #[allow(unused)]
270 fn get_child_index(&self, id: &ContainerID) -> Option<Index>;
271
272 #[allow(unused)]
273 fn contains_child(&self, id: &ContainerID) -> bool;
274
275 #[allow(unused)]
276 fn get_child_containers(&self) -> Vec<ContainerID>;
277
278 fn fork(&self, config: &Configure) -> Self;
279}
280
281impl<T: FastStateSnapshot> FastStateSnapshot for Box<T> {
282 fn encode_snapshot_fast<W: Write>(&mut self, w: W) {
283 self.as_mut().encode_snapshot_fast(w)
284 }
285
286 fn decode_value(bytes: &[u8]) -> LoroResult<(LoroValue, &[u8])> {
287 T::decode_value(bytes)
288 }
289
290 fn decode_snapshot_fast(
291 idx: ContainerIdx,
292 v: (LoroValue, &[u8]),
293 ctx: ContainerCreationContext,
294 ) -> LoroResult<Self>
295 where
296 Self: Sized,
297 {
298 T::decode_snapshot_fast(idx, v, ctx).map(|x| Box::new(x))
299 }
300}
301
302impl<T: ContainerState> ContainerState for Box<T> {
303 fn container_idx(&self) -> ContainerIdx {
304 self.as_ref().container_idx()
305 }
306
307 fn is_state_empty(&self) -> bool {
308 self.as_ref().is_state_empty()
309 }
310
311 fn apply_diff_and_convert(&mut self, diff: InternalDiff, ctx: DiffApplyContext) -> Diff {
312 self.as_mut().apply_diff_and_convert(diff, ctx)
313 }
314
315 fn apply_diff(&mut self, diff: InternalDiff, ctx: DiffApplyContext) -> LoroResult<()> {
316 self.as_mut().apply_diff(diff, ctx)
317 }
318
319 fn validate_diff(&self, diff: &InternalDiff) -> LoroResult<()> {
320 self.as_ref().validate_diff(diff)
321 }
322
323 fn apply_local_op(&mut self, raw_op: &RawOp, op: &Op) -> LoroResult<ApplyLocalOpReturn> {
324 self.as_mut().apply_local_op(raw_op, op)
325 }
326
327 #[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."]
328 fn to_diff(&mut self, doc: &Weak<LoroDocInner>) -> Diff {
329 self.as_mut().to_diff(doc)
330 }
331
332 fn get_value(&mut self) -> LoroValue {
333 self.as_mut().get_value()
334 }
335
336 #[doc = r" Get the index of the child container"]
337 #[allow(unused)]
338 fn get_child_index(&self, id: &ContainerID) -> Option<Index> {
339 self.as_ref().get_child_index(id)
340 }
341
342 fn contains_child(&self, id: &ContainerID) -> bool {
343 self.as_ref().contains_child(id)
344 }
345
346 #[allow(unused)]
347 fn get_child_containers(&self) -> Vec<ContainerID> {
348 self.as_ref().get_child_containers()
349 }
350
351 fn fork(&self, config: &Configure) -> Self {
352 Box::new(self.as_ref().fork(config))
353 }
354}
355
356#[allow(clippy::enum_variant_names)]
357#[enum_dispatch(ContainerState)]
358#[derive(EnumAsInner, Debug)]
359pub enum State {
360 ListState(Box<ListState>),
361 MovableListState(Box<MovableListState>),
362 MapState(Box<MapState>),
363 RichtextState(Box<RichtextState>),
364 TreeState(Box<TreeState>),
365 #[cfg(feature = "counter")]
366 CounterState(Box<counter_state::CounterState>),
367 UnknownState(UnknownState),
368}
369
370impl From<ListState> for State {
371 fn from(s: ListState) -> Self {
372 Self::ListState(Box::new(s))
373 }
374}
375
376impl From<RichtextState> for State {
377 fn from(s: RichtextState) -> Self {
378 Self::RichtextState(Box::new(s))
379 }
380}
381
382impl From<MovableListState> for State {
383 fn from(s: MovableListState) -> Self {
384 Self::MovableListState(Box::new(s))
385 }
386}
387
388impl From<MapState> for State {
389 fn from(s: MapState) -> Self {
390 Self::MapState(Box::new(s))
391 }
392}
393
394impl From<TreeState> for State {
395 fn from(s: TreeState) -> Self {
396 Self::TreeState(Box::new(s))
397 }
398}
399
400#[cfg(feature = "counter")]
401impl From<CounterState> for State {
402 fn from(s: CounterState) -> Self {
403 Self::CounterState(Box::new(s))
404 }
405}
406
407impl State {
408 pub fn new_list(idx: ContainerIdx) -> Self {
409 Self::ListState(Box::new(ListState::new(idx)))
410 }
411
412 pub fn new_map(idx: ContainerIdx) -> Self {
413 Self::MapState(Box::new(MapState::new(idx)))
414 }
415
416 pub fn new_richtext(idx: ContainerIdx, config: Arc<RwLock<StyleConfigMap>>) -> Self {
417 Self::RichtextState(Box::new(RichtextState::new(idx, config)))
418 }
419
420 pub fn new_tree(idx: ContainerIdx, peer: PeerID) -> Self {
421 Self::TreeState(Box::new(TreeState::new(idx, peer)))
422 }
423
424 pub fn new_unknown(idx: ContainerIdx) -> Self {
425 Self::UnknownState(UnknownState::new(idx))
426 }
427
428 pub fn encode_snapshot_fast<W: Write>(&mut self, mut w: W) {
429 match self {
430 State::ListState(s) => s.encode_snapshot_fast(&mut w),
431 State::MovableListState(s) => s.encode_snapshot_fast(&mut w),
432 State::MapState(s) => s.encode_snapshot_fast(&mut w),
433 State::RichtextState(s) => s.encode_snapshot_fast(&mut w),
434 State::TreeState(s) => s.encode_snapshot_fast(&mut w),
435 #[cfg(feature = "counter")]
436 State::CounterState(s) => s.encode_snapshot_fast(&mut w),
437 State::UnknownState(s) => s.encode_snapshot_fast(&mut w),
438 }
439 }
440
441 pub fn fork(&self, config: &Configure) -> Self {
442 match self {
443 State::ListState(list_state) => State::ListState(list_state.fork(config)),
444 State::MovableListState(movable_list_state) => {
445 State::MovableListState(movable_list_state.fork(config))
446 }
447 State::MapState(map_state) => State::MapState(map_state.fork(config)),
448 State::RichtextState(richtext_state) => {
449 State::RichtextState(richtext_state.fork(config))
450 }
451 State::TreeState(tree_state) => State::TreeState(tree_state.fork(config)),
452 #[cfg(feature = "counter")]
453 State::CounterState(counter_state) => State::CounterState(counter_state.fork(config)),
454 State::UnknownState(unknown_state) => State::UnknownState(unknown_state.fork(config)),
455 }
456 }
457}
458
459impl DocState {
460 #[inline]
461 pub fn new_arc(
462 doc: Weak<LoroDocInner>,
463 arena: SharedArena,
464 config: Configure,
465 lock_group: &LoroLockGroup,
466 ) -> Arc<LoroMutex<Self>> {
467 let peer = DefaultRandom.next_u64();
468 let peer = Arc::new(AtomicU64::new(peer));
471 Arc::new(lock_group.new_lock(
472 Self {
473 store: ContainerStore::new(arena.clone(), config.clone(), peer.clone()),
474 peer,
475 arena,
476 frontiers: Frontiers::default(),
477 doc,
478 config,
479 in_txn: false,
480 changed_idx_in_txn: FxHashSet::default(),
481 event_recorder: Default::default(),
482 dead_containers_cache: Default::default(),
483 alive_containers_cache: None,
484 },
485 crate::lock::LockKind::DocState,
486 ))
487 }
488
489 pub fn fork_with_new_peer_id(
490 &mut self,
491 doc: Weak<LoroDocInner>,
492 arena: SharedArena,
493 config: Configure,
494 ) -> Arc<Mutex<Self>> {
495 let peer = Arc::new(AtomicU64::new(DefaultRandom.next_u64()));
496 let store = self.store.fork(arena.clone(), peer.clone(), config.clone());
497 Arc::new(Mutex::new(Self {
498 peer,
499 frontiers: self.frontiers.clone(),
500 store,
501 arena,
502 config,
503 doc,
504 in_txn: false,
505 changed_idx_in_txn: FxHashSet::default(),
506 event_recorder: Default::default(),
507 dead_containers_cache: Default::default(),
508 alive_containers_cache: None,
509 }))
510 }
511
512 pub fn start_recording(&mut self) {
513 if self.is_recording() {
514 return;
515 }
516
517 self.event_recorder.recording_diff = true;
518 self.event_recorder.diff_start_version = Some(self.frontiers.clone());
519 }
520
521 #[inline(always)]
522 pub fn stop_and_clear_recording(&mut self) {
523 self.event_recorder = Default::default();
524 }
525
526 #[inline(always)]
527 pub fn is_recording(&self) -> bool {
528 self.event_recorder.recording_diff
529 }
530
531 pub fn refresh_peer_id(&mut self) {
532 self.peer.store(
533 DefaultRandom.next_u64(),
534 std::sync::atomic::Ordering::Relaxed,
535 );
536 }
537
538 pub fn take_events(&mut self) -> Vec<DocDiff> {
540 if !self.is_recording() {
541 return vec![];
542 }
543
544 self.convert_current_batch_diff_into_event();
545 std::mem::take(&mut self.event_recorder.events)
546 }
547
548 fn record_diff(&mut self, diff: InternalDocDiff) {
556 if !self.event_recorder.recording_diff || diff.diff.is_empty() {
557 return;
558 }
559
560 let Some(last_diff) = self.event_recorder.diffs.last_mut() else {
561 self.event_recorder.diffs.push(diff.into_owned());
562 return;
563 };
564
565 if last_diff.can_merge(&diff) {
566 self.event_recorder.diffs.push(diff.into_owned());
567 return;
568 }
569
570 panic!("should call pre_txn before record_diff")
571 }
572
573 fn pre_txn(&mut self, next_origin: InternalString, next_trigger: EventTriggerKind) {
575 if !self.is_recording() {
576 return;
577 }
578
579 let Some(last_diff) = self.event_recorder.diffs.last() else {
580 return;
581 };
582
583 if last_diff.origin == next_origin && last_diff.by == next_trigger {
584 return;
585 }
586
587 self.convert_current_batch_diff_into_event()
590 }
591
592 fn convert_current_batch_diff_into_event(&mut self) {
593 let recorder = &mut self.event_recorder;
594 if recorder.diffs.is_empty() {
595 return;
596 }
597
598 let diffs = std::mem::take(&mut recorder.diffs);
599 let start = recorder.diff_start_version.take().unwrap();
600 recorder.diff_start_version = Some((*diffs.last().unwrap().new_version).to_owned());
601 let event = self.diffs_to_event(diffs, start);
602 self.event_recorder.events.push(event);
603 }
604
605 #[inline]
608 pub fn set_peer_id(&mut self, peer: PeerID) {
609 self.peer.store(peer, std::sync::atomic::Ordering::Relaxed);
610 }
611
612 pub fn peer_id(&self) -> PeerID {
613 self.peer.load(std::sync::atomic::Ordering::Relaxed)
614 }
615
616 #[instrument(skip_all)]
623 pub(crate) fn apply_diff(
624 &mut self,
625 mut diff: InternalDocDiff<'static>,
626 diff_mode: DiffMode,
627 ) -> LoroResult<()> {
628 if self.in_txn {
629 return Err(LoroError::TransactionError(
630 "apply_diff should not be called in a transaction"
631 .to_string()
632 .into_boxed_str(),
633 ));
634 }
635
636 let is_recording = self.is_recording();
637 let Cow::Owned(mut diffs) = std::mem::take(&mut diff.diff) else {
638 unreachable!()
639 };
640 self.validate_diff_batch(&diffs)?;
641 #[cfg(test)]
642 if diff.origin.as_str() == "__loro_fail_import_state_apply" {
643 return Err(LoroError::internal("state apply failpoint"));
644 }
645 #[cfg(test)]
646 if diff.by == EventTriggerKind::Import {
647 let should_fail = FAIL_NEXT_IMPORT_STATE_APPLY.with(|fail| {
648 let should_fail = fail.get();
649 if should_fail {
650 fail.set(false);
651 }
652 should_fail
653 });
654 if should_fail {
655 return Err(LoroError::internal("state apply failpoint"));
656 }
657 }
658 match diff_mode {
665 DiffMode::Checkout => {
666 self.dead_containers_cache.clear();
667 }
668 _ => {
669 self.dead_containers_cache.clear_alive();
670 }
671 }
672 self.pre_txn(diff.origin.clone(), diff.by);
673
674 diffs.sort_by_cached_key(|diff| self.arena.get_depth(diff.idx));
701 let mut to_revive_in_next_layer: FxHashSet<ContainerIdx> = FxHashSet::default();
702 let mut to_revive_in_this_layer: FxHashSet<ContainerIdx> = FxHashSet::default();
703 let mut last_depth = 0;
704 let len = diffs.len();
705 for mut diff in std::mem::replace(&mut diffs, Vec::with_capacity(len)) {
706 let Some(depth) = self.arena.get_depth(diff.idx) else {
707 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));
708 continue;
709 };
710 let this_depth = depth.get();
711 while this_depth > last_depth {
712 let to_create = std::mem::take(&mut to_revive_in_this_layer);
715 to_revive_in_this_layer = std::mem::take(&mut to_revive_in_next_layer);
716 for new in to_create {
717 let state = self.store.get_or_create_mut(new);
718 if state.is_state_empty() {
719 continue;
720 }
721
722 let external_diff = state.to_diff(&self.doc);
723 trigger_on_new_container(
724 &external_diff,
725 |cid| {
726 to_revive_in_this_layer.insert(cid);
727 },
728 &self.arena,
729 );
730
731 diffs.push(InternalContainerDiff {
732 idx: new,
733 bring_back: true,
734 diff: external_diff.into(),
735 diff_mode: DiffMode::Checkout,
736 });
737 }
738
739 last_depth += 1;
740 }
741
742 let idx = diff.idx;
743 let internal_diff = std::mem::take(&mut diff.diff);
744 match &internal_diff {
745 crate::event::DiffVariant::None => {
746 if is_recording {
747 let state = self.store.get_or_create_mut(diff.idx);
748 let extern_diff = state.to_diff(&self.doc);
749 trigger_on_new_container(
750 &extern_diff,
751 |cid| {
752 to_revive_in_next_layer.insert(cid);
753 },
754 &self.arena,
755 );
756 diff.diff = extern_diff.into();
757 }
758 }
759 crate::event::DiffVariant::Internal(inner_diff) => {
760 self.ensure_containers_created_by_internal_diff(inner_diff);
761 let cid = self.arena.idx_to_id(idx).unwrap();
762 info_span!("apply diff on", container_id = ?cid).in_scope(
763 || -> LoroResult<()> {
764 if self.in_txn {
765 self.changed_idx_in_txn.insert(idx);
766 }
767 let state = self.store.get_or_create_mut(idx);
768 if is_recording {
769 let external_diff =
771 if diff.bring_back || to_revive_in_this_layer.contains(&idx) {
772 state.apply_diff(
773 internal_diff.into_internal().unwrap(),
774 DiffApplyContext {
775 mode: diff.diff_mode,
776 doc: &self.doc,
777 },
778 )?;
779 state.to_diff(&self.doc)
780 } else {
781 state.apply_diff_and_convert(
782 internal_diff.into_internal().unwrap(),
783 DiffApplyContext {
784 mode: diff.diff_mode,
785 doc: &self.doc,
786 },
787 )
788 };
789 trigger_on_new_container(
790 &external_diff,
791 |cid| {
792 to_revive_in_next_layer.insert(cid);
793 },
794 &self.arena,
795 );
796 diff.diff = external_diff.into();
797 } else {
798 state.apply_diff(
799 internal_diff.into_internal().unwrap(),
800 DiffApplyContext {
801 mode: diff.diff_mode,
802 doc: &self.doc,
803 },
804 )?;
805 }
806 Ok(())
807 },
808 )?;
809 }
810 crate::event::DiffVariant::External(_) => unreachable!(),
811 }
812
813 to_revive_in_this_layer.remove(&idx);
814 if !diff.diff.is_empty() {
815 diffs.push(diff);
816 }
817 }
818
819 while !to_revive_in_this_layer.is_empty() || !to_revive_in_next_layer.is_empty() {
821 let to_create = std::mem::take(&mut to_revive_in_this_layer);
822 for new in to_create {
823 let state = self.store.get_or_create_mut(new);
824 if state.is_state_empty() {
825 continue;
826 }
827
828 let external_diff = state.to_diff(&self.doc);
829 trigger_on_new_container(
830 &external_diff,
831 |cid| {
832 to_revive_in_next_layer.insert(cid);
833 },
834 &self.arena,
835 );
836
837 if !external_diff.is_empty() {
838 diffs.push(InternalContainerDiff {
839 idx: new,
840 bring_back: true,
841 diff: external_diff.into(),
842 diff_mode: DiffMode::Checkout,
843 });
844 }
845 }
846
847 to_revive_in_this_layer = std::mem::take(&mut to_revive_in_next_layer);
848 }
849
850 diff.diff = diffs.into();
851 self.frontiers = diff.new_version.clone().into_owned();
852
853 if self.is_recording() {
854 self.record_diff(diff)
855 }
856 Ok(())
857 }
858
859 fn ensure_containers_created_by_internal_diff(&mut self, diff: &InternalDiff) {
866 let mut to_ensure: SmallVec<[ContainerID; 2]> = SmallVec::new();
867 match diff {
868 InternalDiff::ListRaw(delta) => {
869 for item in delta.iter() {
870 if let crate::delta::DeltaItem::Insert { insert, .. } = item {
871 match &insert.values {
872 either::Either::Left(range) => {
873 for value in self.arena.iter_value_slice(range.to_range()) {
874 if let LoroValue::Container(c) = value {
875 to_ensure.push(c);
876 }
877 }
878 }
879 either::Either::Right(LoroValue::Container(c)) => {
880 to_ensure.push(c.clone())
881 }
882 either::Either::Right(_) => {}
883 }
884 }
885 }
886 }
887 InternalDiff::Map(delta) => {
888 for value in delta.updated.values() {
892 let Some(Some(value)) = value.as_ref().map(|v| v.value.as_ref()) else {
893 continue;
894 };
895 if let LoroValue::Container(c) = value {
896 to_ensure.push(c.clone());
897 }
898 }
899 }
900 InternalDiff::Tree(delta) => {
901 for item in delta.diff.iter() {
902 if matches!(item.action, crate::delta::TreeInternalDiff::Create { .. }) {
903 to_ensure.push(item.target.associated_meta_container());
904 }
905 }
906 }
907 InternalDiff::MovableList(delta) => {
908 for elem in delta.elements.values() {
909 if let LoroValue::Container(c) = &elem.value {
910 to_ensure.push(c.clone());
911 }
912 }
913 }
914 InternalDiff::RichtextRaw(_) => {}
915 #[cfg(feature = "counter")]
916 InternalDiff::Counter(_) => {}
917 InternalDiff::Unknown => {}
918 }
919
920 for id in to_ensure {
921 self.ensure_container(&id);
922 }
923 }
924
925 fn validate_diff_batch(&mut self, diffs: &[InternalContainerDiff]) -> LoroResult<()> {
926 for diff in diffs {
927 let crate::event::DiffVariant::Internal(internal_diff) = &diff.diff else {
928 continue;
929 };
930 if let Some(state) = self.store.get_container(diff.idx) {
931 state.validate_diff(internal_diff)?;
932 } else {
933 let state = create_state_(diff.idx, &self.config, self.peer_id());
934 state.validate_diff(internal_diff)?;
935 }
936 }
937
938 Ok(())
939 }
940
941 pub fn apply_local_op(&mut self, raw_op: &RawOp, op: &Op) -> LoroResult<()> {
942 self.set_container_parent_by_raw_op(raw_op);
944 self.ensure_containers_created_by_op(op);
945 let state = self.store.get_or_create_mut(op.container);
946 if self.in_txn {
947 self.changed_idx_in_txn.insert(op.container);
948 }
949 let ret = state.apply_local_op(raw_op, op)?;
950 if !ret.deleted_containers.is_empty() {
951 self.dead_containers_cache.clear_alive();
952 }
953
954 Ok(())
955 }
956
957 pub(crate) fn start_txn(&mut self, origin: InternalString, trigger: EventTriggerKind) {
958 self.pre_txn(origin, trigger);
959 self.in_txn = true;
960 }
961
962 pub(crate) fn abort_txn(&mut self) {
963 self.in_txn = false;
964 }
965
966 pub fn iter_and_decode_all(&mut self) -> impl Iterator<Item = &mut State> {
967 self.store.iter_and_decode_all()
968 }
969
970 pub(crate) fn iter_all_containers_mut(
971 &mut self,
972 ) -> impl Iterator<Item = (ContainerIdx, &mut ContainerWrapper)> {
973 self.store.iter_all_containers()
974 }
975
976 pub fn does_container_exist(&mut self, id: &ContainerID) -> bool {
977 let is_mergeable = id.is_mergeable();
980 if id.is_root() && !is_mergeable {
981 return true;
982 }
983
984 if !is_mergeable {
985 if let Some(idx) = self.arena.id_to_idx(id) {
986 if self.arena.get_depth(idx).is_some() {
987 return true;
988 }
989 }
990 }
991
992 if self.store.contains_id(id) {
993 return true;
994 }
995
996 is_mergeable && self.get_reachable(id)
999 }
1000
1001 pub(crate) fn commit_txn(&mut self, new_frontiers: Frontiers, diff: Option<InternalDocDiff>) {
1002 self.in_txn = false;
1003 self.frontiers = new_frontiers;
1004 if let Some(diff) = diff {
1005 if self.is_recording() {
1006 self.record_diff(diff);
1007 }
1008 }
1009 }
1010
1011 #[inline]
1013 pub(crate) fn ensure_container(&mut self, id: &ContainerID) {
1014 self.store.ensure_container(id);
1015 }
1016
1017 pub(crate) fn ensure_all_alive_containers(
1028 &mut self,
1029 ) -> LoroResult<Arc<FxHashSet<ContainerIdx>>> {
1030 let roots = self.existing_retention_roots();
1031 if !self.in_txn {
1032 if let Some(cache) = &self.alive_containers_cache {
1033 if cache.frontiers == self.frontiers && cache.roots == roots {
1034 return Ok(cache.indices.clone());
1035 }
1036 }
1037 }
1038 self.alive_containers_cache = None;
1040
1041 let indices = Arc::new(self.get_all_alive_container_indices_from_roots(&roots)?);
1042 for idx in indices.iter() {
1043 let id = self.arena.get_container_id(*idx).unwrap();
1044 if !self.store.contains_id(&id) {
1045 self.store.ensure_container(&id);
1046 }
1047 }
1048
1049 if !self.in_txn {
1050 let roots = self.existing_retention_roots();
1054 if estimated_alive_containers_cache_bytes(roots.capacity(), &indices)
1055 <= ALIVE_CONTAINERS_CACHE_MAX_BYTES
1056 {
1057 self.alive_containers_cache = Some(AliveContainersCache {
1058 frontiers: self.frontiers.clone(),
1059 roots,
1060 indices: indices.clone(),
1061 });
1062 }
1063 }
1064
1065 Ok(indices)
1066 }
1067
1068 pub(crate) fn get_value_by_idx(&mut self, container_idx: ContainerIdx) -> LoroValue {
1069 self.store
1070 .get_value(container_idx)
1071 .unwrap_or_else(|| container_idx.get_type().default_value())
1072 }
1073
1074 pub(crate) fn get_map_value_by_key(
1075 &mut self,
1076 container_idx: ContainerIdx,
1077 key: &str,
1078 ) -> Option<LoroValue> {
1079 self.store.map_get(container_idx, key)
1080 }
1081
1082 pub(crate) fn get_map_len(&mut self, container_idx: ContainerIdx) -> usize {
1083 self.store.map_len(container_idx)
1084 }
1085
1086 pub(crate) fn get_map_keys(&mut self, container_idx: ContainerIdx) -> Vec<InternalString> {
1087 self.store.map_keys(container_idx)
1088 }
1089
1090 pub(crate) fn get_map_entries(
1091 &mut self,
1092 container_idx: ContainerIdx,
1093 ) -> Vec<(InternalString, LoroValue)> {
1094 self.store.map_entries(container_idx)
1095 }
1096
1097 pub(crate) fn get_list_value_at(
1098 &mut self,
1099 container_idx: ContainerIdx,
1100 index: usize,
1101 ) -> Option<LoroValue> {
1102 self.store.list_get(container_idx, index)
1103 }
1104
1105 pub(crate) fn get_list_len(&mut self, container_idx: ContainerIdx) -> usize {
1106 self.store.list_len(container_idx)
1107 }
1108
1109 pub(crate) fn get_list_values(&mut self, container_idx: ContainerIdx) -> Vec<LoroValue> {
1110 self.store.list_values(container_idx)
1111 }
1112
1113 pub(crate) fn get_text_unicode_len(&mut self, container_idx: ContainerIdx) -> usize {
1114 self.store.text_unicode_len(container_idx).unwrap_or(0)
1115 }
1116
1117 pub(crate) fn get_text_utf16_len(&mut self, container_idx: ContainerIdx) -> usize {
1118 self.store.text_utf16_len(container_idx).unwrap_or(0)
1119 }
1120
1121 pub(crate) fn get_text_utf8_len(&mut self, container_idx: ContainerIdx) -> usize {
1122 self.store.text_utf8_len(container_idx).unwrap_or(0)
1123 }
1124
1125 pub(crate) fn has_decoded_container_state(&mut self, container_idx: ContainerIdx) -> bool {
1126 self.store.has_decoded_state(container_idx)
1127 }
1128
1129 pub(crate) fn get_text_len(&mut self, container_idx: ContainerIdx, pos_type: PosType) -> usize {
1140 match pos_type {
1141 PosType::Unicode => self.get_text_unicode_len(container_idx),
1142 PosType::Utf16 => self.get_text_utf16_len(container_idx),
1143 PosType::Event if cfg!(feature = "wasm") => self.get_text_utf16_len(container_idx),
1144 PosType::Event => self.get_text_unicode_len(container_idx),
1145 PosType::Bytes => self.get_text_utf8_len(container_idx),
1146 PosType::Entity => self.with_state_mut(container_idx, |state| {
1147 state.as_richtext_state_mut().unwrap().len(PosType::Entity)
1148 }),
1149 }
1150 }
1151
1152 pub(super) fn init_with_states_and_version(
1159 &mut self,
1160 frontiers: Frontiers,
1161 oplog: &OpLog,
1162 unknown_containers: Vec<ContainerIdx>,
1163 need_to_register_parent: bool,
1164 origin: InternalString,
1165 ) -> LoroResult<()> {
1166 self.pre_txn(Default::default(), EventTriggerKind::Import);
1167 if need_to_register_parent {
1168 for state in self.store.iter_and_decode_all() {
1169 let idx = state.container_idx();
1170 let s = state;
1171 for child_id in s.get_child_containers() {
1172 let child_idx = self.arena.register_container(&child_id);
1173 self.arena.set_parent(child_idx, Some(idx));
1174 }
1175 }
1176 }
1177
1178 if !unknown_containers.is_empty() {
1179 let mut diff_calc = DiffCalculator::new(false);
1180 let stack_vv;
1181 let vv = if oplog.frontiers() == &frontiers {
1182 oplog.vv()
1183 } else {
1184 stack_vv = oplog.dag().frontiers_to_vv(&frontiers);
1185 stack_vv.as_ref().unwrap()
1186 };
1187
1188 let (unknown_diffs, _diff_mode) = diff_calc.calc_diff_internal(
1189 oplog,
1190 &Default::default(),
1191 &Default::default(),
1192 vv,
1193 &frontiers,
1194 Some(&|idx| !idx.is_unknown() && unknown_containers.contains(&idx)),
1195 );
1196 self.apply_diff(
1197 InternalDocDiff {
1198 origin: origin.clone(),
1199 by: EventTriggerKind::Import,
1200 diff: unknown_diffs.into(),
1201 new_version: Cow::Owned(frontiers.clone()),
1202 },
1203 DiffMode::Checkout,
1204 )?;
1205 }
1206
1207 if self.is_recording() {
1208 let diff: Vec<_> = self
1209 .store
1210 .iter_all_containers()
1211 .map(|(idx, state)| InternalContainerDiff {
1212 idx,
1213 bring_back: false,
1214 diff: state
1215 .get_state_mut(
1216 idx,
1217 ContainerCreationContext {
1218 configure: &self.config,
1219 peer: self.peer.load(Ordering::Relaxed),
1220 },
1221 )
1222 .to_diff(&self.doc)
1223 .into(),
1224 diff_mode: DiffMode::Checkout,
1225 })
1226 .collect();
1227
1228 self.record_diff(InternalDocDiff {
1229 origin,
1230 by: EventTriggerKind::Import,
1231 diff: diff.into(),
1232 new_version: Cow::Borrowed(&frontiers),
1233 });
1234 }
1235
1236 self.frontiers = frontiers;
1237 Ok(())
1238 }
1239
1240 #[inline(always)]
1241 #[allow(unused)]
1242 pub(crate) fn with_state<F, R>(&mut self, idx: ContainerIdx, f: F) -> R
1243 where
1244 F: FnOnce(&State) -> R,
1245 {
1246 let depth = self.arena.get_depth(idx).unwrap().get() as usize;
1247 let state = self.store.get_or_create_imm(idx);
1248 f(state)
1249 }
1250
1251 #[inline(always)]
1252 pub(crate) fn with_state_mut<F, R>(&mut self, idx: ContainerIdx, f: F) -> R
1253 where
1254 F: FnOnce(&mut State) -> R,
1255 {
1256 let state = self.store.get_or_create_mut(idx);
1257 f(state)
1258 }
1259
1260 pub(super) fn is_in_txn(&self) -> bool {
1261 self.in_txn
1262 }
1263
1264 pub fn can_import_snapshot(&self) -> bool {
1265 !self.in_txn && self.arena.can_import_snapshot() && self.store.can_import_snapshot()
1266 }
1267
1268 pub(crate) fn reset_to_empty_for_failed_snapshot_import(&mut self) {
1269 let was_recording = self.is_recording();
1270 self.frontiers = Frontiers::default();
1271 self.store =
1272 ContainerStore::new(self.arena.clone(), self.config.clone(), self.peer.clone());
1273 self.in_txn = false;
1274 self.changed_idx_in_txn.clear();
1275 self.event_recorder = Default::default();
1276 if was_recording {
1277 self.start_recording();
1278 }
1279 self.dead_containers_cache = Default::default();
1280 self.alive_containers_cache = None;
1281 }
1282
1283 pub fn get_value(&mut self) -> LoroValue {
1284 let roots = self.preferred_root_containers();
1285 let ans: loro_common::LoroMapValue = roots
1286 .into_iter()
1287 .map(|idx| {
1288 let id = self.arena.idx_to_id(idx).unwrap();
1289 let ContainerID::Root {
1290 name,
1291 container_type: _,
1292 } = &id
1293 else {
1294 unreachable!()
1295 };
1296 (name.to_string(), LoroValue::Container(id))
1297 })
1298 .collect();
1299 LoroValue::Map(ans)
1300 }
1301
1302 pub fn get_deep_value(&mut self) -> LoroValue {
1303 let roots = self.preferred_root_containers();
1304 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
1305 let binding = self.config.deleted_root_containers.clone();
1306 let deleted_root_container = binding.lock();
1307 let should_hide_empty_root_container = self
1308 .config
1309 .hide_empty_root_containers
1310 .load(Ordering::Relaxed);
1311 for root_idx in roots {
1312 let id = self.arena.idx_to_id(root_idx).unwrap();
1313 match &id {
1314 loro_common::ContainerID::Root { name, .. } => {
1315 let v = self.get_container_deep_value(root_idx);
1316 if should_hide_empty_root_container
1317 && visible_container_value_is_empty(root_idx.get_type(), &v)
1318 {
1319 continue;
1320 }
1321
1322 if deleted_root_container.contains(&id)
1323 && deleted_root_container_value_is_cleared(root_idx.get_type(), &v)
1324 {
1325 continue;
1326 }
1327
1328 ans.insert(name.to_string(), v);
1329 }
1330 loro_common::ContainerID::Normal { .. } => {
1331 unreachable!()
1332 }
1333 }
1334 }
1335
1336 LoroValue::Map(ans.into())
1337 }
1338
1339 pub fn get_deep_value_with_id(&mut self) -> LoroValue {
1340 let roots = self.preferred_root_containers();
1341 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
1342 for root_idx in roots {
1343 let id = self.arena.idx_to_id(root_idx).unwrap();
1344 match id.clone() {
1345 loro_common::ContainerID::Root { name, .. } => {
1346 ans.insert(
1347 name.to_string(),
1348 self.get_container_deep_value_with_id(root_idx, Some(id)),
1349 );
1350 }
1351 loro_common::ContainerID::Normal { .. } => {
1352 unreachable!()
1353 }
1354 }
1355 }
1356
1357 LoroValue::Map(ans.into())
1358 }
1359
1360 pub(crate) fn preferred_root_containers(&mut self) -> Vec<ContainerIdx> {
1361 let flag = self.store.load_root_containers();
1362 let roots = self.arena.top_level_root_containers(flag);
1366 let mut selected = FxHashMap::default();
1367 let mut names = Vec::new();
1368
1369 for idx in roots {
1370 let Some(id) = self.arena.idx_to_id(idx) else {
1371 continue;
1372 };
1373 if !self.store.contains_id(&id) {
1374 continue;
1375 }
1376 let Some(name) = self.root_container_name(idx) else {
1377 continue;
1378 };
1379 let is_empty = self.root_container_is_empty(idx);
1380 match selected.entry(name.clone()) {
1381 std::collections::hash_map::Entry::Vacant(entry) => {
1382 names.push(name);
1383 entry.insert((idx, is_empty));
1384 }
1385 std::collections::hash_map::Entry::Occupied(mut entry) => {
1386 let (_, selected_is_empty) = entry.get();
1387 if *selected_is_empty || !is_empty {
1390 entry.insert((idx, is_empty));
1391 }
1392 }
1393 }
1394 }
1395
1396 names
1397 .into_iter()
1398 .filter_map(|name| selected.remove(&name).map(|(idx, _)| idx))
1399 .collect()
1400 }
1401
1402 pub(crate) fn preferred_root_container_idx_by_key(
1403 &mut self,
1404 root_index: &InternalString,
1405 ) -> Option<ContainerIdx> {
1406 let flag = self.store.load_root_containers();
1407 let roots = self.arena.top_level_root_containers(flag);
1409 let mut selected = None;
1410
1411 for idx in roots {
1412 let Some(id) = self.arena.idx_to_id(idx) else {
1413 continue;
1414 };
1415 if !self.store.contains_id(&id) {
1416 continue;
1417 }
1418 let Some(name) = self.root_container_name(idx) else {
1419 continue;
1420 };
1421 if &name != root_index {
1422 continue;
1423 }
1424
1425 let is_empty = self.root_container_is_empty(idx);
1426 match selected {
1427 None => selected = Some((idx, is_empty)),
1428 Some((_, selected_is_empty)) => {
1429 if selected_is_empty || !is_empty {
1430 selected = Some((idx, is_empty));
1431 }
1432 }
1433 }
1434 }
1435
1436 selected.map(|(idx, _)| idx)
1437 }
1438
1439 fn root_container_name(&self, idx: ContainerIdx) -> Option<InternalString> {
1440 match self.arena.idx_to_id(idx)? {
1441 ContainerID::Root { name, .. } => Some(name),
1442 ContainerID::Normal { .. } => None,
1443 }
1444 }
1445
1446 fn root_container_is_empty(&mut self, idx: ContainerIdx) -> bool {
1447 let value = self
1448 .store
1449 .get_value_ephemeral(idx)
1450 .unwrap_or_else(|| idx.get_type().default_value());
1451 visible_container_value_is_empty(idx.get_type(), &value)
1452 }
1453
1454 pub fn get_all_container_value_flat(&mut self) -> LoroValue {
1455 let mut map = FxHashMap::default();
1456 self.store.iter_and_decode_all().for_each(|c| {
1457 let value = c.get_value();
1458 let cid = self.arena.idx_to_id(c.container_idx()).unwrap().to_string();
1459 map.insert(cid, value);
1460 });
1461
1462 LoroValue::Map(map.into())
1463 }
1464
1465 pub(crate) fn get_container_deep_value_with_id(
1466 &mut self,
1467 container: ContainerIdx,
1468 id: Option<ContainerID>,
1469 ) -> LoroValue {
1470 let id = id.unwrap_or_else(|| self.arena.idx_to_id(container).unwrap());
1471 let Some(value) = self.store.get_value_ephemeral(container) else {
1472 return container.get_type().default_value();
1473 };
1474 let cid_str = LoroValue::String(id.to_string().into());
1478 match value {
1479 LoroValue::Container(_) => unreachable!(),
1480 LoroValue::List(mut list) => {
1481 if container.get_type() == ContainerType::Tree {
1482 get_meta_value(list.make_mut(), self);
1483 } else {
1484 if list.iter().all(|x| !x.is_container()) {
1485 return LoroValue::Map(
1486 (fx_map!(
1487 "cid".into() => cid_str,
1488 "value".into() => LoroValue::List(list)
1489 ))
1490 .into(),
1491 );
1492 }
1493
1494 let list_mut = list.make_mut();
1495 for item in list_mut.iter_mut() {
1496 if item.is_container() {
1497 let container = item.as_container().unwrap();
1498 let container_idx = self.arena.register_container(container);
1499 let value = self.get_container_deep_value_with_id(
1500 container_idx,
1501 Some(container.clone()),
1502 );
1503 *item = value;
1504 }
1505 }
1506 }
1507 LoroValue::Map(
1508 (fx_map!(
1509 "cid".into() => cid_str,
1510 "value".into() => LoroValue::List(list)
1511 ))
1512 .into(),
1513 )
1514 }
1515 LoroValue::Map(mut map) => {
1516 let mergeable_children = self.mergeable_children_from_value(&id, &map);
1522
1523 let map_mut = map.make_mut();
1524 for (_key, value) in map_mut.iter_mut() {
1525 if value.is_container() {
1526 let container = value.as_container().unwrap();
1527 let container_idx = self.arena.register_container(container);
1528 let new_value = self.get_container_deep_value_with_id(
1529 container_idx,
1530 Some(container.clone()),
1531 );
1532 *value = new_value;
1533 }
1534 }
1535 for (key, cid) in mergeable_children {
1538 let child_idx = self.arena.register_container(&cid);
1539 let new_value = self.get_container_deep_value_with_id(child_idx, Some(cid));
1540 map_mut.insert(key.to_string(), new_value);
1541 }
1542
1543 LoroValue::Map(
1544 (fx_map!(
1545 "cid".into() => cid_str,
1546 "value".into() => LoroValue::Map(map)
1547 ))
1548 .into(),
1549 )
1550 }
1551 _ => LoroValue::Map(
1552 (fx_map!(
1553 "cid".into() => cid_str,
1554 "value".into() => value
1555 ))
1556 .into(),
1557 ),
1558 }
1559 }
1560
1561 pub fn get_container_deep_value(&mut self, container: ContainerIdx) -> LoroValue {
1562 let Some(value) = self.store.get_value_ephemeral(container) else {
1563 return container.get_type().default_value();
1564 };
1565 match value {
1566 LoroValue::Container(_) => unreachable!(),
1567 LoroValue::List(mut list) => {
1568 if container.get_type() == ContainerType::Tree {
1569 get_meta_value(list.make_mut(), self);
1574 } else {
1575 if list.iter().all(|x| !x.is_container()) {
1576 return LoroValue::List(list);
1577 }
1578
1579 let list_mut = list.make_mut();
1580 for item in list_mut.iter_mut() {
1581 if item.is_container() {
1582 let container = item.as_container().unwrap();
1583 let container_idx = self.arena.register_container(container);
1584 let value = self.get_container_deep_value(container_idx);
1585 *item = value;
1586 }
1587 }
1588 }
1589 LoroValue::List(list)
1590 }
1591 LoroValue::Map(mut map) => {
1592 let mergeable_children = self
1598 .arena
1599 .idx_to_id(container)
1600 .map(|parent_id| self.mergeable_children_from_value(&parent_id, &map))
1601 .unwrap_or_default();
1602
1603 if mergeable_children.is_empty() && map.iter().all(|x| !x.1.is_container()) {
1604 return LoroValue::Map(map);
1605 }
1606
1607 let map_mut = map.make_mut();
1608 for (_key, value) in map_mut.iter_mut() {
1609 if value.is_container() {
1610 let container = value.as_container().unwrap();
1611 let container_idx = self.arena.register_container(container);
1612 let new_value = self.get_container_deep_value(container_idx);
1613 *value = new_value;
1614 }
1615 }
1616 for (key, cid) in mergeable_children {
1619 let child_idx = self.arena.register_container(&cid);
1620 let new_value = self.get_container_deep_value(child_idx);
1621 map_mut.insert(key.to_string(), new_value);
1622 }
1623 LoroValue::Map(map)
1624 }
1625 _ => value,
1626 }
1627 }
1628
1629 pub(crate) fn get_list_range_deep_value(
1638 &mut self,
1639 container: ContainerIdx,
1640 start: usize,
1641 end: usize,
1642 with_id: bool,
1643 ) -> LoroValue {
1644 let Some(value) = self.store.get_value_ephemeral(container) else {
1645 return container.get_type().default_value();
1646 };
1647 let LoroValue::List(list) = value else {
1648 return container.get_type().default_value();
1649 };
1650
1651 let len = list.len();
1652 let start = start.min(len);
1653 let end = end.min(len);
1654 if start >= end {
1655 return LoroValue::List(Default::default());
1656 }
1657
1658 let mut ans = Vec::with_capacity(end - start);
1659 for item in list.iter().skip(start).take(end - start) {
1660 if item.is_container() {
1661 let cid = item.as_container().unwrap();
1662 let container_idx = self.arena.register_container(cid);
1663 let value = if with_id {
1664 self.get_container_deep_value_with_id(container_idx, Some(cid.clone()))
1665 } else {
1666 self.get_container_deep_value(container_idx)
1667 };
1668 ans.push(value);
1669 } else {
1670 ans.push(item.clone());
1671 }
1672 }
1673
1674 LoroValue::List(ans.into())
1675 }
1676
1677 pub(crate) fn get_all_alive_containers(&mut self) -> LoroResult<FxHashSet<ContainerID>> {
1678 Ok(self
1679 .get_all_alive_container_indices()?
1680 .into_iter()
1681 .map(|idx| self.arena.get_container_id(idx).unwrap())
1682 .collect())
1683 }
1684
1685 fn get_all_alive_container_indices(&mut self) -> LoroResult<FxHashSet<ContainerIdx>> {
1686 let roots = self.existing_retention_roots();
1687 self.get_all_alive_container_indices_from_roots(&roots)
1688 }
1689
1690 pub(crate) fn existing_retention_roots(&mut self) -> Vec<ContainerIdx> {
1693 let flag = self.store.load_root_containers();
1694 self.arena
1695 .root_containers(flag)
1696 .into_iter()
1697 .filter(|idx| {
1698 let id = self.arena.get_container_id(*idx).unwrap();
1699 self.store.contains_id(&id)
1700 })
1701 .collect()
1702 }
1703
1704 fn get_all_alive_container_indices_from_roots(
1705 &mut self,
1706 roots: &[ContainerIdx],
1707 ) -> LoroResult<FxHashSet<ContainerIdx>> {
1708 let mut ans = FxHashSet::default();
1709 let mut to_visit = Vec::new();
1710 for &idx in roots {
1711 let id = self.arena.get_container_id(idx).unwrap();
1712 let expected_parent = id
1713 .parse_mergeable()
1714 .map(|(parent_id, _, _)| self.arena.register_container(&parent_id));
1715 to_visit.push((idx, expected_parent));
1716 }
1717
1718 while let Some((idx, expected_parent)) = to_visit.pop() {
1719 if !ans.insert(idx) {
1720 self.validate_alive_parent(idx, expected_parent)?;
1724 continue;
1725 }
1726 self.get_alive_children_of(idx, expected_parent, &mut to_visit)?;
1727 }
1728
1729 Ok(ans)
1730 }
1731
1732 fn validate_alive_parent(
1733 &mut self,
1734 child_idx: ContainerIdx,
1735 expected_parent: Option<ContainerIdx>,
1736 ) -> LoroResult<()> {
1737 let encoded_parent = self.store.get_parent_ephemeral(child_idx)?;
1738 self.validate_alive_parent_with_encoded(child_idx, expected_parent, encoded_parent)
1739 }
1740
1741 fn validate_alive_parent_with_encoded(
1742 &mut self,
1743 child_idx: ContainerIdx,
1744 expected_parent: Option<ContainerIdx>,
1745 encoded_parent: Option<Option<ContainerID>>,
1746 ) -> LoroResult<()> {
1747 let child_id = self.arena.get_container_id(child_idx).unwrap();
1748 let expected_parent_id = expected_parent.and_then(|idx| self.arena.get_container_id(idx));
1749 if let Some(encoded_parent) = encoded_parent {
1750 if encoded_parent != expected_parent_id {
1751 return Err(LoroError::DecodeError(
1752 format!(
1753 "container {child_id:?} expects parent {expected_parent_id:?}, but its snapshot state encodes parent {encoded_parent:?}"
1754 )
1755 .into_boxed_str(),
1756 ));
1757 }
1758 }
1759
1760 match self.arena.get_registered_parent(child_idx) {
1761 Some(registered_parent) if registered_parent == expected_parent => {}
1762 Some(registered_parent) => {
1763 let registered_parent =
1764 registered_parent.and_then(|idx| self.arena.get_container_id(idx));
1765 return Err(LoroError::DecodeError(
1766 format!(
1767 "container {child_id:?} expects parent {expected_parent_id:?}, but its registered parent is {registered_parent:?}"
1768 )
1769 .into_boxed_str(),
1770 ));
1771 }
1772 None => self.arena.set_parent(child_idx, expected_parent),
1773 }
1774
1775 Ok(())
1776 }
1777
1778 fn register_alive_child(
1779 &mut self,
1780 parent_idx: ContainerIdx,
1781 child_id: &ContainerID,
1782 ans: &mut Vec<(ContainerIdx, Option<ContainerIdx>)>,
1783 ) {
1784 let child_idx = self.arena.register_container(child_id);
1785 ans.push((child_idx, Some(parent_idx)));
1786 }
1787
1788 fn get_alive_children_of(
1789 &mut self,
1790 idx: ContainerIdx,
1791 expected_parent: Option<ContainerIdx>,
1792 ans: &mut Vec<(ContainerIdx, Option<ContainerIdx>)>,
1793 ) -> LoroResult<()> {
1794 let Some((encoded_parent, value)) = self.store.try_get_parent_and_value_ephemeral(idx)?
1795 else {
1796 self.validate_alive_parent_with_encoded(idx, expected_parent, None)?;
1797 return Ok(());
1798 };
1799 self.validate_alive_parent_with_encoded(idx, expected_parent, Some(encoded_parent))?;
1800
1801 match value {
1802 LoroValue::Container(_) => unreachable!(),
1803 LoroValue::List(list) => {
1804 if idx.get_type() == ContainerType::Tree {
1805 let mut list = list.unwrap();
1810 while let Some(node) = list.pop() {
1811 let map = node.as_map().unwrap();
1812 let meta = map.get("meta").unwrap();
1813 let id = meta.as_container().unwrap();
1814 self.register_alive_child(idx, id, ans);
1815 let children = map.get("children").unwrap();
1816 let children = children.as_list().unwrap();
1817 for child in children.iter() {
1818 list.push(child.clone());
1819 }
1820 }
1821 } else {
1822 for item in list.iter() {
1823 if let LoroValue::Container(id) = item {
1824 self.register_alive_child(idx, id, ans);
1825 }
1826 }
1827 }
1828 }
1829 LoroValue::Map(map) => {
1830 for (_key, value) in map.iter() {
1831 if let LoroValue::Container(id) = value {
1832 self.register_alive_child(idx, id, ans);
1833 }
1834 }
1835 let mergeable_cids: Vec<ContainerID> = self
1843 .arena
1844 .idx_to_id(idx)
1845 .map(|parent_id| {
1846 self.mergeable_children_from_value(&parent_id, &map)
1847 .into_iter()
1848 .map(|(_key, cid)| cid)
1849 .collect()
1850 })
1851 .unwrap_or_default();
1852 for cid in mergeable_cids {
1853 self.register_alive_child(idx, &cid, ans);
1854 }
1855 }
1856 _ => {}
1857 }
1858
1859 Ok(())
1860 }
1861
1862 fn diffs_to_event(&mut self, diffs: Vec<InternalDocDiff<'_>>, from: Frontiers) -> DocDiff {
1865 if diffs.is_empty() {
1866 panic!("diffs is empty");
1867 }
1868
1869 let triggered_by = diffs[0].by;
1870 debug_assert!(diffs.iter().all(|x| x.by == triggered_by));
1871 let mut containers = FxHashMap::default();
1872 let to = (*diffs.last().unwrap().new_version).to_owned();
1873 let origin = diffs[0].origin.clone();
1874 for diff in diffs {
1875 #[allow(clippy::unnecessary_to_owned)]
1876 for container_diff in diff.diff.into_owned() {
1877 let Some((last_container_diff, _)) = containers.get_mut(&container_diff.idx) else {
1878 if let Some(path) = self.get_path(container_diff.idx) {
1879 containers.insert(container_diff.idx, (container_diff.diff, path));
1880 } else {
1881 let _container_id = self
1884 .arena
1885 .idx_to_id(container_diff.idx)
1886 .map(|x| x.to_string())
1887 .unwrap_or_else(|| "unknown".to_string());
1888 #[cfg(feature = "logging")]
1889 loro_common::warn!(
1890 "⚠️ WARNING: ignore event because cannot find its path {:#?} container id:{}",
1891 &container_diff,
1892 _container_id
1893 );
1894 }
1895
1896 continue;
1897 };
1898 let prev = std::mem::take(last_container_diff);
1904 *last_container_diff = prev.compose(container_diff.diff).unwrap();
1905 }
1906 }
1907 let mut diff: Vec<_> = containers
1908 .into_iter()
1909 .map(|(container, (diff, path))| {
1910 let idx = container;
1911 let id = self.arena.get_container_id(idx).unwrap();
1912 let is_unknown = id.is_unknown();
1913
1914 ContainerDiff {
1915 id,
1916 idx,
1917 diff: diff.into_external().unwrap(),
1918 is_unknown,
1919 path,
1920 }
1921 })
1922 .collect();
1923
1924 diff.sort_by_key(|x| {
1928 (
1929 x.path.len(),
1930 match &x.id {
1931 ContainerID::Root { .. } => 0,
1932 ContainerID::Normal { counter, .. } => *counter + 1,
1933 },
1934 )
1935 });
1936 DocDiff {
1937 from,
1938 to,
1939 origin,
1940 by: triggered_by,
1941 diff,
1942 }
1943 }
1944
1945 pub(crate) fn get_reachable(&mut self, id: &ContainerID) -> bool {
1946 if id.is_root() && !id.is_mergeable() {
1947 return true;
1948 }
1949
1950 if self.arena.id_to_idx(id).is_none() {
1954 if !id.is_mergeable() && !self.does_container_exist(id) {
1955 return false;
1956 }
1957 self.arena.register_container(id);
1958 }
1959
1960 let mut idx = self.arena.id_to_idx(id).unwrap();
1961 loop {
1962 let id = self.arena.idx_to_id(idx).unwrap();
1963 if let Some(parent_idx) = self.arena.get_parent(idx) {
1964 if !self.contains_logical_child(parent_idx, &id) {
1965 return false;
1966 }
1967 idx = parent_idx;
1968 } else {
1969 if id.is_root() && !id.is_mergeable() {
1970 return true;
1971 }
1972
1973 return false;
1974 }
1975 }
1976 }
1977
1978 pub(super) fn get_path(&mut self, idx: ContainerIdx) -> Option<Vec<(ContainerID, Index)>> {
1980 let mut ans = Vec::new();
1981 let mut idx = idx;
1982 loop {
1983 let id = self.arena.idx_to_id(idx).unwrap();
1984 if let Some(parent_idx) = self.arena.get_parent(idx) {
1985 let Some(prop) = self.get_logical_child_index(parent_idx, &id) else {
1986 tracing::warn!("Missing in parent's children");
1987 return None;
1988 };
1989 ans.push((id, prop));
1990 idx = parent_idx;
1991 } else {
1992 if id.is_mergeable() {
1994 tracing::info!(id = %id, "Missing parent - mergeable container is inactive");
1995 return None;
1996 }
1997 let Ok(prop) = id.clone().into_root() else {
1998 let id = format!("{}", &id);
1999 tracing::info!(?id, "Missing parent - container is deleted");
2000 return None;
2001 };
2002 ans.push((id, Index::Key(prop.0)));
2003 break;
2004 }
2005 }
2006
2007 ans.reverse();
2008
2009 Some(ans)
2010 }
2011
2012 pub(crate) fn check_before_decode_snapshot(&self) -> LoroResult<()> {
2013 if self.is_in_txn() {
2014 return Err(LoroError::DecodeError(
2015 "State is in txn".to_string().into_boxed_str(),
2016 ));
2017 }
2018
2019 if !self.can_import_snapshot() {
2020 return Err(LoroError::DecodeError(
2021 "State is not empty, cannot import snapshot directly"
2022 .to_string()
2023 .into_boxed_str(),
2024 ));
2025 }
2026
2027 Ok(())
2028 }
2029
2030 pub(crate) fn check_is_the_same(&mut self, other: &mut Self) {
2037 fn get_entries_for_state(
2038 arena: &SharedArena,
2039 state: &mut State,
2040 ) -> Option<(ContainerID, (ContainerIdx, LoroValue))> {
2041 if state.is_state_empty() {
2042 return None;
2043 }
2044
2045 let id = arena.idx_to_id(state.container_idx()).unwrap();
2046 let value = match state {
2047 State::RichtextState(s) => s.get_richtext_value(),
2048 _ => state.get_value(),
2049 };
2050 if match &value {
2051 LoroValue::List(l) => l.is_empty(),
2052 LoroValue::Map(m) => m.is_empty(),
2053 _ => false,
2054 } {
2055 return None;
2056 }
2057 #[cfg(feature = "counter")]
2058 if id.container_type() == ContainerType::Counter {
2059 if let LoroValue::Double(c) = value {
2060 if c.abs() < f64::EPSILON {
2061 return None;
2062 }
2063 }
2064 }
2065
2066 Some((id, (state.container_idx(), value)))
2067 }
2068
2069 let self_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = self
2070 .store
2071 .iter_and_decode_all()
2072 .filter_map(|state: &mut State| {
2073 let arena = &self.arena;
2074 get_entries_for_state(arena, state)
2075 })
2076 .collect();
2077 let mut other_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = other
2078 .store
2079 .iter_and_decode_all()
2080 .filter_map(|state: &mut State| {
2081 let arena = &other.arena;
2082 get_entries_for_state(arena, state)
2083 })
2084 .collect();
2085 for (id, (idx, this_value)) in self_id_to_states {
2086 let (_, other_value) = match other_id_to_states.remove(&id) {
2087 Some(x) => x,
2088 None => {
2089 panic!(
2090 "id: {:?}, path: {:?} is missing, value={:?}",
2091 id,
2092 self.get_path(idx),
2093 &this_value
2094 );
2095 }
2096 };
2097
2098 pretty_assertions::assert_eq!(
2099 this_value,
2100 other_value,
2101 "[self!=other] id: {:?}, path: {:?}",
2102 id,
2103 self.get_path(idx)
2104 );
2105 }
2106
2107 if !other_id_to_states.is_empty() {
2108 panic!("other has more states {:#?}", &other_id_to_states);
2109 }
2110 }
2111
2112 pub fn create_state(&self, idx: ContainerIdx) -> State {
2113 let config = &self.config;
2114 let peer = self.peer.load(std::sync::atomic::Ordering::Relaxed);
2115 create_state_(idx, config, peer)
2116 }
2117
2118 pub fn create_unknown_state(&self, idx: ContainerIdx) -> State {
2119 State::UnknownState(UnknownState::new(idx))
2120 }
2121
2122 pub fn get_relative_position(&mut self, pos: &Cursor, use_event_index: bool) -> Option<usize> {
2123 let idx = self.arena.register_container(&pos.container);
2124 let state = self.store.get_container_mut(idx)?;
2125 if let Some(id) = pos.id {
2126 match state {
2127 State::ListState(s) => s.get_index_of_id(id),
2128 State::RichtextState(s) => s.get_text_index_of_id(id, use_event_index),
2129 State::MovableListState(s) => s.get_index_of_id(id),
2130 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
2131 #[cfg(feature = "counter")]
2132 State::CounterState(_) => unreachable!(),
2133 }
2134 } else {
2135 if matches!(pos.side, crate::cursor::Side::Left) {
2136 return Some(0);
2137 }
2138
2139 match state {
2140 State::ListState(s) => Some(s.len()),
2141 State::RichtextState(s) => Some(if use_event_index {
2142 s.len_event()
2143 } else {
2144 s.len_unicode()
2145 }),
2146 State::MovableListState(s) => Some(s.len()),
2147 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
2148 #[cfg(feature = "counter")]
2149 State::CounterState(_) => unreachable!(),
2150 }
2151 }
2152 }
2153
2154 pub fn get_value_by_path(&mut self, path: &[Index]) -> Option<LoroValue> {
2155 if path.is_empty() {
2156 return None;
2157 }
2158
2159 enum CurContainer {
2160 Container(ContainerIdx),
2161 TreeNode {
2162 tree: ContainerIdx,
2163 node: Option<TreeID>,
2164 },
2165 }
2166
2167 let mut state_idx = {
2168 let root_index = path[0].as_key()?;
2169 CurContainer::Container(self.preferred_root_container_idx_by_key(root_index)?)
2170 };
2171
2172 if path.len() == 1 {
2173 if let CurContainer::Container(c) = state_idx {
2174 let cid = self.arena.idx_to_id(c)?;
2175 return Some(LoroValue::Container(cid));
2176 }
2177 }
2178
2179 let mut i = 1;
2180 while i < path.len() - 1 {
2181 let index = &path[i];
2182 match state_idx {
2183 CurContainer::Container(idx) => {
2184 let parent_id = self.arena.idx_to_id(idx);
2185 let parent_state = self.store.get_container_mut(idx)?;
2186 match parent_state {
2187 State::ListState(l) => {
2188 let Some(LoroValue::Container(c)) = l.get(*index.as_seq()?) else {
2189 return None;
2190 };
2191 state_idx = CurContainer::Container(self.arena.register_container(c));
2192 }
2193 State::MovableListState(l) => {
2194 let Some(LoroValue::Container(c)) =
2195 l.get(*index.as_seq()?, IndexType::ForUser)
2196 else {
2197 return None;
2198 };
2199 state_idx = CurContainer::Container(self.arena.register_container(c));
2200 }
2201 State::MapState(m) => {
2202 let key = index.as_key()?;
2203 let value = m.get(key)?;
2204 let c = match value {
2205 LoroValue::Container(c) => c.clone(),
2206 value => {
2207 let parent_id = parent_id?;
2208 let kind = loro_common::parse_mergeable_marker(
2209 &parent_id, key, value,
2210 )?;
2211 ContainerID::new_mergeable(&parent_id, key, kind)
2212 }
2213 };
2214 state_idx = CurContainer::Container(self.arena.register_container(&c));
2215 }
2216 State::RichtextState(_) => return None,
2217 State::TreeState(_) => {
2218 state_idx = CurContainer::TreeNode {
2219 tree: idx,
2220 node: None,
2221 };
2222 continue;
2223 }
2224 #[cfg(feature = "counter")]
2225 State::CounterState(_) => return None,
2226 State::UnknownState(_) => return None,
2229 }
2230 }
2231 CurContainer::TreeNode { tree, node } => match index {
2232 Index::Key(internal_string) => {
2233 let node = node?;
2234 let idx = self
2235 .arena
2236 .register_container(&node.associated_meta_container());
2237 let map = self.store.get_container(idx)?;
2238 let Some(LoroValue::Container(c)) =
2239 map.as_map_state().unwrap().get(internal_string)
2240 else {
2241 return None;
2242 };
2243
2244 state_idx = CurContainer::Container(self.arena.register_container(c));
2245 }
2246 Index::Seq(i) => {
2247 let tree_state =
2248 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
2249 let parent: TreeParentId = if let Some(node) = node {
2250 node.into()
2251 } else {
2252 TreeParentId::Root
2253 };
2254 let child = tree_state.get_children(&parent)?.nth(*i)?;
2255 state_idx = CurContainer::TreeNode {
2256 tree,
2257 node: Some(child),
2258 };
2259 }
2260 Index::Node(tree_id) => {
2261 let tree_state =
2262 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
2263 if tree_state.parent(tree_id).is_some() {
2264 state_idx = CurContainer::TreeNode {
2265 tree,
2266 node: Some(*tree_id),
2267 }
2268 } else {
2269 return None;
2270 }
2271 }
2272 },
2273 }
2274 i += 1;
2275 }
2276
2277 let parent_idx = match state_idx {
2278 CurContainer::Container(container_idx) => container_idx,
2279 CurContainer::TreeNode { tree, node } => {
2280 if let Some(node) = node {
2281 self.arena
2282 .register_container(&node.associated_meta_container())
2283 } else {
2284 tree
2285 }
2286 }
2287 };
2288
2289 let index = path.last().unwrap();
2290 let parent_id = self.arena.idx_to_id(parent_idx);
2291 let parent_state = self.store.get_or_create_mut(parent_idx);
2292 let value: LoroValue = match parent_state {
2293 State::ListState(l) => l.get(*index.as_seq()?).cloned()?,
2294 State::MovableListState(l) => l.get(*index.as_seq()?, IndexType::ForUser).cloned()?,
2295 State::MapState(m) => {
2296 if let Some(key) = index.as_key() {
2297 let value = m.get(key).cloned()?;
2298 if let Some(parent_id) = &parent_id {
2299 if let Some(kind) =
2300 loro_common::parse_mergeable_marker(parent_id, key, &value)
2301 {
2302 let cid = ContainerID::new_mergeable(parent_id, key, kind);
2303 LoroValue::Container(cid)
2304 } else {
2305 value
2306 }
2307 } else {
2308 value
2309 }
2310 } else if let CurContainer::TreeNode { tree, node } = state_idx {
2311 match index {
2312 Index::Seq(index) => {
2313 let tree_state =
2314 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
2315 let parent: TreeParentId = if let Some(node) = node {
2316 node.into()
2317 } else {
2318 TreeParentId::Root
2319 };
2320 let child = tree_state.get_children(&parent)?.nth(*index)?;
2321 child.associated_meta_container().into()
2322 }
2323 Index::Node(id) => id.associated_meta_container().into(),
2324 _ => return None,
2325 }
2326 } else {
2327 return None;
2328 }
2329 }
2330 State::RichtextState(s) => {
2331 let s = s.to_string_mut();
2332 s.chars()
2333 .nth(*index.as_seq()?)
2334 .map(|c| c.to_string().into())?
2335 }
2336 State::TreeState(_) => {
2337 let id = index.as_node()?;
2338 let cid = id.associated_meta_container();
2339 cid.into()
2340 }
2341 #[cfg(feature = "counter")]
2342 State::CounterState(_) => return None,
2344 State::UnknownState(_) => return None,
2345 };
2346
2347 Some(value)
2348 }
2349
2350 pub(crate) fn shallow_root_store(&self) -> Option<&Arc<GcStore>> {
2351 self.store.shallow_root_store()
2352 }
2353}
2354
2355fn create_state_(idx: ContainerIdx, config: &Configure, peer: u64) -> State {
2356 match idx.get_type() {
2357 ContainerType::Map => State::MapState(Box::new(MapState::new(idx))),
2358 ContainerType::List => State::ListState(Box::new(ListState::new(idx))),
2359 ContainerType::Text => State::RichtextState(Box::new(RichtextState::new(
2360 idx,
2361 config.text_style_config.clone(),
2362 ))),
2363 ContainerType::Tree => State::TreeState(Box::new(TreeState::new(idx, peer))),
2364 ContainerType::MovableList => State::MovableListState(Box::new(MovableListState::new(idx))),
2365 #[cfg(feature = "counter")]
2366 ContainerType::Counter => {
2367 State::CounterState(Box::new(counter_state::CounterState::new(idx)))
2368 }
2369 ContainerType::Unknown(_) => State::UnknownState(UnknownState::new(idx)),
2370 }
2371}
2372
2373fn trigger_on_new_container(
2374 state_diff: &Diff,
2375 mut listener: impl FnMut(ContainerIdx),
2376 arena: &SharedArena,
2377) {
2378 match state_diff {
2379 Diff::List(list) => {
2380 for delta in list.iter() {
2381 if let DeltaItem::Replace {
2382 value,
2383 attr,
2384 delete: _,
2385 } = delta
2386 {
2387 if attr.from_move {
2388 continue;
2389 }
2390
2391 for v in value.iter() {
2392 if let ValueOrHandler::Handler(h) = v {
2393 let idx = h.container_idx();
2394 listener(idx);
2395 }
2396 }
2397 }
2398 }
2399 }
2400 Diff::Map(map) => {
2401 for (_, v) in map.updated.iter() {
2402 if let Some(ValueOrHandler::Handler(h)) = &v.value {
2403 let idx = h.container_idx();
2404 listener(idx);
2405 }
2406 }
2407 }
2408 Diff::Tree(tree) => {
2409 for item in tree.iter() {
2410 if matches!(item.action, TreeExternalDiff::Create { .. }) {
2411 let id = item.target.associated_meta_container();
2412 listener(arena.register_container(&id));
2414 }
2415 }
2416 }
2417 _ => {}
2418 };
2419}
2420
2421#[derive(Default, Clone)]
2422struct EventRecorder {
2423 recording_diff: bool,
2424 diffs: Vec<InternalDocDiff<'static>>,
2427 events: Vec<DocDiff>,
2428 diff_start_version: Option<Frontiers>,
2429}
2430
2431impl EventRecorder {
2432 #[allow(unused)]
2433 pub fn new() -> Self {
2434 Self::default()
2435 }
2436}
2437
2438#[test]
2439fn test_size() {
2440 println!("Size of State = {}", std::mem::size_of::<State>());
2441 println!("Size of MapState = {}", std::mem::size_of::<MapState>());
2442 println!("Size of ListState = {}", std::mem::size_of::<ListState>());
2443 println!(
2444 "Size of TextState = {}",
2445 std::mem::size_of::<RichtextState>()
2446 );
2447 println!("Size of TreeState = {}", std::mem::size_of::<TreeState>());
2448}