1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//! This file contains the methods to maintain the parent-child relationship in Loro.
//! The child-parent relationship is established when the child container is created.
//! It won't be changed. So the depth of a container is fixed.
//!
//!
use loro_common::LoroValue;
use crate::{
arena::SharedArena,
change::Change,
container::{list::list_op::ListOp, map::MapSet},
op::{ListSlice, RawOp, RawOpContent},
DocState, OpLog,
};
impl OpLog {
/// Establish the link between the child container and the parent container.
/// This relationship will never be broken.
/// It's used at the entry of creating new ops to ensure all the valid containers
/// in Loro are properly linked.
pub(super) fn register_container_and_parent_link(&self, change: &Change) {
let arena = &self.arena;
register_container_and_parent_link(arena, change);
}
}
pub(super) fn register_container_and_parent_link(arena: &SharedArena, change: &Change) {
for op in change.ops.iter() {
op.content.visit_created_children(arena, &mut |c| {
let idx = arena.register_container(c);
arena.set_parent(idx, Some(op.container));
});
}
}
impl DocState {
/// This is used in txn to short cut the process of applying an op to the state.
/// So the op here has not been registered on the oplog yet.
pub(super) fn set_container_parent_by_raw_op(&self, raw_op: &RawOp) {
let container = raw_op.container;
match &raw_op.content {
RawOpContent::List(op) => {
if let ListOp::Insert {
slice: ListSlice::RawData(list),
..
} = op
{
let list = match list {
std::borrow::Cow::Borrowed(list) => list.iter(),
std::borrow::Cow::Owned(list) => list.iter(),
};
for value in list {
if let LoroValue::Container(c) = value {
let idx = self.arena.register_container(c);
self.arena.set_parent(idx, Some(container));
}
}
}
if let ListOp::Set {
elem_id: _,
value: LoroValue::Container(c),
} = op
{
let idx = self.arena.register_container(c);
self.arena.set_parent(idx, Some(container));
}
}
RawOpContent::Map(MapSet { key: _, value }) => {
if let Some(LoroValue::Container(c)) = value {
let idx = self.arena.register_container(c);
self.arena.set_parent(idx, Some(container));
}
}
RawOpContent::Tree(tree) => {
let target = tree.target();
// create associated metadata container
// TODO: maybe we could create map container only when setting metadata
let container_id = target.associated_meta_container();
let child_idx = self.arena.register_container(&container_id);
self.arena.set_parent(child_idx, Some(container));
}
#[cfg(feature = "counter")]
RawOpContent::Counter(_) => {}
RawOpContent::Unknown { .. } => {}
}
}
}