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 let was_recording = self.is_recording();
1128 self.frontiers = Frontiers::default();
1129 self.store =
1130 ContainerStore::new(self.arena.clone(), self.config.clone(), self.peer.clone());
1131 self.in_txn = false;
1132 self.changed_idx_in_txn.clear();
1133 self.event_recorder = Default::default();
1134 if was_recording {
1135 self.start_recording();
1136 }
1137 self.dead_containers_cache = Default::default();
1138 }
1139
1140 pub fn get_value(&mut self) -> LoroValue {
1141 let roots = self.preferred_root_containers();
1142 let ans: loro_common::LoroMapValue = roots
1143 .into_iter()
1144 .map(|idx| {
1145 let id = self.arena.idx_to_id(idx).unwrap();
1146 let ContainerID::Root {
1147 name,
1148 container_type: _,
1149 } = &id
1150 else {
1151 unreachable!()
1152 };
1153 (name.to_string(), LoroValue::Container(id))
1154 })
1155 .collect();
1156 LoroValue::Map(ans)
1157 }
1158
1159 pub fn get_deep_value(&mut self) -> LoroValue {
1160 let roots = self.preferred_root_containers();
1161 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
1162 let binding = self.config.deleted_root_containers.clone();
1163 let deleted_root_container = binding.lock();
1164 let should_hide_empty_root_container = self
1165 .config
1166 .hide_empty_root_containers
1167 .load(Ordering::Relaxed);
1168 for root_idx in roots {
1169 let id = self.arena.idx_to_id(root_idx).unwrap();
1170 match &id {
1171 loro_common::ContainerID::Root { name, .. } => {
1172 let v = self.get_container_deep_value(root_idx);
1173 if should_hide_empty_root_container
1174 && visible_container_value_is_empty(root_idx.get_type(), &v)
1175 {
1176 continue;
1177 }
1178
1179 if deleted_root_container.contains(&id)
1180 && deleted_root_container_value_is_cleared(root_idx.get_type(), &v)
1181 {
1182 continue;
1183 }
1184
1185 ans.insert(name.to_string(), v);
1186 }
1187 loro_common::ContainerID::Normal { .. } => {
1188 unreachable!()
1189 }
1190 }
1191 }
1192
1193 LoroValue::Map(ans.into())
1194 }
1195
1196 pub fn get_deep_value_with_id(&mut self) -> LoroValue {
1197 let roots = self.preferred_root_containers();
1198 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
1199 for root_idx in roots {
1200 let id = self.arena.idx_to_id(root_idx).unwrap();
1201 match id.clone() {
1202 loro_common::ContainerID::Root { name, .. } => {
1203 ans.insert(
1204 name.to_string(),
1205 self.get_container_deep_value_with_id(root_idx, Some(id)),
1206 );
1207 }
1208 loro_common::ContainerID::Normal { .. } => {
1209 unreachable!()
1210 }
1211 }
1212 }
1213
1214 LoroValue::Map(ans.into())
1215 }
1216
1217 pub(crate) fn preferred_root_containers(&mut self) -> Vec<ContainerIdx> {
1218 let flag = self.store.load_root_containers();
1219 let roots = self.arena.top_level_root_containers(flag);
1223 let mut selected = FxHashMap::default();
1224 let mut names = Vec::new();
1225
1226 for idx in roots {
1227 let Some(id) = self.arena.idx_to_id(idx) else {
1228 continue;
1229 };
1230 if !self.store.contains_id(&id) {
1231 continue;
1232 }
1233 let Some(name) = self.root_container_name(idx) else {
1234 continue;
1235 };
1236 let is_empty = self.root_container_is_empty(idx);
1237 match selected.entry(name.clone()) {
1238 std::collections::hash_map::Entry::Vacant(entry) => {
1239 names.push(name);
1240 entry.insert((idx, is_empty));
1241 }
1242 std::collections::hash_map::Entry::Occupied(mut entry) => {
1243 let (_, selected_is_empty) = entry.get();
1244 if *selected_is_empty || !is_empty {
1247 entry.insert((idx, is_empty));
1248 }
1249 }
1250 }
1251 }
1252
1253 names
1254 .into_iter()
1255 .filter_map(|name| selected.remove(&name).map(|(idx, _)| idx))
1256 .collect()
1257 }
1258
1259 pub(crate) fn preferred_root_container_idx_by_key(
1260 &mut self,
1261 root_index: &InternalString,
1262 ) -> Option<ContainerIdx> {
1263 let flag = self.store.load_root_containers();
1264 let roots = self.arena.top_level_root_containers(flag);
1266 let mut selected = None;
1267
1268 for idx in roots {
1269 let Some(id) = self.arena.idx_to_id(idx) else {
1270 continue;
1271 };
1272 if !self.store.contains_id(&id) {
1273 continue;
1274 }
1275 let Some(name) = self.root_container_name(idx) else {
1276 continue;
1277 };
1278 if &name != root_index {
1279 continue;
1280 }
1281
1282 let is_empty = self.root_container_is_empty(idx);
1283 match selected {
1284 None => selected = Some((idx, is_empty)),
1285 Some((_, selected_is_empty)) => {
1286 if selected_is_empty || !is_empty {
1287 selected = Some((idx, is_empty));
1288 }
1289 }
1290 }
1291 }
1292
1293 selected.map(|(idx, _)| idx)
1294 }
1295
1296 fn root_container_name(&self, idx: ContainerIdx) -> Option<InternalString> {
1297 match self.arena.idx_to_id(idx)? {
1298 ContainerID::Root { name, .. } => Some(name),
1299 ContainerID::Normal { .. } => None,
1300 }
1301 }
1302
1303 fn root_container_is_empty(&mut self, idx: ContainerIdx) -> bool {
1304 let value = self
1305 .store
1306 .get_value(idx)
1307 .unwrap_or_else(|| idx.get_type().default_value());
1308 visible_container_value_is_empty(idx.get_type(), &value)
1309 }
1310
1311 pub fn get_all_container_value_flat(&mut self) -> LoroValue {
1312 let mut map = FxHashMap::default();
1313 self.store.iter_and_decode_all().for_each(|c| {
1314 let value = c.get_value();
1315 let cid = self.arena.idx_to_id(c.container_idx()).unwrap().to_string();
1316 map.insert(cid, value);
1317 });
1318
1319 LoroValue::Map(map.into())
1320 }
1321
1322 pub(crate) fn get_container_deep_value_with_id(
1323 &mut self,
1324 container: ContainerIdx,
1325 id: Option<ContainerID>,
1326 ) -> LoroValue {
1327 let id = id.unwrap_or_else(|| self.arena.idx_to_id(container).unwrap());
1328 let Some(value) = self.store.get_value(container) else {
1329 return container.get_type().default_value();
1330 };
1331 let cid_str = LoroValue::String(format!("idx:{}, id:{}", container.to_index(), id).into());
1332 match value {
1333 LoroValue::Container(_) => unreachable!(),
1334 LoroValue::List(mut list) => {
1335 if container.get_type() == ContainerType::Tree {
1336 get_meta_value(list.make_mut(), self);
1337 } else {
1338 if list.iter().all(|x| !x.is_container()) {
1339 return LoroValue::Map(
1340 (fx_map!(
1341 "cid".into() => cid_str,
1342 "value".into() => LoroValue::List(list)
1343 ))
1344 .into(),
1345 );
1346 }
1347
1348 let list_mut = list.make_mut();
1349 for item in list_mut.iter_mut() {
1350 if item.is_container() {
1351 let container = item.as_container().unwrap();
1352 let container_idx = self.arena.register_container(container);
1353 let value = self.get_container_deep_value_with_id(
1354 container_idx,
1355 Some(container.clone()),
1356 );
1357 *item = value;
1358 }
1359 }
1360 }
1361 LoroValue::Map(
1362 (fx_map!(
1363 "cid".into() => cid_str,
1364 "value".into() => LoroValue::List(list)
1365 ))
1366 .into(),
1367 )
1368 }
1369 LoroValue::Map(mut map) => {
1370 let mergeable_children = self.mergeable_children_from_value(&id, &map);
1376
1377 let map_mut = map.make_mut();
1378 for (_key, value) in map_mut.iter_mut() {
1379 if value.is_container() {
1380 let container = value.as_container().unwrap();
1381 let container_idx = self.arena.register_container(container);
1382 let new_value = self.get_container_deep_value_with_id(
1383 container_idx,
1384 Some(container.clone()),
1385 );
1386 *value = new_value;
1387 }
1388 }
1389 for (key, cid) in mergeable_children {
1392 let child_idx = self.arena.register_container(&cid);
1393 let new_value = self.get_container_deep_value_with_id(child_idx, Some(cid));
1394 map_mut.insert(key.to_string(), new_value);
1395 }
1396
1397 LoroValue::Map(
1398 (fx_map!(
1399 "cid".into() => cid_str,
1400 "value".into() => LoroValue::Map(map)
1401 ))
1402 .into(),
1403 )
1404 }
1405 _ => LoroValue::Map(
1406 (fx_map!(
1407 "cid".into() => cid_str,
1408 "value".into() => value
1409 ))
1410 .into(),
1411 ),
1412 }
1413 }
1414
1415 pub fn get_container_deep_value(&mut self, container: ContainerIdx) -> LoroValue {
1416 let Some(value) = self.store.get_value(container) else {
1417 return container.get_type().default_value();
1418 };
1419 match value {
1420 LoroValue::Container(_) => unreachable!(),
1421 LoroValue::List(mut list) => {
1422 if container.get_type() == ContainerType::Tree {
1423 get_meta_value(list.make_mut(), self);
1428 } else {
1429 if list.iter().all(|x| !x.is_container()) {
1430 return LoroValue::List(list);
1431 }
1432
1433 let list_mut = list.make_mut();
1434 for item in list_mut.iter_mut() {
1435 if item.is_container() {
1436 let container = item.as_container().unwrap();
1437 let container_idx = self.arena.register_container(container);
1438 let value = self.get_container_deep_value(container_idx);
1439 *item = value;
1440 }
1441 }
1442 }
1443 LoroValue::List(list)
1444 }
1445 LoroValue::Map(mut map) => {
1446 let mergeable_children = self
1452 .arena
1453 .idx_to_id(container)
1454 .map(|parent_id| self.mergeable_children_from_value(&parent_id, &map))
1455 .unwrap_or_default();
1456
1457 if mergeable_children.is_empty() && map.iter().all(|x| !x.1.is_container()) {
1458 return LoroValue::Map(map);
1459 }
1460
1461 let map_mut = map.make_mut();
1462 for (_key, value) in map_mut.iter_mut() {
1463 if value.is_container() {
1464 let container = value.as_container().unwrap();
1465 let container_idx = self.arena.register_container(container);
1466 let new_value = self.get_container_deep_value(container_idx);
1467 *value = new_value;
1468 }
1469 }
1470 for (key, cid) in mergeable_children {
1473 let child_idx = self.arena.register_container(&cid);
1474 let new_value = self.get_container_deep_value(child_idx);
1475 map_mut.insert(key.to_string(), new_value);
1476 }
1477 LoroValue::Map(map)
1478 }
1479 _ => value,
1480 }
1481 }
1482
1483 pub(crate) fn get_all_alive_containers(&mut self) -> FxHashSet<ContainerID> {
1484 let flag = self.store.load_all();
1485 let mut ans = FxHashSet::default();
1486 let mut to_visit = self
1487 .arena
1488 .root_containers(flag)
1489 .iter()
1490 .map(|x| self.arena.get_container_id(*x).unwrap())
1491 .filter(|id| self.store.contains_id(id))
1492 .collect_vec();
1493
1494 while let Some(id) = to_visit.pop() {
1495 self.get_alive_children_of(&id, &mut to_visit);
1496 ans.insert(id);
1497 }
1498
1499 ans
1500 }
1501
1502 pub(crate) fn get_alive_children_of(&mut self, id: &ContainerID, ans: &mut Vec<ContainerID>) {
1503 let idx = self.arena.register_container(id);
1504 let Some(value) = self.store.get_value(idx) else {
1505 return;
1506 };
1507
1508 match value {
1509 LoroValue::Container(_) => unreachable!(),
1510 LoroValue::List(list) => {
1511 if idx.get_type() == ContainerType::Tree {
1512 let mut list = list.unwrap();
1517 while let Some(node) = list.pop() {
1518 let map = node.as_map().unwrap();
1519 let meta = map.get("meta").unwrap();
1520 let id = meta.as_container().unwrap();
1521 ans.push(id.clone());
1522 let children = map.get("children").unwrap();
1523 let children = children.as_list().unwrap();
1524 for child in children.iter() {
1525 list.push(child.clone());
1526 }
1527 }
1528 } else {
1529 for item in list.iter() {
1530 if let LoroValue::Container(id) = item {
1531 ans.push(id.clone());
1532 }
1533 }
1534 }
1535 }
1536 LoroValue::Map(map) => {
1537 for (_key, value) in map.iter() {
1538 if let LoroValue::Container(id) = value {
1539 ans.push(id.clone());
1540 }
1541 }
1542 let mergeable_cids: Vec<ContainerID> = self
1550 .arena
1551 .idx_to_id(idx)
1552 .map(|parent_id| {
1553 self.mergeable_children_from_value(&parent_id, &map)
1554 .into_iter()
1555 .map(|(_key, cid)| cid)
1556 .collect()
1557 })
1558 .unwrap_or_default();
1559 for cid in mergeable_cids {
1560 self.arena.register_container(&cid);
1561 ans.push(cid);
1562 }
1563 }
1564 _ => {}
1565 }
1566 }
1567
1568 fn diffs_to_event(&mut self, diffs: Vec<InternalDocDiff<'_>>, from: Frontiers) -> DocDiff {
1571 if diffs.is_empty() {
1572 panic!("diffs is empty");
1573 }
1574
1575 let triggered_by = diffs[0].by;
1576 debug_assert!(diffs.iter().all(|x| x.by == triggered_by));
1577 let mut containers = FxHashMap::default();
1578 let to = (*diffs.last().unwrap().new_version).to_owned();
1579 let origin = diffs[0].origin.clone();
1580 for diff in diffs {
1581 #[allow(clippy::unnecessary_to_owned)]
1582 for container_diff in diff.diff.into_owned() {
1583 let Some((last_container_diff, _)) = containers.get_mut(&container_diff.idx) else {
1584 if let Some(path) = self.get_path(container_diff.idx) {
1585 containers.insert(container_diff.idx, (container_diff.diff, path));
1586 } else {
1587 let _container_id = self
1590 .arena
1591 .idx_to_id(container_diff.idx)
1592 .map(|x| x.to_string())
1593 .unwrap_or_else(|| "unknown".to_string());
1594 #[cfg(feature = "logging")]
1595 loro_common::warn!(
1596 "⚠️ WARNING: ignore event because cannot find its path {:#?} container id:{}",
1597 &container_diff,
1598 _container_id
1599 );
1600 }
1601
1602 continue;
1603 };
1604 let prev = std::mem::take(last_container_diff);
1610 *last_container_diff = prev.compose(container_diff.diff).unwrap();
1611 }
1612 }
1613 let mut diff: Vec<_> = containers
1614 .into_iter()
1615 .map(|(container, (diff, path))| {
1616 let idx = container;
1617 let id = self.arena.get_container_id(idx).unwrap();
1618 let is_unknown = id.is_unknown();
1619
1620 ContainerDiff {
1621 id,
1622 idx,
1623 diff: diff.into_external().unwrap(),
1624 is_unknown,
1625 path,
1626 }
1627 })
1628 .collect();
1629
1630 diff.sort_by_key(|x| {
1634 (
1635 x.path.len(),
1636 match &x.id {
1637 ContainerID::Root { .. } => 0,
1638 ContainerID::Normal { counter, .. } => *counter + 1,
1639 },
1640 )
1641 });
1642 DocDiff {
1643 from,
1644 to,
1645 origin,
1646 by: triggered_by,
1647 diff,
1648 }
1649 }
1650
1651 pub(crate) fn get_reachable(&mut self, id: &ContainerID) -> bool {
1652 if id.is_root() && !id.is_mergeable() {
1653 return true;
1654 }
1655
1656 if self.arena.id_to_idx(id).is_none() {
1660 if !id.is_mergeable() && !self.does_container_exist(id) {
1661 return false;
1662 }
1663 self.arena.register_container(id);
1664 }
1665
1666 let mut idx = self.arena.id_to_idx(id).unwrap();
1667 loop {
1668 let id = self.arena.idx_to_id(idx).unwrap();
1669 if let Some(parent_idx) = self.arena.get_parent(idx) {
1670 if !self.contains_logical_child(parent_idx, &id) {
1671 return false;
1672 }
1673 idx = parent_idx;
1674 } else {
1675 if id.is_root() && !id.is_mergeable() {
1676 return true;
1677 }
1678
1679 return false;
1680 }
1681 }
1682 }
1683
1684 pub(super) fn get_path(&mut self, idx: ContainerIdx) -> Option<Vec<(ContainerID, Index)>> {
1686 let mut ans = Vec::new();
1687 let mut idx = idx;
1688 loop {
1689 let id = self.arena.idx_to_id(idx).unwrap();
1690 if let Some(parent_idx) = self.arena.get_parent(idx) {
1691 let Some(prop) = self.get_logical_child_index(parent_idx, &id) else {
1692 tracing::warn!("Missing in parent's children");
1693 return None;
1694 };
1695 ans.push((id, prop));
1696 idx = parent_idx;
1697 } else {
1698 if id.is_mergeable() {
1700 tracing::info!(id = %id, "Missing parent - mergeable container is inactive");
1701 return None;
1702 }
1703 let Ok(prop) = id.clone().into_root() else {
1704 let id = format!("{}", &id);
1705 tracing::info!(?id, "Missing parent - container is deleted");
1706 return None;
1707 };
1708 ans.push((id, Index::Key(prop.0)));
1709 break;
1710 }
1711 }
1712
1713 ans.reverse();
1714
1715 Some(ans)
1716 }
1717
1718 pub(crate) fn check_before_decode_snapshot(&self) -> LoroResult<()> {
1719 if self.is_in_txn() {
1720 return Err(LoroError::DecodeError(
1721 "State is in txn".to_string().into_boxed_str(),
1722 ));
1723 }
1724
1725 if !self.can_import_snapshot() {
1726 return Err(LoroError::DecodeError(
1727 "State is not empty, cannot import snapshot directly"
1728 .to_string()
1729 .into_boxed_str(),
1730 ));
1731 }
1732
1733 Ok(())
1734 }
1735
1736 pub(crate) fn check_is_the_same(&mut self, other: &mut Self) {
1743 fn get_entries_for_state(
1744 arena: &SharedArena,
1745 state: &mut State,
1746 ) -> Option<(ContainerID, (ContainerIdx, LoroValue))> {
1747 if state.is_state_empty() {
1748 return None;
1749 }
1750
1751 let id = arena.idx_to_id(state.container_idx()).unwrap();
1752 let value = match state {
1753 State::RichtextState(s) => s.get_richtext_value(),
1754 _ => state.get_value(),
1755 };
1756 if match &value {
1757 LoroValue::List(l) => l.is_empty(),
1758 LoroValue::Map(m) => m.is_empty(),
1759 _ => false,
1760 } {
1761 return None;
1762 }
1763 #[cfg(feature = "counter")]
1764 if id.container_type() == ContainerType::Counter {
1765 if let LoroValue::Double(c) = value {
1766 if c.abs() < f64::EPSILON {
1767 return None;
1768 }
1769 }
1770 }
1771
1772 Some((id, (state.container_idx(), value)))
1773 }
1774
1775 let self_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = self
1776 .store
1777 .iter_and_decode_all()
1778 .filter_map(|state: &mut State| {
1779 let arena = &self.arena;
1780 get_entries_for_state(arena, state)
1781 })
1782 .collect();
1783 let mut other_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = other
1784 .store
1785 .iter_and_decode_all()
1786 .filter_map(|state: &mut State| {
1787 let arena = &other.arena;
1788 get_entries_for_state(arena, state)
1789 })
1790 .collect();
1791 for (id, (idx, this_value)) in self_id_to_states {
1792 let (_, other_value) = match other_id_to_states.remove(&id) {
1793 Some(x) => x,
1794 None => {
1795 panic!(
1796 "id: {:?}, path: {:?} is missing, value={:?}",
1797 id,
1798 self.get_path(idx),
1799 &this_value
1800 );
1801 }
1802 };
1803
1804 pretty_assertions::assert_eq!(
1805 this_value,
1806 other_value,
1807 "[self!=other] id: {:?}, path: {:?}",
1808 id,
1809 self.get_path(idx)
1810 );
1811 }
1812
1813 if !other_id_to_states.is_empty() {
1814 panic!("other has more states {:#?}", &other_id_to_states);
1815 }
1816 }
1817
1818 pub fn create_state(&self, idx: ContainerIdx) -> State {
1819 let config = &self.config;
1820 let peer = self.peer.load(std::sync::atomic::Ordering::Relaxed);
1821 create_state_(idx, config, peer)
1822 }
1823
1824 pub fn create_unknown_state(&self, idx: ContainerIdx) -> State {
1825 State::UnknownState(UnknownState::new(idx))
1826 }
1827
1828 pub fn get_relative_position(&mut self, pos: &Cursor, use_event_index: bool) -> Option<usize> {
1829 let idx = self.arena.register_container(&pos.container);
1830 let state = self.store.get_container_mut(idx)?;
1831 if let Some(id) = pos.id {
1832 match state {
1833 State::ListState(s) => s.get_index_of_id(id),
1834 State::RichtextState(s) => s.get_text_index_of_id(id, use_event_index),
1835 State::MovableListState(s) => s.get_index_of_id(id),
1836 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
1837 #[cfg(feature = "counter")]
1838 State::CounterState(_) => unreachable!(),
1839 }
1840 } else {
1841 if matches!(pos.side, crate::cursor::Side::Left) {
1842 return Some(0);
1843 }
1844
1845 match state {
1846 State::ListState(s) => Some(s.len()),
1847 State::RichtextState(s) => Some(if use_event_index {
1848 s.len_event()
1849 } else {
1850 s.len_unicode()
1851 }),
1852 State::MovableListState(s) => Some(s.len()),
1853 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
1854 #[cfg(feature = "counter")]
1855 State::CounterState(_) => unreachable!(),
1856 }
1857 }
1858 }
1859
1860 pub fn get_value_by_path(&mut self, path: &[Index]) -> Option<LoroValue> {
1861 if path.is_empty() {
1862 return None;
1863 }
1864
1865 enum CurContainer {
1866 Container(ContainerIdx),
1867 TreeNode {
1868 tree: ContainerIdx,
1869 node: Option<TreeID>,
1870 },
1871 }
1872
1873 let mut state_idx = {
1874 let root_index = path[0].as_key()?;
1875 CurContainer::Container(self.preferred_root_container_idx_by_key(root_index)?)
1876 };
1877
1878 if path.len() == 1 {
1879 if let CurContainer::Container(c) = state_idx {
1880 let cid = self.arena.idx_to_id(c)?;
1881 return Some(LoroValue::Container(cid));
1882 }
1883 }
1884
1885 let mut i = 1;
1886 while i < path.len() - 1 {
1887 let index = &path[i];
1888 match state_idx {
1889 CurContainer::Container(idx) => {
1890 let parent_id = self.arena.idx_to_id(idx);
1891 let parent_state = self.store.get_container_mut(idx)?;
1892 match parent_state {
1893 State::ListState(l) => {
1894 let Some(LoroValue::Container(c)) = l.get(*index.as_seq()?) else {
1895 return None;
1896 };
1897 state_idx = CurContainer::Container(self.arena.register_container(c));
1898 }
1899 State::MovableListState(l) => {
1900 let Some(LoroValue::Container(c)) =
1901 l.get(*index.as_seq()?, IndexType::ForUser)
1902 else {
1903 return None;
1904 };
1905 state_idx = CurContainer::Container(self.arena.register_container(c));
1906 }
1907 State::MapState(m) => {
1908 let key = index.as_key()?;
1909 let value = m.get(key)?;
1910 let c = match value {
1911 LoroValue::Container(c) => c.clone(),
1912 value => {
1913 let parent_id = parent_id?;
1914 let kind = loro_common::parse_mergeable_marker(
1915 &parent_id, key, value,
1916 )?;
1917 ContainerID::new_mergeable(&parent_id, key, kind)
1918 }
1919 };
1920 state_idx = CurContainer::Container(self.arena.register_container(&c));
1921 }
1922 State::RichtextState(_) => return None,
1923 State::TreeState(_) => {
1924 state_idx = CurContainer::TreeNode {
1925 tree: idx,
1926 node: None,
1927 };
1928 continue;
1929 }
1930 #[cfg(feature = "counter")]
1931 State::CounterState(_) => return None,
1932 State::UnknownState(_) => unreachable!(),
1933 }
1934 }
1935 CurContainer::TreeNode { tree, node } => match index {
1936 Index::Key(internal_string) => {
1937 let node = node?;
1938 let idx = self
1939 .arena
1940 .register_container(&node.associated_meta_container());
1941 let map = self.store.get_container(idx)?;
1942 let Some(LoroValue::Container(c)) =
1943 map.as_map_state().unwrap().get(internal_string)
1944 else {
1945 return None;
1946 };
1947
1948 state_idx = CurContainer::Container(self.arena.register_container(c));
1949 }
1950 Index::Seq(i) => {
1951 let tree_state =
1952 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1953 let parent: TreeParentId = if let Some(node) = node {
1954 node.into()
1955 } else {
1956 TreeParentId::Root
1957 };
1958 let child = tree_state.get_children(&parent)?.nth(*i)?;
1959 state_idx = CurContainer::TreeNode {
1960 tree,
1961 node: Some(child),
1962 };
1963 }
1964 Index::Node(tree_id) => {
1965 let tree_state =
1966 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1967 if tree_state.parent(tree_id).is_some() {
1968 state_idx = CurContainer::TreeNode {
1969 tree,
1970 node: Some(*tree_id),
1971 }
1972 } else {
1973 return None;
1974 }
1975 }
1976 },
1977 }
1978 i += 1;
1979 }
1980
1981 let parent_idx = match state_idx {
1982 CurContainer::Container(container_idx) => container_idx,
1983 CurContainer::TreeNode { tree, node } => {
1984 if let Some(node) = node {
1985 self.arena
1986 .register_container(&node.associated_meta_container())
1987 } else {
1988 tree
1989 }
1990 }
1991 };
1992
1993 let index = path.last().unwrap();
1994 let parent_id = self.arena.idx_to_id(parent_idx);
1995 let parent_state = self.store.get_or_create_mut(parent_idx);
1996 let value: LoroValue = match parent_state {
1997 State::ListState(l) => l.get(*index.as_seq()?).cloned()?,
1998 State::MovableListState(l) => l.get(*index.as_seq()?, IndexType::ForUser).cloned()?,
1999 State::MapState(m) => {
2000 if let Some(key) = index.as_key() {
2001 let value = m.get(key).cloned()?;
2002 if let Some(parent_id) = &parent_id {
2003 if let Some(kind) =
2004 loro_common::parse_mergeable_marker(parent_id, key, &value)
2005 {
2006 let cid = ContainerID::new_mergeable(parent_id, key, kind);
2007 LoroValue::Container(cid)
2008 } else {
2009 value
2010 }
2011 } else {
2012 value
2013 }
2014 } else if let CurContainer::TreeNode { tree, node } = state_idx {
2015 match index {
2016 Index::Seq(index) => {
2017 let tree_state =
2018 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
2019 let parent: TreeParentId = if let Some(node) = node {
2020 node.into()
2021 } else {
2022 TreeParentId::Root
2023 };
2024 let child = tree_state.get_children(&parent)?.nth(*index)?;
2025 child.associated_meta_container().into()
2026 }
2027 Index::Node(id) => id.associated_meta_container().into(),
2028 _ => return None,
2029 }
2030 } else {
2031 return None;
2032 }
2033 }
2034 State::RichtextState(s) => {
2035 let s = s.to_string_mut();
2036 s.chars()
2037 .nth(*index.as_seq()?)
2038 .map(|c| c.to_string().into())?
2039 }
2040 State::TreeState(_) => {
2041 let id = index.as_node()?;
2042 let cid = id.associated_meta_container();
2043 cid.into()
2044 }
2045 #[cfg(feature = "counter")]
2046 State::CounterState(_) => unreachable!(),
2047 State::UnknownState(_) => unreachable!(),
2048 };
2049
2050 Some(value)
2051 }
2052
2053 pub(crate) fn shallow_root_store(&self) -> Option<&Arc<GcStore>> {
2054 self.store.shallow_root_store()
2055 }
2056}
2057
2058fn create_state_(idx: ContainerIdx, config: &Configure, peer: u64) -> State {
2059 match idx.get_type() {
2060 ContainerType::Map => State::MapState(Box::new(MapState::new(idx))),
2061 ContainerType::List => State::ListState(Box::new(ListState::new(idx))),
2062 ContainerType::Text => State::RichtextState(Box::new(RichtextState::new(
2063 idx,
2064 config.text_style_config.clone(),
2065 ))),
2066 ContainerType::Tree => State::TreeState(Box::new(TreeState::new(idx, peer))),
2067 ContainerType::MovableList => State::MovableListState(Box::new(MovableListState::new(idx))),
2068 #[cfg(feature = "counter")]
2069 ContainerType::Counter => {
2070 State::CounterState(Box::new(counter_state::CounterState::new(idx)))
2071 }
2072 ContainerType::Unknown(_) => State::UnknownState(UnknownState::new(idx)),
2073 }
2074}
2075
2076fn trigger_on_new_container(
2077 state_diff: &Diff,
2078 mut listener: impl FnMut(ContainerIdx),
2079 arena: &SharedArena,
2080) {
2081 match state_diff {
2082 Diff::List(list) => {
2083 for delta in list.iter() {
2084 if let DeltaItem::Replace {
2085 value,
2086 attr,
2087 delete: _,
2088 } = delta
2089 {
2090 if attr.from_move {
2091 continue;
2092 }
2093
2094 for v in value.iter() {
2095 if let ValueOrHandler::Handler(h) = v {
2096 let idx = h.container_idx();
2097 listener(idx);
2098 }
2099 }
2100 }
2101 }
2102 }
2103 Diff::Map(map) => {
2104 for (_, v) in map.updated.iter() {
2105 if let Some(ValueOrHandler::Handler(h)) = &v.value {
2106 let idx = h.container_idx();
2107 listener(idx);
2108 }
2109 }
2110 }
2111 Diff::Tree(tree) => {
2112 for item in tree.iter() {
2113 if matches!(item.action, TreeExternalDiff::Create { .. }) {
2114 let id = item.target.associated_meta_container();
2115 listener(arena.register_container(&id));
2117 }
2118 }
2119 }
2120 _ => {}
2121 };
2122}
2123
2124#[derive(Default, Clone)]
2125struct EventRecorder {
2126 recording_diff: bool,
2127 diffs: Vec<InternalDocDiff<'static>>,
2130 events: Vec<DocDiff>,
2131 diff_start_version: Option<Frontiers>,
2132}
2133
2134impl EventRecorder {
2135 #[allow(unused)]
2136 pub fn new() -> Self {
2137 Self::default()
2138 }
2139}
2140
2141#[test]
2142fn test_size() {
2143 println!("Size of State = {}", std::mem::size_of::<State>());
2144 println!("Size of MapState = {}", std::mem::size_of::<MapState>());
2145 println!("Size of ListState = {}", std::mem::size_of::<ListState>());
2146 println!(
2147 "Size of TextState = {}",
2148 std::mem::size_of::<RichtextState>()
2149 );
2150 println!("Size of TreeState = {}", std::mem::size_of::<TreeState>());
2151}