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