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