1use crate::sync::{AtomicU64, Mutex, RwLock};
2use std::sync::{Arc, Weak};
3use std::{borrow::Cow, io::Write, sync::atomic::Ordering};
4
5use container_store::ContainerStore;
6use dead_containers_cache::DeadContainersCache;
7use enum_as_inner::EnumAsInner;
8use enum_dispatch::enum_dispatch;
9use itertools::Itertools;
10use loro_common::{ContainerID, LoroError, LoroResult, TreeID};
11use loro_delta::DeltaItem;
12use rustc_hash::{FxHashMap, FxHashSet};
13use tracing::{info_span, instrument, warn};
14
15use crate::{
16 configure::{Configure, DefaultRandom, SecureRandomGenerator},
17 container::{idx::ContainerIdx, richtext::config::StyleConfigMap},
18 cursor::Cursor,
19 delta::TreeExternalDiff,
20 diff_calc::{DiffCalculator, DiffMode},
21 event::{Diff, EventTriggerKind, Index, InternalContainerDiff, InternalDiff},
22 fx_map,
23 handler::ValueOrHandler,
24 id::PeerID,
25 lock::{LoroLockGroup, LoroMutex},
26 op::{Op, RawOp},
27 version::Frontiers,
28 ContainerDiff, ContainerType, DocDiff, InternalString, LoroDocInner, LoroValue, OpLog,
29};
30
31pub(crate) mod analyzer;
32pub(crate) mod container_store;
33#[cfg(feature = "counter")]
34mod counter_state;
35mod dead_containers_cache;
36mod list_state;
37mod map_state;
38mod movable_list_state;
39mod richtext_state;
40mod tree_state;
41mod unknown_state;
42
43pub(crate) use self::movable_list_state::{IndexType, MovableListState};
44pub(crate) use container_store::GcStore;
45pub(crate) use list_state::ListState;
46pub(crate) use map_state::MapState;
47pub(crate) use richtext_state::RichtextState;
48pub(crate) use tree_state::FiIfNotConfigured;
49pub(crate) use tree_state::{get_meta_value, FractionalIndexGenResult, NodePosition, TreeState};
50pub use tree_state::{TreeNode, TreeNodeWithChildren, TreeParentId};
51
52use self::{container_store::ContainerWrapper, unknown_state::UnknownState};
53
54#[cfg(feature = "counter")]
55use self::counter_state::CounterState;
56
57use super::{arena::SharedArena, event::InternalDocDiff};
58
59pub struct DocState {
60 pub(super) peer: Arc<AtomicU64>,
61
62 pub(super) frontiers: Frontiers,
63 pub(super) store: ContainerStore,
65 pub(super) arena: SharedArena,
66 pub(crate) config: Configure,
67 doc: Weak<LoroDocInner>,
69 in_txn: bool,
71 changed_idx_in_txn: FxHashSet<ContainerIdx>,
72
73 event_recorder: EventRecorder,
75
76 dead_containers_cache: DeadContainersCache,
77}
78
79impl std::fmt::Debug for DocState {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 f.debug_struct("DocState")
82 .field("peer", &self.peer)
83 .finish()
84 }
85}
86
87#[derive(Clone, Copy)]
88pub(crate) struct ContainerCreationContext<'a> {
89 pub configure: &'a Configure,
90 pub peer: PeerID,
91}
92
93pub(crate) struct DiffApplyContext<'a> {
94 pub mode: DiffMode,
95 pub doc: &'a Weak<LoroDocInner>,
96}
97
98pub(crate) trait FastStateSnapshot {
99 fn encode_snapshot_fast<W: Write>(&mut self, w: W);
100 fn decode_value(bytes: &[u8]) -> LoroResult<(LoroValue, &[u8])>;
101 fn decode_snapshot_fast(
102 idx: ContainerIdx,
103 v: (LoroValue, &[u8]),
104 ctx: ContainerCreationContext,
105 ) -> LoroResult<Self>
106 where
107 Self: Sized;
108}
109
110#[derive(Debug, Clone, Default)]
111pub(crate) struct ApplyLocalOpReturn {
112 pub deleted_containers: Vec<ContainerID>,
113}
114
115#[enum_dispatch]
116pub(crate) trait ContainerState {
117 fn container_idx(&self) -> ContainerIdx;
118
119 fn is_state_empty(&self) -> bool;
120
121 #[must_use]
122 fn apply_diff_and_convert(&mut self, diff: InternalDiff, ctx: DiffApplyContext) -> Diff;
123
124 fn apply_diff(&mut self, diff: InternalDiff, ctx: DiffApplyContext) -> LoroResult<()>;
130
131 fn apply_local_op(&mut self, raw_op: &RawOp, op: &Op) -> LoroResult<ApplyLocalOpReturn>;
132 fn to_diff(&mut self, doc: &Weak<LoroDocInner>) -> Diff;
134
135 fn get_value(&mut self) -> LoroValue;
136
137 #[allow(unused)]
139 fn get_child_index(&self, id: &ContainerID) -> Option<Index>;
140
141 #[allow(unused)]
142 fn contains_child(&self, id: &ContainerID) -> bool;
143
144 #[allow(unused)]
145 fn get_child_containers(&self) -> Vec<ContainerID>;
146
147 fn fork(&self, config: &Configure) -> Self;
148}
149
150impl<T: FastStateSnapshot> FastStateSnapshot for Box<T> {
151 fn encode_snapshot_fast<W: Write>(&mut self, w: W) {
152 self.as_mut().encode_snapshot_fast(w)
153 }
154
155 fn decode_value(bytes: &[u8]) -> LoroResult<(LoroValue, &[u8])> {
156 T::decode_value(bytes)
157 }
158
159 fn decode_snapshot_fast(
160 idx: ContainerIdx,
161 v: (LoroValue, &[u8]),
162 ctx: ContainerCreationContext,
163 ) -> LoroResult<Self>
164 where
165 Self: Sized,
166 {
167 T::decode_snapshot_fast(idx, v, ctx).map(|x| Box::new(x))
168 }
169}
170
171impl<T: ContainerState> ContainerState for Box<T> {
172 fn container_idx(&self) -> ContainerIdx {
173 self.as_ref().container_idx()
174 }
175
176 fn is_state_empty(&self) -> bool {
177 self.as_ref().is_state_empty()
178 }
179
180 fn apply_diff_and_convert(&mut self, diff: InternalDiff, ctx: DiffApplyContext) -> Diff {
181 self.as_mut().apply_diff_and_convert(diff, ctx)
182 }
183
184 fn apply_diff(&mut self, diff: InternalDiff, ctx: DiffApplyContext) -> LoroResult<()> {
185 self.as_mut().apply_diff(diff, ctx)
186 }
187
188 fn apply_local_op(&mut self, raw_op: &RawOp, op: &Op) -> LoroResult<ApplyLocalOpReturn> {
189 self.as_mut().apply_local_op(raw_op, op)
190 }
191
192 #[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."]
193 fn to_diff(&mut self, doc: &Weak<LoroDocInner>) -> Diff {
194 self.as_mut().to_diff(doc)
195 }
196
197 fn get_value(&mut self) -> LoroValue {
198 self.as_mut().get_value()
199 }
200
201 #[doc = r" Get the index of the child container"]
202 #[allow(unused)]
203 fn get_child_index(&self, id: &ContainerID) -> Option<Index> {
204 self.as_ref().get_child_index(id)
205 }
206
207 fn contains_child(&self, id: &ContainerID) -> bool {
208 self.as_ref().contains_child(id)
209 }
210
211 #[allow(unused)]
212 fn get_child_containers(&self) -> Vec<ContainerID> {
213 self.as_ref().get_child_containers()
214 }
215
216 fn fork(&self, config: &Configure) -> Self {
217 Box::new(self.as_ref().fork(config))
218 }
219}
220
221#[allow(clippy::enum_variant_names)]
222#[enum_dispatch(ContainerState)]
223#[derive(EnumAsInner, Debug)]
224pub enum State {
225 ListState(Box<ListState>),
226 MovableListState(Box<MovableListState>),
227 MapState(Box<MapState>),
228 RichtextState(Box<RichtextState>),
229 TreeState(Box<TreeState>),
230 #[cfg(feature = "counter")]
231 CounterState(Box<counter_state::CounterState>),
232 UnknownState(UnknownState),
233}
234
235impl From<ListState> for State {
236 fn from(s: ListState) -> Self {
237 Self::ListState(Box::new(s))
238 }
239}
240
241impl From<RichtextState> for State {
242 fn from(s: RichtextState) -> Self {
243 Self::RichtextState(Box::new(s))
244 }
245}
246
247impl From<MovableListState> for State {
248 fn from(s: MovableListState) -> Self {
249 Self::MovableListState(Box::new(s))
250 }
251}
252
253impl From<MapState> for State {
254 fn from(s: MapState) -> Self {
255 Self::MapState(Box::new(s))
256 }
257}
258
259impl From<TreeState> for State {
260 fn from(s: TreeState) -> Self {
261 Self::TreeState(Box::new(s))
262 }
263}
264
265#[cfg(feature = "counter")]
266impl From<CounterState> for State {
267 fn from(s: CounterState) -> Self {
268 Self::CounterState(Box::new(s))
269 }
270}
271
272impl State {
273 pub fn new_list(idx: ContainerIdx) -> Self {
274 Self::ListState(Box::new(ListState::new(idx)))
275 }
276
277 pub fn new_map(idx: ContainerIdx) -> Self {
278 Self::MapState(Box::new(MapState::new(idx)))
279 }
280
281 pub fn new_richtext(idx: ContainerIdx, config: Arc<RwLock<StyleConfigMap>>) -> Self {
282 Self::RichtextState(Box::new(RichtextState::new(idx, config)))
283 }
284
285 pub fn new_tree(idx: ContainerIdx, peer: PeerID) -> Self {
286 Self::TreeState(Box::new(TreeState::new(idx, peer)))
287 }
288
289 pub fn new_unknown(idx: ContainerIdx) -> Self {
290 Self::UnknownState(UnknownState::new(idx))
291 }
292
293 pub fn encode_snapshot_fast<W: Write>(&mut self, mut w: W) {
294 match self {
295 State::ListState(s) => s.encode_snapshot_fast(&mut w),
296 State::MovableListState(s) => s.encode_snapshot_fast(&mut w),
297 State::MapState(s) => s.encode_snapshot_fast(&mut w),
298 State::RichtextState(s) => s.encode_snapshot_fast(&mut w),
299 State::TreeState(s) => s.encode_snapshot_fast(&mut w),
300 #[cfg(feature = "counter")]
301 State::CounterState(s) => s.encode_snapshot_fast(&mut w),
302 State::UnknownState(s) => s.encode_snapshot_fast(&mut w),
303 }
304 }
305
306 pub fn fork(&self, config: &Configure) -> Self {
307 match self {
308 State::ListState(list_state) => State::ListState(list_state.fork(config)),
309 State::MovableListState(movable_list_state) => {
310 State::MovableListState(movable_list_state.fork(config))
311 }
312 State::MapState(map_state) => State::MapState(map_state.fork(config)),
313 State::RichtextState(richtext_state) => {
314 State::RichtextState(richtext_state.fork(config))
315 }
316 State::TreeState(tree_state) => State::TreeState(tree_state.fork(config)),
317 #[cfg(feature = "counter")]
318 State::CounterState(counter_state) => State::CounterState(counter_state.fork(config)),
319 State::UnknownState(unknown_state) => State::UnknownState(unknown_state.fork(config)),
320 }
321 }
322}
323
324impl DocState {
325 #[inline]
326 pub fn new_arc(
327 doc: Weak<LoroDocInner>,
328 arena: SharedArena,
329 config: Configure,
330 lock_group: &LoroLockGroup,
331 ) -> Arc<LoroMutex<Self>> {
332 let peer = DefaultRandom.next_u64();
333 let peer = Arc::new(AtomicU64::new(peer));
336 Arc::new(lock_group.new_lock(
337 Self {
338 store: ContainerStore::new(arena.clone(), config.clone(), peer.clone()),
339 peer,
340 arena,
341 frontiers: Frontiers::default(),
342 doc,
343 config,
344 in_txn: false,
345 changed_idx_in_txn: FxHashSet::default(),
346 event_recorder: Default::default(),
347 dead_containers_cache: Default::default(),
348 },
349 crate::lock::LockKind::DocState,
350 ))
351 }
352
353 pub fn fork_with_new_peer_id(
354 &mut self,
355 doc: Weak<LoroDocInner>,
356 arena: SharedArena,
357 config: Configure,
358 ) -> Arc<Mutex<Self>> {
359 let peer = Arc::new(AtomicU64::new(DefaultRandom.next_u64()));
360 let store = self.store.fork(arena.clone(), peer.clone(), config.clone());
361 Arc::new(Mutex::new(Self {
362 peer,
363 frontiers: self.frontiers.clone(),
364 store,
365 arena,
366 config,
367 doc,
368 in_txn: false,
369 changed_idx_in_txn: FxHashSet::default(),
370 event_recorder: Default::default(),
371 dead_containers_cache: Default::default(),
372 }))
373 }
374
375 pub fn start_recording(&mut self) {
376 if self.is_recording() {
377 return;
378 }
379
380 self.event_recorder.recording_diff = true;
381 self.event_recorder.diff_start_version = Some(self.frontiers.clone());
382 }
383
384 #[inline(always)]
385 pub fn stop_and_clear_recording(&mut self) {
386 self.event_recorder = Default::default();
387 }
388
389 #[inline(always)]
390 pub fn is_recording(&self) -> bool {
391 self.event_recorder.recording_diff
392 }
393
394 pub fn refresh_peer_id(&mut self) {
395 self.peer.store(
396 DefaultRandom.next_u64(),
397 std::sync::atomic::Ordering::Relaxed,
398 );
399 }
400
401 pub fn take_events(&mut self) -> Vec<DocDiff> {
403 if !self.is_recording() {
404 return vec![];
405 }
406
407 self.convert_current_batch_diff_into_event();
408 std::mem::take(&mut self.event_recorder.events)
409 }
410
411 fn record_diff(&mut self, diff: InternalDocDiff) {
419 if !self.event_recorder.recording_diff || diff.diff.is_empty() {
420 return;
421 }
422
423 let Some(last_diff) = self.event_recorder.diffs.last_mut() else {
424 self.event_recorder.diffs.push(diff.into_owned());
425 return;
426 };
427
428 if last_diff.can_merge(&diff) {
429 self.event_recorder.diffs.push(diff.into_owned());
430 return;
431 }
432
433 panic!("should call pre_txn before record_diff")
434 }
435
436 fn pre_txn(&mut self, next_origin: InternalString, next_trigger: EventTriggerKind) {
438 if !self.is_recording() {
439 return;
440 }
441
442 let Some(last_diff) = self.event_recorder.diffs.last() else {
443 return;
444 };
445
446 if last_diff.origin == next_origin && last_diff.by == next_trigger {
447 return;
448 }
449
450 self.convert_current_batch_diff_into_event()
453 }
454
455 fn convert_current_batch_diff_into_event(&mut self) {
456 let recorder = &mut self.event_recorder;
457 if recorder.diffs.is_empty() {
458 return;
459 }
460
461 let diffs = std::mem::take(&mut recorder.diffs);
462 let start = recorder.diff_start_version.take().unwrap();
463 recorder.diff_start_version = Some((*diffs.last().unwrap().new_version).to_owned());
464 let event = self.diffs_to_event(diffs, start);
465 self.event_recorder.events.push(event);
466 }
467
468 #[inline]
471 pub fn set_peer_id(&mut self, peer: PeerID) {
472 self.peer.store(peer, std::sync::atomic::Ordering::Relaxed);
473 }
474
475 pub fn peer_id(&self) -> PeerID {
476 self.peer.load(std::sync::atomic::Ordering::Relaxed)
477 }
478
479 #[instrument(skip_all)]
487 pub(crate) fn apply_diff(
488 &mut self,
489 mut diff: InternalDocDiff<'static>,
490 diff_mode: DiffMode,
491 ) -> LoroResult<()> {
492 if self.in_txn {
493 panic!("apply_diff should not be called in a transaction");
494 }
495
496 match diff_mode {
497 DiffMode::Checkout => {
498 self.dead_containers_cache.clear();
499 }
500 _ => {
501 self.dead_containers_cache.clear_alive();
502 }
503 }
504
505 let is_recording = self.is_recording();
506 self.pre_txn(diff.origin.clone(), diff.by);
507 let Cow::Owned(mut diffs) = std::mem::take(&mut diff.diff) else {
508 unreachable!()
509 };
510
511 diffs.sort_by_cached_key(|diff| self.arena.get_depth(diff.idx));
538 let mut to_revive_in_next_layer: FxHashSet<ContainerIdx> = FxHashSet::default();
539 let mut to_revive_in_this_layer: FxHashSet<ContainerIdx> = FxHashSet::default();
540 let mut last_depth = 0;
541 let len = diffs.len();
542 for mut diff in std::mem::replace(&mut diffs, Vec::with_capacity(len)) {
543 let Some(depth) = self.arena.get_depth(diff.idx) else {
544 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));
545 continue;
546 };
547 let this_depth = depth.get();
548 while this_depth > last_depth {
549 let to_create = std::mem::take(&mut to_revive_in_this_layer);
552 to_revive_in_this_layer = std::mem::take(&mut to_revive_in_next_layer);
553 for new in to_create {
554 let state = self.store.get_or_create_mut(new);
555 if state.is_state_empty() {
556 continue;
557 }
558
559 let external_diff = state.to_diff(&self.doc);
560 trigger_on_new_container(
561 &external_diff,
562 |cid| {
563 to_revive_in_this_layer.insert(cid);
564 },
565 &self.arena,
566 );
567
568 diffs.push(InternalContainerDiff {
569 idx: new,
570 bring_back: true,
571 diff: external_diff.into(),
572 diff_mode: DiffMode::Checkout,
573 });
574 }
575
576 last_depth += 1;
577 }
578
579 let idx = diff.idx;
580 let internal_diff = std::mem::take(&mut diff.diff);
581 match &internal_diff {
582 crate::event::DiffVariant::None => {
583 if is_recording {
584 let state = self.store.get_or_create_mut(diff.idx);
585 let extern_diff = state.to_diff(&self.doc);
586 trigger_on_new_container(
587 &extern_diff,
588 |cid| {
589 to_revive_in_next_layer.insert(cid);
590 },
591 &self.arena,
592 );
593 diff.diff = extern_diff.into();
594 }
595 }
596 crate::event::DiffVariant::Internal(_) => {
597 let cid = self.arena.idx_to_id(idx).unwrap();
598 info_span!("apply diff on", container_id = ?cid).in_scope(
599 || -> LoroResult<()> {
600 if self.in_txn {
601 self.changed_idx_in_txn.insert(idx);
602 }
603 let state = self.store.get_or_create_mut(idx);
604 if is_recording {
605 let external_diff =
607 if diff.bring_back || to_revive_in_this_layer.contains(&idx) {
608 state.apply_diff(
609 internal_diff.into_internal().unwrap(),
610 DiffApplyContext {
611 mode: diff.diff_mode,
612 doc: &self.doc,
613 },
614 )?;
615 state.to_diff(&self.doc)
616 } else {
617 state.apply_diff_and_convert(
618 internal_diff.into_internal().unwrap(),
619 DiffApplyContext {
620 mode: diff.diff_mode,
621 doc: &self.doc,
622 },
623 )
624 };
625 trigger_on_new_container(
626 &external_diff,
627 |cid| {
628 to_revive_in_next_layer.insert(cid);
629 },
630 &self.arena,
631 );
632 diff.diff = external_diff.into();
633 } else {
634 state.apply_diff(
635 internal_diff.into_internal().unwrap(),
636 DiffApplyContext {
637 mode: diff.diff_mode,
638 doc: &self.doc,
639 },
640 )?;
641 }
642 Ok(())
643 },
644 )?;
645 }
646 crate::event::DiffVariant::External(_) => unreachable!(),
647 }
648
649 to_revive_in_this_layer.remove(&idx);
650 if !diff.diff.is_empty() {
651 diffs.push(diff);
652 }
653 }
654
655 while !to_revive_in_this_layer.is_empty() || !to_revive_in_next_layer.is_empty() {
657 let to_create = std::mem::take(&mut to_revive_in_this_layer);
658 for new in to_create {
659 let state = self.store.get_or_create_mut(new);
660 if state.is_state_empty() {
661 continue;
662 }
663
664 let external_diff = state.to_diff(&self.doc);
665 trigger_on_new_container(
666 &external_diff,
667 |cid| {
668 to_revive_in_next_layer.insert(cid);
669 },
670 &self.arena,
671 );
672
673 if !external_diff.is_empty() {
674 diffs.push(InternalContainerDiff {
675 idx: new,
676 bring_back: true,
677 diff: external_diff.into(),
678 diff_mode: DiffMode::Checkout,
679 });
680 }
681 }
682
683 to_revive_in_this_layer = std::mem::take(&mut to_revive_in_next_layer);
684 }
685
686 diff.diff = diffs.into();
687 self.frontiers = diff.new_version.clone().into_owned();
688 if self.is_recording() {
689 self.record_diff(diff)
690 }
691 Ok(())
692 }
693
694 pub fn apply_local_op(&mut self, raw_op: &RawOp, op: &Op) -> LoroResult<()> {
695 self.set_container_parent_by_raw_op(raw_op);
697 let state = self.store.get_or_create_mut(op.container);
698 if self.in_txn {
699 self.changed_idx_in_txn.insert(op.container);
700 }
701 let ret = state.apply_local_op(raw_op, op)?;
702 if !ret.deleted_containers.is_empty() {
703 self.dead_containers_cache.clear_alive();
704 }
705
706 Ok(())
707 }
708
709 pub(crate) fn start_txn(&mut self, origin: InternalString, trigger: EventTriggerKind) {
710 self.pre_txn(origin, trigger);
711 self.in_txn = true;
712 }
713
714 pub(crate) fn abort_txn(&mut self) {
715 self.in_txn = false;
716 }
717
718 pub fn iter_and_decode_all(&mut self) -> impl Iterator<Item = &mut State> {
719 self.store.iter_and_decode_all()
720 }
721
722 pub(crate) fn iter_all_containers_mut(
723 &mut self,
724 ) -> impl Iterator<Item = (&ContainerIdx, &mut ContainerWrapper)> {
725 self.store.iter_all_containers()
726 }
727
728 pub fn does_container_exist(&mut self, id: &ContainerID) -> bool {
729 if id.is_root() {
732 return true;
733 }
734
735 if let Some(idx) = self.arena.id_to_idx(id) {
736 if self.arena.get_depth(idx).is_some() {
737 return true;
738 }
739 }
740
741 self.store.contains_id(id)
742 }
743
744 pub(crate) fn commit_txn(&mut self, new_frontiers: Frontiers, diff: Option<InternalDocDiff>) {
745 self.in_txn = false;
746 self.frontiers = new_frontiers;
747 if self.is_recording() {
748 self.record_diff(diff.unwrap());
749 }
750 }
751
752 #[inline]
754 pub(crate) fn ensure_container(&mut self, id: &ContainerID) {
755 self.store.ensure_container(id);
756 }
757
758 pub(crate) fn ensure_all_alive_containers(&mut self) -> FxHashSet<ContainerID> {
760 let ans = self.get_all_alive_containers();
763 for id in ans.iter() {
764 self.ensure_container(id);
765 }
766
767 ans
768 }
769
770 pub(crate) fn get_value_by_idx(&mut self, container_idx: ContainerIdx) -> LoroValue {
771 self.store
772 .get_value(container_idx)
773 .unwrap_or_else(|| container_idx.get_type().default_value())
774 }
775
776 pub(super) fn init_with_states_and_version(
783 &mut self,
784 frontiers: Frontiers,
785 oplog: &OpLog,
786 unknown_containers: Vec<ContainerIdx>,
787 need_to_register_parent: bool,
788 origin: InternalString,
789 ) -> LoroResult<()> {
790 self.pre_txn(Default::default(), EventTriggerKind::Import);
791 if need_to_register_parent {
792 for state in self.store.iter_and_decode_all() {
793 let idx = state.container_idx();
794 let s = state;
795 for child_id in s.get_child_containers() {
796 let child_idx = self.arena.register_container(&child_id);
797 self.arena.set_parent(child_idx, Some(idx));
798 }
799 }
800 }
801
802 if !unknown_containers.is_empty() {
803 let mut diff_calc = DiffCalculator::new(false);
804 let stack_vv;
805 let vv = if oplog.frontiers() == &frontiers {
806 oplog.vv()
807 } else {
808 stack_vv = oplog.dag().frontiers_to_vv(&frontiers);
809 stack_vv.as_ref().unwrap()
810 };
811
812 let (unknown_diffs, _diff_mode) = diff_calc.calc_diff_internal(
813 oplog,
814 &Default::default(),
815 &Default::default(),
816 vv,
817 &frontiers,
818 Some(&|idx| !idx.is_unknown() && unknown_containers.contains(&idx)),
819 );
820 self.apply_diff(
821 InternalDocDiff {
822 origin: origin.clone(),
823 by: EventTriggerKind::Import,
824 diff: unknown_diffs.into(),
825 new_version: Cow::Owned(frontiers.clone()),
826 },
827 DiffMode::Checkout,
828 )?;
829 }
830
831 if self.is_recording() {
832 let diff: Vec<_> = self
833 .store
834 .iter_all_containers()
835 .map(|(&idx, state)| InternalContainerDiff {
836 idx,
837 bring_back: false,
838 diff: state
839 .get_state_mut(
840 idx,
841 ContainerCreationContext {
842 configure: &self.config,
843 peer: self.peer.load(Ordering::Relaxed),
844 },
845 )
846 .to_diff(&self.doc)
847 .into(),
848 diff_mode: DiffMode::Checkout,
849 })
850 .collect();
851
852 self.record_diff(InternalDocDiff {
853 origin,
854 by: EventTriggerKind::Import,
855 diff: diff.into(),
856 new_version: Cow::Borrowed(&frontiers),
857 });
858 }
859
860 self.frontiers = frontiers;
861 Ok(())
862 }
863
864 #[inline(always)]
865 #[allow(unused)]
866 pub(crate) fn with_state<F, R>(&mut self, idx: ContainerIdx, f: F) -> R
867 where
868 F: FnOnce(&State) -> R,
869 {
870 let depth = self.arena.get_depth(idx).unwrap().get() as usize;
871 let state = self.store.get_or_create_imm(idx);
872 f(state)
873 }
874
875 #[inline(always)]
876 pub(crate) fn with_state_mut<F, R>(&mut self, idx: ContainerIdx, f: F) -> R
877 where
878 F: FnOnce(&mut State) -> R,
879 {
880 let state = self.store.get_or_create_mut(idx);
881 f(state)
882 }
883
884 pub(super) fn is_in_txn(&self) -> bool {
885 self.in_txn
886 }
887
888 pub fn can_import_snapshot(&self) -> bool {
889 !self.in_txn && self.arena.can_import_snapshot() && self.store.can_import_snapshot()
890 }
891
892 pub fn get_value(&mut self) -> LoroValue {
893 let flag = self.store.load_all();
894 let roots = self.arena.root_containers(flag);
895 let ans: loro_common::LoroMapValue = roots
896 .into_iter()
897 .map(|idx| {
898 let id = self.arena.idx_to_id(idx).unwrap();
899 let ContainerID::Root {
900 name,
901 container_type: _,
902 } = &id
903 else {
904 unreachable!()
905 };
906 (name.to_string(), LoroValue::Container(id))
907 })
908 .collect();
909 LoroValue::Map(ans)
910 }
911
912 pub fn get_deep_value(&mut self) -> LoroValue {
913 let flag = self.store.load_all();
914 let roots = self.arena.root_containers(flag);
915 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
916 let binding = self.config.deleted_root_containers.clone();
917 let deleted_root_container = binding.lock();
918 let should_hide_empty_root_container = self
919 .config
920 .hide_empty_root_containers
921 .load(Ordering::Relaxed);
922 for root_idx in roots {
923 let id = self.arena.idx_to_id(root_idx).unwrap();
924 match &id {
925 loro_common::ContainerID::Root { name, .. } => {
926 let v = self.get_container_deep_value(root_idx);
927 if (should_hide_empty_root_container || deleted_root_container.contains(&id))
928 && v.is_empty_collection()
929 {
930 continue;
931 }
932
933 ans.insert(name.to_string(), v);
934 }
935 loro_common::ContainerID::Normal { .. } => {
936 unreachable!()
937 }
938 }
939 }
940
941 LoroValue::Map(ans.into())
942 }
943
944 pub fn get_deep_value_with_id(&mut self) -> LoroValue {
945 let flag = self.store.load_all();
946 let roots = self.arena.root_containers(flag);
947 let mut ans = FxHashMap::with_capacity_and_hasher(roots.len(), Default::default());
948 for root_idx in roots {
949 let id = self.arena.idx_to_id(root_idx).unwrap();
950 match id.clone() {
951 loro_common::ContainerID::Root { name, .. } => {
952 ans.insert(
953 name.to_string(),
954 self.get_container_deep_value_with_id(root_idx, Some(id)),
955 );
956 }
957 loro_common::ContainerID::Normal { .. } => {
958 unreachable!()
959 }
960 }
961 }
962
963 LoroValue::Map(ans.into())
964 }
965
966 pub fn get_all_container_value_flat(&mut self) -> LoroValue {
967 let mut map = FxHashMap::default();
968 self.store.iter_and_decode_all().for_each(|c| {
969 let value = c.get_value();
970 let cid = self.arena.idx_to_id(c.container_idx()).unwrap().to_string();
971 map.insert(cid, value);
972 });
973
974 LoroValue::Map(map.into())
975 }
976
977 pub(crate) fn get_container_deep_value_with_id(
978 &mut self,
979 container: ContainerIdx,
980 id: Option<ContainerID>,
981 ) -> LoroValue {
982 let id = id.unwrap_or_else(|| self.arena.idx_to_id(container).unwrap());
983 let Some(state) = self.store.get_container_mut(container) else {
984 return container.get_type().default_value();
985 };
986 let value = state.get_value();
987 let cid_str = LoroValue::String(format!("idx:{}, id:{}", container.to_index(), id).into());
988 match value {
989 LoroValue::Container(_) => unreachable!(),
990 LoroValue::List(mut list) => {
991 if container.get_type() == ContainerType::Tree {
992 get_meta_value(list.make_mut(), self);
993 } else {
994 if list.iter().all(|x| !x.is_container()) {
995 return LoroValue::Map(
996 (fx_map!(
997 "cid".into() => cid_str,
998 "value".into() => LoroValue::List(list)
999 ))
1000 .into(),
1001 );
1002 }
1003
1004 let list_mut = list.make_mut();
1005 for item in list_mut.iter_mut() {
1006 if item.is_container() {
1007 let container = item.as_container().unwrap();
1008 let container_idx = self.arena.register_container(container);
1009 let value = self.get_container_deep_value_with_id(
1010 container_idx,
1011 Some(container.clone()),
1012 );
1013 *item = value;
1014 }
1015 }
1016 }
1017 LoroValue::Map(
1018 (fx_map!(
1019 "cid".into() => cid_str,
1020 "value".into() => LoroValue::List(list)
1021 ))
1022 .into(),
1023 )
1024 }
1025 LoroValue::Map(mut map) => {
1026 let map_mut = map.make_mut();
1027 for (_key, value) in map_mut.iter_mut() {
1028 if value.is_container() {
1029 let container = value.as_container().unwrap();
1030 let container_idx = self.arena.register_container(container);
1031 let new_value = self.get_container_deep_value_with_id(
1032 container_idx,
1033 Some(container.clone()),
1034 );
1035 *value = new_value;
1036 }
1037 }
1038
1039 LoroValue::Map(
1040 (fx_map!(
1041 "cid".into() => cid_str,
1042 "value".into() => LoroValue::Map(map)
1043 ))
1044 .into(),
1045 )
1046 }
1047 _ => LoroValue::Map(
1048 (fx_map!(
1049 "cid".into() => cid_str,
1050 "value".into() => value
1051 ))
1052 .into(),
1053 ),
1054 }
1055 }
1056
1057 pub fn get_container_deep_value(&mut self, container: ContainerIdx) -> LoroValue {
1058 let Some(value) = self.store.get_value(container) else {
1059 return container.get_type().default_value();
1060 };
1061 match value {
1062 LoroValue::Container(_) => unreachable!(),
1063 LoroValue::List(mut list) => {
1064 if container.get_type() == ContainerType::Tree {
1065 get_meta_value(list.make_mut(), self);
1070 } else {
1071 if list.iter().all(|x| !x.is_container()) {
1072 return LoroValue::List(list);
1073 }
1074
1075 let list_mut = list.make_mut();
1076 for item in list_mut.iter_mut() {
1077 if item.is_container() {
1078 let container = item.as_container().unwrap();
1079 let container_idx = self.arena.register_container(container);
1080 let value = self.get_container_deep_value(container_idx);
1081 *item = value;
1082 }
1083 }
1084 }
1085 LoroValue::List(list)
1086 }
1087 LoroValue::Map(mut map) => {
1088 if map.iter().all(|x| !x.1.is_container()) {
1089 return LoroValue::Map(map);
1090 }
1091
1092 let map_mut = map.make_mut();
1093 for (_key, value) in map_mut.iter_mut() {
1094 if value.is_container() {
1095 let container = value.as_container().unwrap();
1096 let container_idx = self.arena.register_container(container);
1097 let new_value = self.get_container_deep_value(container_idx);
1098 *value = new_value;
1099 }
1100 }
1101 LoroValue::Map(map)
1102 }
1103 _ => value,
1104 }
1105 }
1106
1107 pub(crate) fn get_all_alive_containers(&mut self) -> FxHashSet<ContainerID> {
1108 let flag = self.store.load_all();
1109 let mut ans = FxHashSet::default();
1110 let mut to_visit = self
1111 .arena
1112 .root_containers(flag)
1113 .iter()
1114 .map(|x| self.arena.get_container_id(*x).unwrap())
1115 .collect_vec();
1116
1117 while let Some(id) = to_visit.pop() {
1118 self.get_alive_children_of(&id, &mut to_visit);
1119 ans.insert(id);
1120 }
1121
1122 ans
1123 }
1124
1125 pub(crate) fn get_alive_children_of(&mut self, id: &ContainerID, ans: &mut Vec<ContainerID>) {
1126 let idx = self.arena.register_container(id);
1127 let Some(value) = self.store.get_value(idx) else {
1128 return;
1129 };
1130
1131 match value {
1132 LoroValue::Container(_) => unreachable!(),
1133 LoroValue::List(list) => {
1134 if idx.get_type() == ContainerType::Tree {
1135 let mut list = list.unwrap();
1140 while let Some(node) = list.pop() {
1141 let map = node.as_map().unwrap();
1142 let meta = map.get("meta").unwrap();
1143 let id = meta.as_container().unwrap();
1144 ans.push(id.clone());
1145 let children = map.get("children").unwrap();
1146 let children = children.as_list().unwrap();
1147 for child in children.iter() {
1148 list.push(child.clone());
1149 }
1150 }
1151 } else {
1152 for item in list.iter() {
1153 if let LoroValue::Container(id) = item {
1154 ans.push(id.clone());
1155 }
1156 }
1157 }
1158 }
1159 LoroValue::Map(map) => {
1160 for (_key, value) in map.iter() {
1161 if let LoroValue::Container(id) = value {
1162 ans.push(id.clone());
1163 }
1164 }
1165 }
1166 _ => {}
1167 }
1168 }
1169
1170 fn diffs_to_event(&mut self, diffs: Vec<InternalDocDiff<'_>>, from: Frontiers) -> DocDiff {
1173 if diffs.is_empty() {
1174 panic!("diffs is empty");
1175 }
1176
1177 let triggered_by = diffs[0].by;
1178 debug_assert!(diffs.iter().all(|x| x.by == triggered_by));
1179 let mut containers = FxHashMap::default();
1180 let to = (*diffs.last().unwrap().new_version).to_owned();
1181 let origin = diffs[0].origin.clone();
1182 for diff in diffs {
1183 #[allow(clippy::unnecessary_to_owned)]
1184 for container_diff in diff.diff.into_owned() {
1185 let Some((last_container_diff, _)) = containers.get_mut(&container_diff.idx) else {
1186 if let Some(path) = self.get_path(container_diff.idx) {
1187 containers.insert(container_diff.idx, (container_diff.diff, path));
1188 } else {
1189 loro_common::warn!(
1192 "⚠️ WARNING: ignore event because cannot find its path {:#?} container id:{}",
1193 &container_diff,
1194 self.arena.idx_to_id(container_diff.idx).unwrap()
1195 );
1196 }
1197
1198 continue;
1199 };
1200 *last_container_diff = last_container_diff
1202 .clone()
1203 .compose(container_diff.diff)
1204 .unwrap();
1205 }
1206 }
1207 let mut diff: Vec<_> = containers
1208 .into_iter()
1209 .map(|(container, (diff, path))| {
1210 let idx = container;
1211 let id = self.arena.get_container_id(idx).unwrap();
1212 let is_unknown = id.is_unknown();
1213
1214 ContainerDiff {
1215 id,
1216 idx,
1217 diff: diff.into_external().unwrap(),
1218 is_unknown,
1219 path,
1220 }
1221 })
1222 .collect();
1223
1224 diff.sort_by_key(|x| {
1228 (
1229 x.path.len(),
1230 match &x.id {
1231 ContainerID::Root { .. } => 0,
1232 ContainerID::Normal { counter, .. } => *counter + 1,
1233 },
1234 )
1235 });
1236 DocDiff {
1237 from,
1238 to,
1239 origin,
1240 by: triggered_by,
1241 diff,
1242 }
1243 }
1244
1245 pub(crate) fn get_reachable(&mut self, id: &ContainerID) -> bool {
1246 if matches!(id, ContainerID::Root { .. }) {
1247 return true;
1248 }
1249
1250 if self.arena.id_to_idx(id).is_none() {
1252 if !self.does_container_exist(id) {
1253 return false;
1254 }
1255 self.arena.register_container(id);
1257 }
1258
1259 let mut idx = self.arena.id_to_idx(id).unwrap();
1260 loop {
1261 let id = self.arena.idx_to_id(idx).unwrap();
1262 if let Some(parent_idx) = self.arena.get_parent(idx) {
1263 let Some(parent_state) = self.store.get_container_mut(parent_idx) else {
1264 return false;
1265 };
1266 if !parent_state.contains_child(&id) {
1267 return false;
1268 }
1269 idx = parent_idx;
1270 } else {
1271 if id.is_root() {
1272 return true;
1273 }
1274
1275 return false;
1276 }
1277 }
1278 }
1279
1280 pub(super) fn get_path(&mut self, idx: ContainerIdx) -> Option<Vec<(ContainerID, Index)>> {
1282 let mut ans = Vec::new();
1283 let mut idx = idx;
1284 loop {
1285 let id = self.arena.idx_to_id(idx).unwrap();
1286 if let Some(parent_idx) = self.arena.get_parent(idx) {
1287 let parent_state = self.store.get_container_mut(parent_idx)?;
1288 let Some(prop) = parent_state.get_child_index(&id) else {
1289 tracing::warn!("Missing in parent's children");
1290 return None;
1291 };
1292 ans.push((id, prop));
1293 idx = parent_idx;
1294 } else {
1295 let Ok(prop) = id.clone().into_root() else {
1297 let id = format!("{}", &id);
1298 tracing::info!(?id, "Missing parent - container is deleted");
1299 return None;
1300 };
1301 ans.push((id, Index::Key(prop.0)));
1302 break;
1303 }
1304 }
1305
1306 ans.reverse();
1307
1308 Some(ans)
1309 }
1310
1311 pub(crate) fn check_before_decode_snapshot(&self) -> LoroResult<()> {
1312 if self.is_in_txn() {
1313 return Err(LoroError::DecodeError(
1314 "State is in txn".to_string().into_boxed_str(),
1315 ));
1316 }
1317
1318 if !self.can_import_snapshot() {
1319 return Err(LoroError::DecodeError(
1320 "State is not empty, cannot import snapshot directly"
1321 .to_string()
1322 .into_boxed_str(),
1323 ));
1324 }
1325
1326 Ok(())
1327 }
1328
1329 pub(crate) fn check_is_the_same(&mut self, other: &mut Self) {
1336 fn get_entries_for_state(
1337 arena: &SharedArena,
1338 state: &mut State,
1339 ) -> Option<(ContainerID, (ContainerIdx, LoroValue))> {
1340 if state.is_state_empty() {
1341 return None;
1342 }
1343
1344 let id = arena.idx_to_id(state.container_idx()).unwrap();
1345 let value = match state {
1346 State::RichtextState(s) => s.get_richtext_value(),
1347 _ => state.get_value(),
1348 };
1349 if match &value {
1350 LoroValue::List(l) => l.is_empty(),
1351 LoroValue::Map(m) => m.is_empty(),
1352 _ => false,
1353 } {
1354 return None;
1355 }
1356 #[cfg(feature = "counter")]
1357 if id.container_type() == ContainerType::Counter {
1358 if let LoroValue::Double(c) = value {
1359 if c.abs() < f64::EPSILON {
1360 return None;
1361 }
1362 }
1363 }
1364
1365 Some((id, (state.container_idx(), value)))
1366 }
1367
1368 let self_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = self
1369 .store
1370 .iter_and_decode_all()
1371 .filter_map(|state: &mut State| {
1372 let arena = &self.arena;
1373 get_entries_for_state(arena, state)
1374 })
1375 .collect();
1376 let mut other_id_to_states: FxHashMap<ContainerID, (ContainerIdx, LoroValue)> = other
1377 .store
1378 .iter_and_decode_all()
1379 .filter_map(|state: &mut State| {
1380 let arena = &other.arena;
1381 get_entries_for_state(arena, state)
1382 })
1383 .collect();
1384 for (id, (idx, this_value)) in self_id_to_states {
1385 let (_, other_value) = match other_id_to_states.remove(&id) {
1386 Some(x) => x,
1387 None => {
1388 panic!(
1389 "id: {:?}, path: {:?} is missing, value={:?}",
1390 id,
1391 self.get_path(idx),
1392 &this_value
1393 );
1394 }
1395 };
1396
1397 pretty_assertions::assert_eq!(
1398 this_value,
1399 other_value,
1400 "[self!=other] id: {:?}, path: {:?}",
1401 id,
1402 self.get_path(idx)
1403 );
1404 }
1405
1406 if !other_id_to_states.is_empty() {
1407 panic!("other has more states {:#?}", &other_id_to_states);
1408 }
1409 }
1410
1411 pub fn create_state(&self, idx: ContainerIdx) -> State {
1412 let config = &self.config;
1413 let peer = self.peer.load(std::sync::atomic::Ordering::Relaxed);
1414 create_state_(idx, config, peer)
1415 }
1416
1417 pub fn create_unknown_state(&self, idx: ContainerIdx) -> State {
1418 State::UnknownState(UnknownState::new(idx))
1419 }
1420
1421 pub fn get_relative_position(&mut self, pos: &Cursor, use_event_index: bool) -> Option<usize> {
1422 let idx = self.arena.register_container(&pos.container);
1423 let state = self.store.get_container_mut(idx)?;
1424 if let Some(id) = pos.id {
1425 match state {
1426 State::ListState(s) => s.get_index_of_id(id),
1427 State::RichtextState(s) => s.get_text_index_of_id(id, use_event_index),
1428 State::MovableListState(s) => s.get_index_of_id(id),
1429 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
1430 #[cfg(feature = "counter")]
1431 State::CounterState(_) => unreachable!(),
1432 }
1433 } else {
1434 if matches!(pos.side, crate::cursor::Side::Left) {
1435 return Some(0);
1436 }
1437
1438 match state {
1439 State::ListState(s) => Some(s.len()),
1440 State::RichtextState(s) => Some(if use_event_index {
1441 s.len_event()
1442 } else {
1443 s.len_unicode()
1444 }),
1445 State::MovableListState(s) => Some(s.len()),
1446 State::MapState(_) | State::TreeState(_) | State::UnknownState(_) => unreachable!(),
1447 #[cfg(feature = "counter")]
1448 State::CounterState(_) => unreachable!(),
1449 }
1450 }
1451 }
1452
1453 pub fn get_value_by_path(&mut self, path: &[Index]) -> Option<LoroValue> {
1454 if path.is_empty() {
1455 return None;
1456 }
1457
1458 enum CurContainer {
1459 Container(ContainerIdx),
1460 TreeNode {
1461 tree: ContainerIdx,
1462 node: Option<TreeID>,
1463 },
1464 }
1465
1466 let mut state_idx = {
1467 let root_index = path[0].as_key()?;
1468 CurContainer::Container(self.arena.get_root_container_idx_by_key(root_index)?)
1469 };
1470
1471 if path.len() == 1 {
1472 if let CurContainer::Container(c) = state_idx {
1473 let cid = self.arena.idx_to_id(c)?;
1474 return Some(LoroValue::Container(cid));
1475 }
1476 }
1477
1478 let mut i = 1;
1479 while i < path.len() - 1 {
1480 let index = &path[i];
1481 match state_idx {
1482 CurContainer::Container(idx) => {
1483 let parent_state = self.store.get_container_mut(idx)?;
1484 match parent_state {
1485 State::ListState(l) => {
1486 let Some(LoroValue::Container(c)) = l.get(*index.as_seq()?) else {
1487 return None;
1488 };
1489 state_idx = CurContainer::Container(self.arena.register_container(c));
1490 }
1491 State::MovableListState(l) => {
1492 let Some(LoroValue::Container(c)) =
1493 l.get(*index.as_seq()?, IndexType::ForUser)
1494 else {
1495 return None;
1496 };
1497 state_idx = CurContainer::Container(self.arena.register_container(c));
1498 }
1499 State::MapState(m) => {
1500 let Some(LoroValue::Container(c)) = m.get(index.as_key()?) else {
1501 return None;
1502 };
1503 state_idx = CurContainer::Container(self.arena.register_container(c));
1504 }
1505 State::RichtextState(_) => return None,
1506 State::TreeState(_) => {
1507 state_idx = CurContainer::TreeNode {
1508 tree: idx,
1509 node: None,
1510 };
1511 continue;
1512 }
1513 #[cfg(feature = "counter")]
1514 State::CounterState(_) => return None,
1515 State::UnknownState(_) => unreachable!(),
1516 }
1517 }
1518 CurContainer::TreeNode { tree, node } => match index {
1519 Index::Key(internal_string) => {
1520 let node = node?;
1521 let idx = self
1522 .arena
1523 .register_container(&node.associated_meta_container());
1524 let map = self.store.get_container(idx)?;
1525 let Some(LoroValue::Container(c)) =
1526 map.as_map_state().unwrap().get(internal_string)
1527 else {
1528 return None;
1529 };
1530
1531 state_idx = CurContainer::Container(self.arena.register_container(c));
1532 }
1533 Index::Seq(i) => {
1534 let tree_state =
1535 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1536 let parent: TreeParentId = if let Some(node) = node {
1537 node.into()
1538 } else {
1539 TreeParentId::Root
1540 };
1541 let child = tree_state.get_children(&parent)?.nth(*i)?;
1542 state_idx = CurContainer::TreeNode {
1543 tree,
1544 node: Some(child),
1545 };
1546 }
1547 Index::Node(tree_id) => {
1548 let tree_state =
1549 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1550 if tree_state.parent(tree_id).is_some() {
1551 state_idx = CurContainer::TreeNode {
1552 tree,
1553 node: Some(*tree_id),
1554 }
1555 } else {
1556 return None;
1557 }
1558 }
1559 },
1560 }
1561 i += 1;
1562 }
1563
1564 let parent_idx = match state_idx {
1565 CurContainer::Container(container_idx) => container_idx,
1566 CurContainer::TreeNode { tree, node } => {
1567 if let Some(node) = node {
1568 self.arena
1569 .register_container(&node.associated_meta_container())
1570 } else {
1571 tree
1572 }
1573 }
1574 };
1575
1576 let parent_state = self.store.get_or_create_mut(parent_idx);
1577 let index = path.last().unwrap();
1578 let value: LoroValue = match parent_state {
1579 State::ListState(l) => l.get(*index.as_seq()?).cloned()?,
1580 State::MovableListState(l) => l.get(*index.as_seq()?, IndexType::ForUser).cloned()?,
1581 State::MapState(m) => {
1582 if let Some(key) = index.as_key() {
1583 m.get(key).cloned()?
1584 } else if let CurContainer::TreeNode { tree, node } = state_idx {
1585 match index {
1586 Index::Seq(index) => {
1587 let tree_state =
1588 self.store.get_container_mut(tree)?.as_tree_state().unwrap();
1589 let parent: TreeParentId = if let Some(node) = node {
1590 node.into()
1591 } else {
1592 TreeParentId::Root
1593 };
1594 let child = tree_state.get_children(&parent)?.nth(*index)?;
1595 child.associated_meta_container().into()
1596 }
1597 Index::Node(id) => id.associated_meta_container().into(),
1598 _ => return None,
1599 }
1600 } else {
1601 return None;
1602 }
1603 }
1604 State::RichtextState(s) => {
1605 let s = s.to_string_mut();
1606 s.chars()
1607 .nth(*index.as_seq()?)
1608 .map(|c| c.to_string().into())?
1609 }
1610 State::TreeState(_) => {
1611 let id = index.as_node()?;
1612 let cid = id.associated_meta_container();
1613 cid.into()
1614 }
1615 #[cfg(feature = "counter")]
1616 State::CounterState(_) => unreachable!(),
1617 State::UnknownState(_) => unreachable!(),
1618 };
1619
1620 Some(value)
1621 }
1622
1623 pub(crate) fn shallow_root_store(&self) -> Option<&Arc<GcStore>> {
1624 self.store.shallow_root_store()
1625 }
1626}
1627
1628fn create_state_(idx: ContainerIdx, config: &Configure, peer: u64) -> State {
1629 match idx.get_type() {
1630 ContainerType::Map => State::MapState(Box::new(MapState::new(idx))),
1631 ContainerType::List => State::ListState(Box::new(ListState::new(idx))),
1632 ContainerType::Text => State::RichtextState(Box::new(RichtextState::new(
1633 idx,
1634 config.text_style_config.clone(),
1635 ))),
1636 ContainerType::Tree => State::TreeState(Box::new(TreeState::new(idx, peer))),
1637 ContainerType::MovableList => State::MovableListState(Box::new(MovableListState::new(idx))),
1638 #[cfg(feature = "counter")]
1639 ContainerType::Counter => {
1640 State::CounterState(Box::new(counter_state::CounterState::new(idx)))
1641 }
1642 ContainerType::Unknown(_) => State::UnknownState(UnknownState::new(idx)),
1643 }
1644}
1645
1646fn trigger_on_new_container(
1647 state_diff: &Diff,
1648 mut listener: impl FnMut(ContainerIdx),
1649 arena: &SharedArena,
1650) {
1651 match state_diff {
1652 Diff::List(list) => {
1653 for delta in list.iter() {
1654 if let DeltaItem::Replace {
1655 value,
1656 attr,
1657 delete: _,
1658 } = delta
1659 {
1660 if attr.from_move {
1661 continue;
1662 }
1663
1664 for v in value.iter() {
1665 if let ValueOrHandler::Handler(h) = v {
1666 let idx = h.container_idx();
1667 listener(idx);
1668 }
1669 }
1670 }
1671 }
1672 }
1673 Diff::Map(map) => {
1674 for (_, v) in map.updated.iter() {
1675 if let Some(ValueOrHandler::Handler(h)) = &v.value {
1676 let idx = h.container_idx();
1677 listener(idx);
1678 }
1679 }
1680 }
1681 Diff::Tree(tree) => {
1682 for item in tree.iter() {
1683 if matches!(item.action, TreeExternalDiff::Create { .. }) {
1684 let id = item.target.associated_meta_container();
1685 listener(arena.register_container(&id));
1687 }
1688 }
1689 }
1690 _ => {}
1691 };
1692}
1693
1694#[derive(Default, Clone)]
1695struct EventRecorder {
1696 recording_diff: bool,
1697 diffs: Vec<InternalDocDiff<'static>>,
1700 events: Vec<DocDiff>,
1701 diff_start_version: Option<Frontiers>,
1702}
1703
1704impl EventRecorder {
1705 #[allow(unused)]
1706 pub fn new() -> Self {
1707 Self::default()
1708 }
1709}
1710
1711#[test]
1712fn test_size() {
1713 println!("Size of State = {}", std::mem::size_of::<State>());
1714 println!("Size of MapState = {}", std::mem::size_of::<MapState>());
1715 println!("Size of ListState = {}", std::mem::size_of::<ListState>());
1716 println!(
1717 "Size of TextState = {}",
1718 std::mem::size_of::<RichtextState>()
1719 );
1720 println!("Size of TreeState = {}", std::mem::size_of::<TreeState>());
1721}