loro_internal/op/
content.rs

1use std::sync::Arc;
2
3use enum_as_inner::EnumAsInner;
4use loro_common::{ContainerID, ContainerType, LoroValue};
5use rle::{HasLength, Mergable, Sliceable};
6#[cfg(feature = "wasm")]
7use serde::{Deserialize, Serialize};
8
9use crate::{
10    arena::SharedArena,
11    container::{
12        list::list_op::{InnerListOp, ListOp},
13        map::MapSet,
14        tree::tree_op::TreeOp,
15    },
16    encoding::OwnedValue,
17};
18
19#[derive(EnumAsInner, Debug, Clone)]
20pub enum InnerContent {
21    List(InnerListOp),
22    Map(MapSet),
23    Tree(Arc<TreeOp>),
24    // The future content should not use any encoded arena context.
25    Future(FutureInnerContent),
26}
27
28impl InnerContent {
29    pub fn visit_created_children(&self, arena: &SharedArena, f: &mut dyn FnMut(&ContainerID)) {
30        match self {
31            InnerContent::List(l) => match l {
32                InnerListOp::Insert { slice, .. } => {
33                    for v in arena.iter_value_slice(slice.to_range()) {
34                        if let LoroValue::Container(c) = v {
35                            f(&c);
36                        }
37                    }
38                }
39                InnerListOp::Set { value, .. } => {
40                    if let LoroValue::Container(c) = value {
41                        f(c);
42                    }
43                }
44
45                InnerListOp::Move { .. } => {}
46                InnerListOp::InsertText { .. } => {}
47                InnerListOp::Delete(_) => {}
48                InnerListOp::StyleStart { .. } => {}
49                InnerListOp::StyleEnd => {}
50            },
51            crate::op::InnerContent::Map(m) => {
52                if let Some(LoroValue::Container(c)) = &m.value {
53                    f(c);
54                }
55            }
56            crate::op::InnerContent::Tree(t) => {
57                let id = t.target().associated_meta_container();
58                f(&id);
59            }
60            crate::op::InnerContent::Future(f) => match &f {
61                #[cfg(feature = "counter")]
62                crate::op::FutureInnerContent::Counter(_) => {}
63                crate::op::FutureInnerContent::Unknown { .. } => {}
64            },
65        }
66    }
67}
68
69impl InnerContent {
70    pub fn estimate_storage_size(&self, kind: ContainerType) -> usize {
71        match self {
72            InnerContent::List(l) => l.estimate_storage_size(kind),
73            InnerContent::Map(_) => 3,
74            InnerContent::Tree(_) => 8,
75            InnerContent::Future(f) => f.estimate_storage_size(),
76        }
77    }
78}
79
80#[derive(EnumAsInner, Debug, Clone)]
81pub enum FutureInnerContent {
82    #[cfg(feature = "counter")]
83    Counter(f64),
84    Unknown {
85        prop: i32,
86        value: Box<OwnedValue>,
87    },
88}
89impl FutureInnerContent {
90    fn estimate_storage_size(&self) -> usize {
91        match self {
92            #[cfg(feature = "counter")]
93            FutureInnerContent::Counter(_) => 4,
94            FutureInnerContent::Unknown { .. } => 6,
95        }
96    }
97}
98
99// Note: It will be encoded into binary format, so the order of its fields should not be changed.
100#[derive(EnumAsInner, Debug, PartialEq)]
101#[cfg_attr(feature = "wasm", derive(Serialize, Deserialize,))]
102pub enum RawOpContent<'a> {
103    Map(MapSet),
104    List(ListOp<'a>),
105    Tree(Arc<TreeOp>),
106    #[cfg(feature = "counter")]
107    Counter(f64),
108    Unknown {
109        prop: i32,
110        value: OwnedValue,
111    },
112}
113
114impl Clone for RawOpContent<'_> {
115    fn clone(&self) -> Self {
116        match self {
117            Self::Map(arg0) => Self::Map(arg0.clone()),
118            Self::List(arg0) => Self::List(arg0.clone()),
119            Self::Tree(arg0) => Self::Tree(arg0.clone()),
120            #[cfg(feature = "counter")]
121            Self::Counter(x) => Self::Counter(*x),
122            Self::Unknown { prop, value } => Self::Unknown {
123                prop: *prop,
124                value: value.clone(),
125            },
126        }
127    }
128}
129
130impl RawOpContent<'_> {
131    pub fn to_static(&self) -> RawOpContent<'static> {
132        match self {
133            Self::Map(arg0) => RawOpContent::Map(arg0.clone()),
134            Self::List(arg0) => match arg0 {
135                ListOp::Insert { slice, pos } => RawOpContent::List(ListOp::Insert {
136                    slice: slice.to_static(),
137                    pos: *pos,
138                }),
139                ListOp::Delete(x) => RawOpContent::List(ListOp::Delete(*x)),
140                ListOp::StyleStart {
141                    start,
142                    end,
143                    key,
144                    value,
145                    info,
146                } => RawOpContent::List(ListOp::StyleStart {
147                    start: *start,
148                    end: *end,
149                    key: key.clone(),
150                    value: value.clone(),
151                    info: *info,
152                }),
153                ListOp::StyleEnd => RawOpContent::List(ListOp::StyleEnd),
154                ListOp::Move {
155                    from,
156                    to,
157                    elem_id: from_id,
158                } => RawOpContent::List(ListOp::Move {
159                    from: *from,
160                    to: *to,
161                    elem_id: *from_id,
162                }),
163                ListOp::Set { elem_id, value } => RawOpContent::List(ListOp::Set {
164                    elem_id: *elem_id,
165                    value: value.clone(),
166                }),
167            },
168            Self::Tree(arg0) => RawOpContent::Tree(arg0.clone()),
169            #[cfg(feature = "counter")]
170            Self::Counter(x) => RawOpContent::Counter(*x),
171            Self::Unknown { prop, value } => RawOpContent::Unknown {
172                prop: *prop,
173                value: value.clone(),
174            },
175        }
176    }
177}
178
179impl HasLength for RawOpContent<'_> {
180    fn content_len(&self) -> usize {
181        match self {
182            RawOpContent::Map(x) => x.content_len(),
183            RawOpContent::List(x) => x.content_len(),
184            RawOpContent::Tree(x) => x.content_len(),
185            #[cfg(feature = "counter")]
186            RawOpContent::Counter(_) => 1,
187            RawOpContent::Unknown { .. } => 1,
188        }
189    }
190}
191
192impl Mergable for RawOpContent<'_> {
193    fn is_mergable(&self, other: &Self, _conf: &()) -> bool
194    where
195        Self: Sized,
196    {
197        match (self, other) {
198            (RawOpContent::List(x), RawOpContent::List(y)) => x.is_mergable(y, &()),
199            (RawOpContent::Tree(x), RawOpContent::Tree(y)) => x.is_mergable(y, &()),
200            _ => false,
201        }
202    }
203
204    fn merge(&mut self, _other: &Self, _conf: &())
205    where
206        Self: Sized,
207    {
208        match self {
209            RawOpContent::List(x) => match _other {
210                RawOpContent::List(y) => x.merge(y, &()),
211                _ => unreachable!(),
212            },
213            _ => unreachable!(),
214        }
215    }
216}
217
218impl HasLength for InnerContent {
219    fn content_len(&self) -> usize {
220        match self {
221            InnerContent::List(list) => list.atom_len(),
222            InnerContent::Map(_) => 1,
223            InnerContent::Tree(_) => 1,
224            InnerContent::Future(_) => 1,
225        }
226    }
227}
228
229impl Sliceable for InnerContent {
230    fn slice(&self, from: usize, to: usize) -> Self {
231        match self {
232            a @ InnerContent::Map(_) => {
233                assert!(from == 0 && to == 1);
234                a.clone()
235            }
236            a @ InnerContent::Tree(_) => {
237                assert!(from == 0 && to == 1);
238                a.clone()
239            }
240            InnerContent::List(x) => InnerContent::List(x.slice(from, to)),
241            InnerContent::Future(f) => {
242                assert!(from == 0 && to == 1);
243                InnerContent::Future(f.clone())
244            }
245        }
246    }
247}
248
249impl Mergable for InnerContent {
250    fn is_mergable(&self, other: &Self, _conf: &()) -> bool
251    where
252        Self: Sized,
253    {
254        match (self, other) {
255            (InnerContent::List(x), InnerContent::List(y)) => x.is_mergable(y, &()),
256            _ => false,
257        }
258    }
259
260    fn merge(&mut self, _other: &Self, _conf: &())
261    where
262        Self: Sized,
263    {
264        match self {
265            InnerContent::List(x) => match _other {
266                InnerContent::List(y) => x.merge(y, &()),
267                _ => unreachable!(),
268            },
269            _ => unreachable!(),
270        }
271    }
272}