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