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