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, PosType},
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 if self.store.contains_id(id) {
890 return true;
891 }
892
893 is_mergeable && self.get_reachable(id)
896 }
897
898 pub(crate) fn commit_txn(&mut self, new_frontiers: Frontiers, diff: Option<InternalDocDiff>) {
899 self.in_txn = false;
900 self.frontiers = new_frontiers;
901 if let Some(diff) = diff {
902 if self.is_recording() {
903 self.record_diff(diff);
904 }
905 }
906 }
907
908 #[inline]
910 pub(crate) fn ensure_container(&mut self, id: &ContainerID) {
911 self.store.ensure_container(id);
912 }
913
914 pub(crate) fn ensure_all_alive_containers(&mut self) -> FxHashSet<ContainerID> {
916 let ans = self.get_all_alive_containers();
919 for id in ans.iter() {
920 self.ensure_container(id);
921 }
922
923 ans
924 }
925
926 pub(crate) fn get_value_by_idx(&mut self, container_idx: ContainerIdx) -> LoroValue {
927 self.store
928 .get_value(container_idx)
929 .unwrap_or_else(|| container_idx.get_type().default_value())
930 }
931
932 pub(crate) fn get_map_value_by_key(
933 &mut self,
934 container_idx: ContainerIdx,
935 key: &str,
936 ) -> Option<LoroValue> {
937 self.store.map_get(container_idx, key)
938 }
939
940 pub(crate) fn get_map_len(&mut self, container_idx: ContainerIdx) -> usize {
941 self.store.map_len(container_idx)
942 }
943
944 pub(crate) fn get_map_keys(&mut self, container_idx: ContainerIdx) -> Vec<InternalString> {
945 self.store.map_keys(container_idx)
946 }
947
948 pub(crate) fn get_map_entries(
949 &mut self,
950 container_idx: ContainerIdx,
951 ) -> Vec<(InternalString, LoroValue)> {
952 self.store.map_entries(container_idx)
953 }
954
955 pub(crate) fn get_list_value_at(
956 &mut self,
957 container_idx: ContainerIdx,
958 index: usize,
959 ) -> Option<LoroValue> {
960 self.store.list_get(container_idx, index)
961 }
962
963 pub(crate) fn get_list_len(&mut self, container_idx: ContainerIdx) -> usize {
964 self.store.list_len(container_idx)
965 }
966
967 pub(crate) fn get_list_values(&mut self, container_idx: ContainerIdx) -> Vec<LoroValue> {
968 self.store.list_values(container_idx)
969 }
970
971 pub(crate) fn get_text_unicode_len(&mut self, container_idx: ContainerIdx) -> usize {
972 self.store.text_unicode_len(container_idx).unwrap_or(0)
973 }
974
975 pub(crate) fn get_text_utf16_len(&mut self, container_idx: ContainerIdx) -> usize {
976 self.store.text_utf16_len(container_idx).unwrap_or(0)
977 }
978
979 pub(crate) fn get_text_utf8_len(&mut self, container_idx: ContainerIdx) -> usize {
980 self.store.text_utf8_len(container_idx).unwrap_or(0)
981 }
982
983 pub(crate) fn has_decoded_container_state(&mut self, container_idx: ContainerIdx) -> bool {
984 self.store.has_decoded_state(container_idx)
985 }
986
987 pub(crate) fn get_text_len(&mut self, container_idx: ContainerIdx, pos_type: PosType) -> usize {
998 match pos_type {
999 PosType::Unicode => self.get_text_unicode_len(container_idx),
1000 PosType::Utf16 => self.get_text_utf16_len(container_idx),
1001 PosType::Event if cfg!(feature = "wasm") => self.get_text_utf16_len(container_idx),
1002 PosType::Event => self.get_text_unicode_len(container_idx),
1003 PosType::Bytes => self.get_text_utf8_len(container_idx),
1004 PosType::Entity => self.with_state_mut(container_idx, |state| {
1005 state.as_richtext_state_mut().unwrap().len(PosType::Entity)
1006 }),
1007 }
1008 }
1009
1010 pub(super) fn init_with_states_and_version(
1017 &mut self,
1018 frontiers: Frontiers,
1019 oplog: &OpLog,
1020 unknown_containers: Vec<ContainerIdx>,
1021 need_to_register_parent: bool,
1022 origin: InternalString,
1023 ) -> LoroResult<()> {
1024 self.pre_txn(Default::default(), EventTriggerKind::Import);
1025 if need_to_register_parent {
1026 for state in self.store.iter_and_decode_all() {
1027 let idx = state.container_idx();
1028 let s = state;
1029 for child_id in s.get_child_containers() {
1030 let child_idx = self.arena.register_container(&child_id);
1031 self.arena.set_parent(child_idx, Some(idx));
1032 }
1033 }
1034 }
1035
1036 if !unknown_containers.is_empty() {
1037 let mut diff_calc = DiffCalculator::new(false);
1038 let stack_vv;
1039 let vv = if oplog.frontiers() == &frontiers {
1040 oplog.vv()
1041 } else {
1042 stack_vv = oplog.dag().frontiers_to_vv(&frontiers);
1043 stack_vv.as_ref().unwrap()
1044 };
1045
1046 let (unknown_diffs, _diff_mode) = diff_calc.calc_diff_internal(
1047 oplog,
1048 &Default::default(),
1049 &Default::default(),
1050 vv,
1051 &frontiers,
1052 Some(&|idx| !idx.is_unknown() && unknown_containers.contains(&idx)),
1053 );
1054 self.apply_diff(
1055 InternalDocDiff {
1056 origin: origin.clone(),
1057 by: EventTriggerKind::Import,
1058 diff: unknown_diffs.into(),
1059 new_version: Cow::Owned(frontiers.clone()),
1060 },
1061 DiffMode::Checkout,
1062 )?;
1063 }
1064
1065 if self.is_recording() {
1066 let diff: Vec<_> = self
1067 .store
1068 .iter_all_containers()
1069 .map(|(idx, state)| InternalContainerDiff {
1070 idx,
1071 bring_back: false,
1072 diff: state
1073 .get_state_mut(
1074 idx,
1075 ContainerCreationContext {
1076 configure: &self.config,
1077 peer: self.peer.load(Ordering::Relaxed),
1078 },
1079 )
1080 .to_diff(&self.doc)
1081 .into(),
1082 diff_mode: DiffMode::Checkout,
1083 })
1084 .collect();
1085
1086 self.record_diff(InternalDocDiff {
1087 origin,
1088 by: EventTriggerKind::Import,
1089 diff: diff.into(),
1090 new_version: Cow::Borrowed(&frontiers),
1091 });
1092 }
1093
1094 self.frontiers = frontiers;
1095 Ok(())
1096 }
1097
1098 #[inline(always)]
1099 #[allow(unused)]
1100 pub(crate) fn with_state<F, R>(&mut self, idx: ContainerIdx, f: F) -> R
1101 where
1102 F: FnOnce(&State) -> R,
1103 {
1104 let depth = self.arena.get_depth(idx).unwrap().get() as usize;
1105 let state = self.store.get_or_create_imm(idx);
1106 f(state)
1107 }
1108
1109 #[inline(always)]
1110 pub(crate) fn with_state_mut<F, R>(&mut self, idx: ContainerIdx, f: F) -> R
1111 where
1112 F: FnOnce(&mut State) -> R,
1113 {
1114 let state = self.store.get_or_create_mut(idx);
1115 f(state)
1116 }
1117
1118 pub(super) fn is_in_txn(&self) -> bool {
1119 self.in_txn
1120 }
1121
1122 pub fn can_import_snapshot(&self) -> bool {
1123 !self.in_txn && self.arena.can_import_snapshot() && self.store.can_import_snapshot()
1124 }
1125
1126 pub(crate) fn reset_to_empty_for_failed_snapshot_import(&mut self) {
1127 self.frontiers = Frontiers::default();
1128 self.store =
1129 ContainerStore::new(self.arena.clone(), self.config.clone(), self.peer.clone());
1130 self.in_txn = false;
1131 self.changed_idx_in_txn.clear();
1132 self.event_recorder = Default::default();
1133 self.dead_containers_cache = Default::default();
1134 }
1135
1136 pub fn get_value(&mut self) -> LoroValue {
1137 let roots = self.preferred_root_containers();
1138 let ans: loro_common::LoroMapValue = roots
1139 .into_iter()
1140 .map(|idx| {
1141 let id = self.arena.idx_to_id(idx).unwrap();
1142 let ContainerID::Root {
1143 name,
1144 container_type: _,
1145 } = &id
1146 else {
1147 unreachable!()
1148 };
1149 (name.to_string(), LoroValue::Container(id))
1150 })
1151 .collect();
1152 LoroValue::Map(ans)
1153 }
1154
1155 pub fn get_deep_value(&mut self) -> LoroValue {
1156 let roots = self.preferred_root_containers();
1157 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
1158 let binding = self.config.deleted_root_containers.clone();
1159 let deleted_root_container = binding.lock();
1160 let should_hide_empty_root_container = self
1161 .config
1162 .hide_empty_root_containers
1163 .load(Ordering::Relaxed);
1164 for root_idx in roots {
1165 let id = self.arena.idx_to_id(root_idx).unwrap();
1166 match &id {
1167 loro_common::ContainerID::Root { name, .. } => {
1168 let v = self.get_container_deep_value(root_idx);
1169 if should_hide_empty_root_container
1170 && visible_container_value_is_empty(root_idx.get_type(), &v)
1171 {
1172 continue;
1173 }
1174
1175 if deleted_root_container.contains(&id)
1176 && deleted_root_container_value_is_cleared(root_idx.get_type(), &v)
1177 {
1178 continue;
1179 }
1180
1181 ans.insert(name.to_string(), v);
1182 }
1183 loro_common::ContainerID::Normal { .. } => {
1184 unreachable!()
1185 }
1186 }
1187 }
1188
1189 LoroValue::Map(ans.into())
1190 }
1191
1192 pub fn get_deep_value_with_id(&mut self) -> LoroValue {
1193 let roots = self.preferred_root_containers();
1194 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
1195 for root_idx in roots {
1196 let id = self.arena.idx_to_id(root_idx).unwrap();
1197 match id.clone() {
1198 loro_common::ContainerID::Root { name, .. } => {
1199 ans.insert(
1200 name.to_string(),
1201 self.get_container_deep_value_with_id(root_idx, Some(id)),
1202 );
1203 }
1204 loro_common::ContainerID::Normal { .. } => {
1205 unreachable!()
1206 }
1207 }
1208 }
1209
1210 LoroValue::Map(ans.into())
1211 }
1212
1213 pub(crate) fn preferred_root_containers(&mut self) -> Vec<ContainerIdx> {
1214 let flag = self.store.load_root_containers();
1215 let roots = self.arena.top_level_root_containers(flag);
1219 let mut selected = FxHashMap::default();
1220 let mut names = Vec::new();
1221
1222 for idx in roots {
1223 let Some(id) = self.arena.idx_to_id(idx) else {
1224 continue;
1225 };
1226 if !self.store.contains_id(&id) {
1227 continue;
1228 }
1229 let Some(name) = self.root_container_name(idx) else {
1230 continue;
1231 };
1232 let is_empty = self.root_container_is_empty(idx);
1233 match selected.entry(name.clone()) {
1234 std::collections::hash_map::Entry::Vacant(entry) => {
1235 names.push(name);
1236 entry.insert((idx, is_empty));
1237 }
1238 std::collections::hash_map::Entry::Occupied(mut entry) => {
1239 let (_, selected_is_empty) = entry.get();
1240 if *selected_is_empty || !is_empty {
1243 entry.insert((idx, is_empty));
1244 }
1245 }
1246 }
1247 }
1248
1249 names
1250 .into_iter()
1251 .filter_map(|name| selected.remove(&name).map(|(idx, _)| idx))
1252 .collect()
1253 }
1254
1255 pub(crate) fn preferred_root_container_idx_by_key(
1256 &mut self,
1257 root_index: &InternalString,
1258 ) -> Option<ContainerIdx> {
1259 let flag = self.store.load_root_containers();
1260 let roots = self.arena.top_level_root_containers(flag);
1262 let mut selected = None;
1263
1264 for idx in roots {
1265 let Some(id) = self.arena.idx_to_id(idx) else {
1266 continue;
1267 };
1268 if !self.store.contains_id(&id) {
1269 continue;
1270 }
1271 let Some(name) = self.root_container_name(idx) else {
1272 continue;
1273 };
1274 if &name != root_index {
1275 continue;
1276 }
1277
1278 let is_empty = self.root_container_is_empty(idx);
1279 match selected {
1280 None => selected = Some((idx, is_empty)),
1281 Some((_, selected_is_empty)) => {
1282 if selected_is_empty || !is_empty {
1283 selected = Some((idx, is_empty));
1284 }
1285 }
1286 }
1287 }
1288
1289 selected.map(|(idx, _)| idx)
1290 }
1291
1292 fn root_container_name(&self, idx: ContainerIdx) -> Option<InternalString> {
1293 match self.arena.idx_to_id(idx)? {
1294 ContainerID::Root { name, .. } => Some(name),
1295 ContainerID::Normal { .. } => None,
1296 }
1297 }
1298
1299 fn root_container_is_empty(&mut self, idx: ContainerIdx) -> bool {
1300 let value = self
1301 .store
1302 .get_value(idx)
1303 .unwrap_or_else(|| idx.get_type().default_value());
1304 visible_container_value_is_empty(idx.get_type(), &value)
1305 }
1306
1307 pub fn get_all_container_value_flat(&mut self) -> LoroValue {
1308 let mut map = FxHashMap::default();
1309 self.store.iter_and_decode_all().for_each(|c| {
1310 let value = c.get_value();
1311 let cid = self.arena.idx_to_id(c.container_idx()).unwrap().to_string();
1312 map.insert(cid, value);
1313 });
1314
1315 LoroValue::Map(map.into())
1316 }
1317
1318 pub(crate) fn get_container_deep_value_with_id(
1319 &mut self,
1320 container: ContainerIdx,
1321 id: Option<ContainerID>,
1322 ) -> LoroValue {
1323 let id = id.unwrap_or_else(|| self.arena.idx_to_id(container).unwrap());
1324 let Some(value) = self.store.get_value(container) else {
1325 return container.get_type().default_value();
1326 };
1327 let cid_str = LoroValue::String(format!("idx:{}, id:{}", container.to_index(), id).into());
1328 match value {
1329 LoroValue::Container(_) => unreachable!(),
1330 LoroValue::List(mut list) => {
1331 if container.get_type() == ContainerType::Tree {
1332 get_meta_value(list.make_mut(), self);
1333 } else {
1334 if list.iter().all(|x| !x.is_container()) {
1335 return LoroValue::Map(
1336 (fx_map!(
1337 "cid".into() => cid_str,
1338 "value".into() => LoroValue::List(list)
1339 ))
1340 .into(),
1341 );
1342 }
1343
1344 let list_mut = list.make_mut();
1345 for item in list_mut.iter_mut() {
1346 if item.is_container() {
1347 let container = item.as_container().unwrap();
1348 let container_idx = self.arena.register_container(container);
1349 let value = self.get_container_deep_value_with_id(
1350 container_idx,
1351 Some(container.clone()),
1352 );
1353 *item = value;
1354 }
1355 }
1356 }
1357 LoroValue::Map(
1358 (fx_map!(
1359 "cid".into() => cid_str,
1360 "value".into() => LoroValue::List(list)
1361 ))
1362 .into(),
1363 )
1364 }
1365 LoroValue::Map(mut map) => {
1366 let mergeable_children = self.mergeable_children_from_value(&id, &map);
1372
1373 let map_mut = map.make_mut();
1374 for (_key, value) in map_mut.iter_mut() {
1375 if value.is_container() {
1376 let container = value.as_container().unwrap();
1377 let container_idx = self.arena.register_container(container);
1378 let new_value = self.get_container_deep_value_with_id(
1379 container_idx,
1380 Some(container.clone()),
1381 );
1382 *value = new_value;
1383 }
1384 }
1385 for (key, cid) in mergeable_children {
1388 let child_idx = self.arena.register_container(&cid);
1389 let new_value = self.get_container_deep_value_with_id(child_idx, Some(cid));
1390 map_mut.insert(key.to_string(), new_value);
1391 }
1392
1393 LoroValue::Map(
1394 (fx_map!(
1395 "cid".into() => cid_str,
1396 "value".into() => LoroValue::Map(map)
1397 ))
1398 .into(),
1399 )
1400 }
1401 _ => LoroValue::Map(
1402 (fx_map!(
1403 "cid".into() => cid_str,
1404 "value".into() => value
1405 ))
1406 .into(),
1407 ),
1408 }
1409 }
1410
1411 pub fn get_container_deep_value(&mut self, container: ContainerIdx) -> LoroValue {
1412 let Some(value) = self.store.get_value(container) else {
1413 return container.get_type().default_value();
1414 };
1415 match value {
1416 LoroValue::Container(_) => unreachable!(),
1417 LoroValue::List(mut list) => {
1418 if container.get_type() == ContainerType::Tree {
1419 get_meta_value(list.make_mut(), self);
1424 } else {
1425 if list.iter().all(|x| !x.is_container()) {
1426 return LoroValue::List(list);
1427 }
1428
1429 let list_mut = list.make_mut();
1430 for item in list_mut.iter_mut() {
1431 if item.is_container() {
1432 let container = item.as_container().unwrap();
1433 let container_idx = self.arena.register_container(container);
1434 let value = self.get_container_deep_value(container_idx);
1435 *item = value;
1436 }
1437 }
1438 }
1439 LoroValue::List(list)
1440 }
1441 LoroValue::Map(mut map) => {
1442 let mergeable_children = self
1448 .arena
1449 .idx_to_id(container)
1450 .map(|parent_id| self.mergeable_children_from_value(&parent_id, &map))
1451 .unwrap_or_default();
1452
1453 if mergeable_children.is_empty() && map.iter().all(|x| !x.1.is_container()) {
1454 return LoroValue::Map(map);
1455 }
1456
1457 let map_mut = map.make_mut();
1458 for (_key, value) in map_mut.iter_mut() {
1459 if value.is_container() {
1460 let container = value.as_container().unwrap();
1461 let container_idx = self.arena.register_container(container);
1462 let new_value = self.get_container_deep_value(container_idx);
1463 *value = new_value;
1464 }
1465 }
1466 for (key, cid) in mergeable_children {
1469 let child_idx = self.arena.register_container(&cid);
1470 let new_value = self.get_container_deep_value(child_idx);
1471 map_mut.insert(key.to_string(), new_value);
1472 }
1473 LoroValue::Map(map)
1474 }
1475 _ => value,
1476 }
1477 }
1478
1479 pub(crate) fn get_all_alive_containers(&mut self) -> FxHashSet<ContainerID> {
1480 let flag = self.store.load_all();
1481 let mut ans = FxHashSet::default();
1482 let mut to_visit = self
1483 .arena
1484 .root_containers(flag)
1485 .iter()
1486 .map(|x| self.arena.get_container_id(*x).unwrap())
1487 .filter(|id| self.store.contains_id(id))
1488 .collect_vec();
1489
1490 while let Some(id) = to_visit.pop() {
1491 self.get_alive_children_of(&id, &mut to_visit);
1492 ans.insert(id);
1493 }
1494
1495 ans
1496 }
1497
1498 pub(crate) fn get_alive_children_of(&mut self, id: &ContainerID, ans: &mut Vec<ContainerID>) {
1499 let idx = self.arena.register_container(id);
1500 let Some(value) = self.store.get_value(idx) else {
1501 return;
1502 };
1503
1504 match value {
1505 LoroValue::Container(_) => unreachable!(),
1506 LoroValue::List(list) => {
1507 if idx.get_type() == ContainerType::Tree {
1508 let mut list = list.unwrap();
1513 while let Some(node) = list.pop() {
1514 let map = node.as_map().unwrap();
1515 let meta = map.get("meta").unwrap();
1516 let id = meta.as_container().unwrap();
1517 ans.push(id.clone());
1518 let children = map.get("children").unwrap();
1519 let children = children.as_list().unwrap();
1520 for child in children.iter() {
1521 list.push(child.clone());
1522 }
1523 }
1524 } else {
1525 for item in list.iter() {
1526 if let LoroValue::Container(id) = item {
1527 ans.push(id.clone());
1528 }
1529 }
1530 }
1531 }
1532 LoroValue::Map(map) => {
1533 for (_key, value) in map.iter() {
1534 if let LoroValue::Container(id) = value {
1535 ans.push(id.clone());
1536 }
1537 }
1538 let mergeable_cids: Vec<ContainerID> = self
1546 .arena
1547 .idx_to_id(idx)
1548 .map(|parent_id| {
1549 self.mergeable_children_from_value(&parent_id, &map)
1550 .into_iter()
1551 .map(|(_key, cid)| cid)
1552 .collect()
1553 })
1554 .unwrap_or_default();
1555 for cid in mergeable_cids {
1556 self.arena.register_container(&cid);
1557 ans.push(cid);
1558 }
1559 }
1560 _ => {}
1561 }
1562 }
1563
1564 fn diffs_to_event(&mut self, diffs: Vec<InternalDocDiff<'_>>, from: Frontiers) -> DocDiff {
1567 if diffs.is_empty() {
1568 panic!("diffs is empty");
1569 }
1570
1571 let triggered_by = diffs[0].by;
1572 debug_assert!(diffs.iter().all(|x| x.by == triggered_by));
1573 let mut containers = FxHashMap::default();
1574 let to = (*diffs.last().unwrap().new_version).to_owned();
1575 let origin = diffs[0].origin.clone();
1576 for diff in diffs {
1577 #[allow(clippy::unnecessary_to_owned)]
1578 for container_diff in diff.diff.into_owned() {
1579 let Some((last_container_diff, _)) = containers.get_mut(&container_diff.idx) else {
1580 if let Some(path) = self.get_path(container_diff.idx) {
1581 containers.insert(container_diff.idx, (container_diff.diff, path));
1582 } else {
1583 let _container_id = self
1586 .arena
1587 .idx_to_id(container_diff.idx)
1588 .map(|x| x.to_string())
1589 .unwrap_or_else(|| "unknown".to_string());
1590 #[cfg(feature = "logging")]
1591 loro_common::warn!(
1592 "⚠️ WARNING: ignore event because cannot find its path {:#?} container id:{}",
1593 &container_diff,
1594 _container_id
1595 );
1596 }
1597
1598 continue;
1599 };
1600 let prev = std::mem::take(last_container_diff);
1606 *last_container_diff = prev.compose(container_diff.diff).unwrap();
1607 }
1608 }
1609 let mut diff: Vec<_> = containers
1610 .into_iter()
1611 .map(|(container, (diff, path))| {
1612 let idx = container;
1613 let id = self.arena.get_container_id(idx).unwrap();
1614 let is_unknown = id.is_unknown();
1615
1616 ContainerDiff {
1617 id,
1618 idx,
1619 diff: diff.into_external().unwrap(),
1620 is_unknown,
1621 path,
1622 }
1623 })
1624 .collect();
1625
1626 diff.sort_by_key(|x| {
1630 (
1631 x.path.len(),
1632 match &x.id {
1633 ContainerID::Root { .. } => 0,
1634 ContainerID::Normal { counter, .. } => *counter + 1,
1635 },
1636 )
1637 });
1638 DocDiff {
1639 from,
1640 to,
1641 origin,
1642 by: triggered_by,
1643 diff,
1644 }
1645 }
1646
1647 pub(crate) fn get_reachable(&mut self, id: &ContainerID) -> bool {
1648 if id.is_root() && !id.is_mergeable() {
1649 return true;
1650 }
1651
1652 if self.arena.id_to_idx(id).is_none() {
1656 if !id.is_mergeable() && !self.does_container_exist(id) {
1657 return false;
1658 }
1659 self.arena.register_container(id);
1660 }
1661
1662 let mut idx = self.arena.id_to_idx(id).unwrap();
1663 loop {
1664 let id = self.arena.idx_to_id(idx).unwrap();
1665 if let Some(parent_idx) = self.arena.get_parent(idx) {
1666 if !self.contains_logical_child(parent_idx, &id) {
1667 return false;
1668 }
1669 idx = parent_idx;
1670 } else {
1671 if id.is_root() && !id.is_mergeable() {
1672 return true;
1673 }
1674
1675 return false;
1676 }
1677 }
1678 }
1679
1680 pub(super) fn get_path(&mut self, idx: ContainerIdx) -> Option<Vec<(ContainerID, Index)>> {
1682 let mut ans = Vec::new();
1683 let mut idx = idx;
1684 loop {
1685 let id = self.arena.idx_to_id(idx).unwrap();
1686 if let Some(parent_idx) = self.arena.get_parent(idx) {
1687 let Some(prop) = self.get_logical_child_index(parent_idx, &id) else {
1688 tracing::warn!("Missing in parent's children");
1689 return None;
1690 };
1691 ans.push((id, prop));
1692 idx = parent_idx;
1693 } else {
1694 if id.is_mergeable() {
1696 tracing::info!(id = %id, "Missing parent - mergeable container is inactive");
1697 return None;
1698 }
1699 let Ok(prop) = id.clone().into_root() else {
1700 let id = format!("{}", &id);
1701 tracing::info!(?id, "Missing parent - container is deleted");
1702 return None;
1703 };
1704 ans.push((id, Index::Key(prop.0)));
1705 break;
1706 }
1707 }
1708
1709 ans.reverse();
1710
1711 Some(ans)
1712 }
1713
1714 pub(crate) fn check_before_decode_snapshot(&self) -> LoroResult<()> {
1715 if self.is_in_txn() {
1716 return Err(LoroError::DecodeError(
1717 "State is in txn".to_string().into_boxed_str(),
1718 ));
1719 }
1720
1721 if !self.can_import_snapshot() {
1722 return Err(LoroError::DecodeError(
1723 "State is not empty, cannot import snapshot directly"
1724 .to_string()
1725 .into_boxed_str(),
1726 ));
1727 }
1728
1729 Ok(())
1730 }
1731
1732 pub(crate) fn check_is_the_same(&mut self, other: &mut Self) {
1739 fn get_entries_for_state(
1740 arena: &SharedArena,
1741 state: &mut State,
1742 ) -> Option<(ContainerID, (ContainerIdx, LoroValue))> {
1743 if state.is_state_empty() {
1744 return None;
1745 }
1746
1747 let id = arena.idx_to_id(state.container_idx()).unwrap();
1748 let value = match state {
1749 State::RichtextState(s) => s.get_richtext_value(),
1750 _ => state.get_value(),
1751 };
1752 if match &value {
1753 LoroValue::List(l) => l.is_empty(),
1754 LoroValue::Map(m) => m.is_empty(),
1755 _ => false,
1756 } {
1757 return None;
1758 }
1759 #[cfg(feature = "counter")]
1760 if id.container_type() == ContainerType::Counter {
1761 if let LoroValue::Double(c) = value {
1762 if c.abs() < f64::EPSILON {
1763 return None;
1764 }
1765 }
1766 }
1767
1768 Some((id, (state.container_idx(), value)))
1769 }
1770
1771 let self_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = self
1772 .store
1773 .iter_and_decode_all()
1774 .filter_map(|state: &mut State| {
1775 let arena = &self.arena;
1776 get_entries_for_state(arena, state)
1777 })
1778 .collect();
1779 let mut other_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = other
1780 .store
1781 .iter_and_decode_all()
1782 .filter_map(|state: &mut State| {
1783 let arena = &other.arena;
1784 get_entries_for_state(arena, state)
1785 })
1786 .collect();
1787 for (id, (idx, this_value)) in self_id_to_states {
1788 let (_, other_value) = match other_id_to_states.remove(&id) {
1789 Some(x) => x,
1790 None => {
1791 panic!(
1792 "id: {:?}, path: {:?} is missing, value={:?}",
1793 id,
1794 self.get_path(idx),
1795 &this_value
1796 );
1797 }
1798 };
1799
1800 pretty_assertions::assert_eq!(
1801 this_value,
1802 other_value,
1803 "[self!=other] id: {:?}, path: {:?}",
1804 id,
1805 self.get_path(idx)
1806 );
1807 }
1808
1809 if !other_id_to_states.is_empty() {
1810 panic!("other has more states {:#?}", &other_id_to_states);
1811 }
1812 }
1813
1814 pub fn create_state(&self, idx: ContainerIdx) -> State {
1815 let config = &self.config;
1816 let peer = self.peer.load(std::sync::atomic::Ordering::Relaxed);
1817 create_state_(idx, config, peer)
1818 }
1819
1820 pub fn create_unknown_state(&self, idx: ContainerIdx) -> State {
1821 State::UnknownState(UnknownState::new(idx))
1822 }
1823
1824 pub fn get_relative_position(&mut self, pos: &Cursor, use_event_index: bool) -> Option<usize> {
1825 let idx = self.arena.register_container(&pos.container);
1826 let state = self.store.get_container_mut(idx)?;
1827 if let Some(id) = pos.id {
1828 match state {
1829 State::ListState(s) => s.get_index_of_id(id),
1830 State::RichtextState(s) => s.get_text_index_of_id(id, use_event_index),
1831 State::MovableListState(s) => s.get_index_of_id(id),
1832 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
1833 #[cfg(feature = "counter")]
1834 State::CounterState(_) => unreachable!(),
1835 }
1836 } else {
1837 if matches!(pos.side, crate::cursor::Side::Left) {
1838 return Some(0);
1839 }
1840
1841 match state {
1842 State::ListState(s) => Some(s.len()),
1843 State::RichtextState(s) => Some(if use_event_index {
1844 s.len_event()
1845 } else {
1846 s.len_unicode()
1847 }),
1848 State::MovableListState(s) => Some(s.len()),
1849 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
1850 #[cfg(feature = "counter")]
1851 State::CounterState(_) => unreachable!(),
1852 }
1853 }
1854 }
1855
1856 pub fn get_value_by_path(&mut self, path: &[Index]) -> Option<LoroValue> {
1857 if path.is_empty() {
1858 return None;
1859 }
1860
1861 enum CurContainer {
1862 Container(ContainerIdx),
1863 TreeNode {
1864 tree: ContainerIdx,
1865 node: Option<TreeID>,
1866 },
1867 }
1868
1869 let mut state_idx = {
1870 let root_index = path[0].as_key()?;
1871 CurContainer::Container(self.preferred_root_container_idx_by_key(root_index)?)
1872 };
1873
1874 if path.len() == 1 {
1875 if let CurContainer::Container(c) = state_idx {
1876 let cid = self.arena.idx_to_id(c)?;
1877 return Some(LoroValue::Container(cid));
1878 }
1879 }
1880
1881 let mut i = 1;
1882 while i < path.len() - 1 {
1883 let index = &path[i];
1884 match state_idx {
1885 CurContainer::Container(idx) => {
1886 let parent_id = self.arena.idx_to_id(idx);
1887 let parent_state = self.store.get_container_mut(idx)?;
1888 match parent_state {
1889 State::ListState(l) => {
1890 let Some(LoroValue::Container(c)) = l.get(*index.as_seq()?) else {
1891 return None;
1892 };
1893 state_idx = CurContainer::Container(self.arena.register_container(c));
1894 }
1895 State::MovableListState(l) => {
1896 let Some(LoroValue::Container(c)) =
1897 l.get(*index.as_seq()?, IndexType::ForUser)
1898 else {
1899 return None;
1900 };
1901 state_idx = CurContainer::Container(self.arena.register_container(c));
1902 }
1903 State::MapState(m) => {
1904 let key = index.as_key()?;
1905 let value = m.get(key)?;
1906 let c = match value {
1907 LoroValue::Container(c) => c.clone(),
1908 value => {
1909 let parent_id = parent_id?;
1910 let kind = loro_common::parse_mergeable_marker(
1911 &parent_id, key, value,
1912 )?;
1913 ContainerID::new_mergeable(&parent_id, key, kind)
1914 }
1915 };
1916 state_idx = CurContainer::Container(self.arena.register_container(&c));
1917 }
1918 State::RichtextState(_) => return None,
1919 State::TreeState(_) => {
1920 state_idx = CurContainer::TreeNode {
1921 tree: idx,
1922 node: None,
1923 };
1924 continue;
1925 }
1926 #[cfg(feature = "counter")]
1927 State::CounterState(_) => return None,
1928 State::UnknownState(_) => unreachable!(),
1929 }
1930 }
1931 CurContainer::TreeNode { tree, node } => match index {
1932 Index::Key(internal_string) => {
1933 let node = node?;
1934 let idx = self
1935 .arena
1936 .register_container(&node.associated_meta_container());
1937 let map = self.store.get_container(idx)?;
1938 let Some(LoroValue::Container(c)) =
1939 map.as_map_state().unwrap().get(internal_string)
1940 else {
1941 return None;
1942 };
1943
1944 state_idx = CurContainer::Container(self.arena.register_container(c));
1945 }
1946 Index::Seq(i) => {
1947 let tree_state =
1948 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1949 let parent: TreeParentId = if let Some(node) = node {
1950 node.into()
1951 } else {
1952 TreeParentId::Root
1953 };
1954 let child = tree_state.get_children(&parent)?.nth(*i)?;
1955 state_idx = CurContainer::TreeNode {
1956 tree,
1957 node: Some(child),
1958 };
1959 }
1960 Index::Node(tree_id) => {
1961 let tree_state =
1962 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1963 if tree_state.parent(tree_id).is_some() {
1964 state_idx = CurContainer::TreeNode {
1965 tree,
1966 node: Some(*tree_id),
1967 }
1968 } else {
1969 return None;
1970 }
1971 }
1972 },
1973 }
1974 i += 1;
1975 }
1976
1977 let parent_idx = match state_idx {
1978 CurContainer::Container(container_idx) => container_idx,
1979 CurContainer::TreeNode { tree, node } => {
1980 if let Some(node) = node {
1981 self.arena
1982 .register_container(&node.associated_meta_container())
1983 } else {
1984 tree
1985 }
1986 }
1987 };
1988
1989 let index = path.last().unwrap();
1990 let parent_id = self.arena.idx_to_id(parent_idx);
1991 let parent_state = self.store.get_or_create_mut(parent_idx);
1992 let value: LoroValue = match parent_state {
1993 State::ListState(l) => l.get(*index.as_seq()?).cloned()?,
1994 State::MovableListState(l) => l.get(*index.as_seq()?, IndexType::ForUser).cloned()?,
1995 State::MapState(m) => {
1996 if let Some(key) = index.as_key() {
1997 let value = m.get(key).cloned()?;
1998 if let Some(parent_id) = &parent_id {
1999 if let Some(kind) =
2000 loro_common::parse_mergeable_marker(parent_id, key, &value)
2001 {
2002 let cid = ContainerID::new_mergeable(parent_id, key, kind);
2003 LoroValue::Container(cid)
2004 } else {
2005 value
2006 }
2007 } else {
2008 value
2009 }
2010 } else if let CurContainer::TreeNode { tree, node } = state_idx {
2011 match index {
2012 Index::Seq(index) => {
2013 let tree_state =
2014 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
2015 let parent: TreeParentId = if let Some(node) = node {
2016 node.into()
2017 } else {
2018 TreeParentId::Root
2019 };
2020 let child = tree_state.get_children(&parent)?.nth(*index)?;
2021 child.associated_meta_container().into()
2022 }
2023 Index::Node(id) => id.associated_meta_container().into(),
2024 _ => return None,
2025 }
2026 } else {
2027 return None;
2028 }
2029 }
2030 State::RichtextState(s) => {
2031 let s = s.to_string_mut();
2032 s.chars()
2033 .nth(*index.as_seq()?)
2034 .map(|c| c.to_string().into())?
2035 }
2036 State::TreeState(_) => {
2037 let id = index.as_node()?;
2038 let cid = id.associated_meta_container();
2039 cid.into()
2040 }
2041 #[cfg(feature = "counter")]
2042 State::CounterState(_) => unreachable!(),
2043 State::UnknownState(_) => unreachable!(),
2044 };
2045
2046 Some(value)
2047 }
2048
2049 pub(crate) fn shallow_root_store(&self) -> Option<&Arc<GcStore>> {
2050 self.store.shallow_root_store()
2051 }
2052}
2053
2054fn create_state_(idx: ContainerIdx, config: &Configure, peer: u64) -> State {
2055 match idx.get_type() {
2056 ContainerType::Map => State::MapState(Box::new(MapState::new(idx))),
2057 ContainerType::List => State::ListState(Box::new(ListState::new(idx))),
2058 ContainerType::Text => State::RichtextState(Box::new(RichtextState::new(
2059 idx,
2060 config.text_style_config.clone(),
2061 ))),
2062 ContainerType::Tree => State::TreeState(Box::new(TreeState::new(idx, peer))),
2063 ContainerType::MovableList => State::MovableListState(Box::new(MovableListState::new(idx))),
2064 #[cfg(feature = "counter")]
2065 ContainerType::Counter => {
2066 State::CounterState(Box::new(counter_state::CounterState::new(idx)))
2067 }
2068 ContainerType::Unknown(_) => State::UnknownState(UnknownState::new(idx)),
2069 }
2070}
2071
2072fn trigger_on_new_container(
2073 state_diff: &Diff,
2074 mut listener: impl FnMut(ContainerIdx),
2075 arena: &SharedArena,
2076) {
2077 match state_diff {
2078 Diff::List(list) => {
2079 for delta in list.iter() {
2080 if let DeltaItem::Replace {
2081 value,
2082 attr,
2083 delete: _,
2084 } = delta
2085 {
2086 if attr.from_move {
2087 continue;
2088 }
2089
2090 for v in value.iter() {
2091 if let ValueOrHandler::Handler(h) = v {
2092 let idx = h.container_idx();
2093 listener(idx);
2094 }
2095 }
2096 }
2097 }
2098 }
2099 Diff::Map(map) => {
2100 for (_, v) in map.updated.iter() {
2101 if let Some(ValueOrHandler::Handler(h)) = &v.value {
2102 let idx = h.container_idx();
2103 listener(idx);
2104 }
2105 }
2106 }
2107 Diff::Tree(tree) => {
2108 for item in tree.iter() {
2109 if matches!(item.action, TreeExternalDiff::Create { .. }) {
2110 let id = item.target.associated_meta_container();
2111 listener(arena.register_container(&id));
2113 }
2114 }
2115 }
2116 _ => {}
2117 };
2118}
2119
2120#[derive(Default, Clone)]
2121struct EventRecorder {
2122 recording_diff: bool,
2123 diffs: Vec<InternalDocDiff<'static>>,
2126 events: Vec<DocDiff>,
2127 diff_start_version: Option<Frontiers>,
2128}
2129
2130impl EventRecorder {
2131 #[allow(unused)]
2132 pub fn new() -> Self {
2133 Self::default()
2134 }
2135}
2136
2137#[test]
2138fn test_size() {
2139 println!("Size of State = {}", std::mem::size_of::<State>());
2140 println!("Size of MapState = {}", std::mem::size_of::<MapState>());
2141 println!("Size of ListState = {}", std::mem::size_of::<ListState>());
2142 println!(
2143 "Size of TextState = {}",
2144 std::mem::size_of::<RichtextState>()
2145 );
2146 println!("Size of TreeState = {}", std::mem::size_of::<TreeState>());
2147}