1use std::collections::BTreeMap;
13
14use serde::{Deserialize, Serialize};
15
16use crate::log::command::{ElementKind, PropTag, PropWrite};
17use crate::log::id::{ElementId, WriteOrder};
18
19#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)]
23pub enum Liveness {
24 Live,
25 Deleted,
26}
27
28impl Liveness {
29 pub fn is_live(self) -> bool {
30 self == Liveness::Live
31 }
32}
33
34#[derive(Clone, Copy, PartialEq, Eq, Debug)]
37pub enum Applied {
38 Won,
39 LostToNewer,
42}
43
44#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
48pub struct Register {
49 pub value: Option<PropWrite>,
50 pub order: WriteOrder,
51}
52
53#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
54pub struct Element {
55 kind: ElementKind,
56 created: WriteOrder,
59 liveness: Liveness,
60 liveness_order: WriteOrder,
61 registers: BTreeMap<PropTag, Register>,
62}
63
64impl Element {
65 fn new(kind: ElementKind, created: WriteOrder) -> Self {
66 Self {
67 kind,
68 created,
69 liveness: Liveness::Live,
70 liveness_order: created,
71 registers: BTreeMap::new(),
72 }
73 }
74
75 pub fn kind(&self) -> ElementKind {
76 self.kind
77 }
78
79 pub fn created(&self) -> WriteOrder {
80 self.created
81 }
82
83 pub fn liveness(&self) -> Liveness {
84 self.liveness
85 }
86
87 pub fn is_live(&self) -> bool {
88 self.liveness.is_live()
89 }
90
91 pub fn get(&self, tag: PropTag) -> Option<&PropWrite> {
92 self.registers.get(&tag).and_then(|r| r.value.as_ref())
93 }
94
95 pub fn register(&self, tag: PropTag) -> Option<&Register> {
96 self.registers.get(&tag)
97 }
98
99 pub fn registers(&self) -> impl Iterator<Item = (PropTag, &Register)> {
101 self.registers.iter().map(|(tag, reg)| (*tag, reg))
102 }
103
104 pub fn parent(&self) -> Option<ElementId> {
105 match self.get(PropTag::Parent) {
106 Some(PropWrite::Parent(id)) => Some(*id),
107 _ => None,
108 }
109 }
110
111 fn write(&mut self, tag: PropTag, value: Option<PropWrite>, order: WriteOrder) -> Applied {
119 match self.registers.get(&tag) {
120 Some(held) if held.order > order => Applied::LostToNewer,
121 _ => {
122 self.registers.insert(tag, Register { value, order });
123 Applied::Won
124 }
125 }
126 }
127
128 fn set_liveness(&mut self, liveness: Liveness, order: WriteOrder) -> Applied {
129 if self.liveness_order > order {
130 return Applied::LostToNewer;
131 }
132 self.liveness = liveness;
133 self.liveness_order = order;
134 Applied::Won
135 }
136}
137
138#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
140pub struct DocState {
141 elements: BTreeMap<ElementId, Element>,
142}
143
144impl DocState {
145 pub fn new() -> Self {
146 Self::default()
147 }
148
149 pub fn len(&self) -> usize {
150 self.elements.len()
151 }
152
153 pub fn is_empty(&self) -> bool {
154 self.elements.is_empty()
155 }
156
157 pub fn contains(&self, id: ElementId) -> bool {
158 self.elements.contains_key(&id)
159 }
160
161 pub fn element(&self, id: ElementId) -> Option<&Element> {
162 self.elements.get(&id)
163 }
164
165 pub fn live(&self, id: ElementId) -> Option<&Element> {
169 self.elements.get(&id).filter(|e| e.is_live())
170 }
171
172 pub fn get(&self, id: ElementId, tag: PropTag) -> Option<&PropWrite> {
173 self.live(id)?.get(tag)
174 }
175
176 pub fn iter(&self) -> impl Iterator<Item = (ElementId, &Element)> {
178 self.elements.iter().map(|(id, e)| (*id, e))
179 }
180
181 pub fn children(&self, parent: ElementId) -> Vec<ElementId> {
185 let mut found: Vec<(WriteOrder, ElementId)> = self
186 .elements
187 .iter()
188 .filter(|(_, e)| e.is_live() && e.parent() == Some(parent))
189 .map(|(id, e)| (e.created, *id))
190 .collect();
191 found.sort_unstable();
192 found.into_iter().map(|(_, id)| id).collect()
193 }
194
195 pub fn is_rooted(&self, id: ElementId) -> bool {
200 let mut at = id;
201 for _ in 0..=self.elements.len() {
202 if at.is_document() {
203 return true;
204 }
205 match self.live(at).and_then(Element::parent) {
206 Some(parent) => at = parent,
207 None => return false,
208 }
209 }
210 false
211 }
212
213 pub(crate) fn ensure(&mut self, id: ElementId, kind: ElementKind, created: WriteOrder) {
214 match self.elements.get_mut(&id) {
215 Some(existing) => existing.created = existing.created.min(created),
218 None => {
219 self.elements.insert(id, Element::new(kind, created));
220 }
221 }
222 }
223
224 pub(crate) fn write(
225 &mut self,
226 id: ElementId,
227 tag: PropTag,
228 value: Option<PropWrite>,
229 order: WriteOrder,
230 ) -> Option<Applied> {
231 Some(self.elements.get_mut(&id)?.write(tag, value, order))
232 }
233
234 pub(crate) fn set_liveness(
235 &mut self,
236 id: ElementId,
237 liveness: Liveness,
238 order: WriteOrder,
239 ) -> Option<Applied> {
240 Some(self.elements.get_mut(&id)?.set_liveness(liveness, order))
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 use super::*;
247 use crate::log::id::{ActorId, BatchIndex, Lamport, Stamp};
248
249 fn order(lamport: u64, actor_byte: u8) -> WriteOrder {
250 WriteOrder::new(
251 Stamp {
252 lamport: Lamport::new(lamport),
253 actor: ActorId::from_uuid(uuid::Uuid::from_bytes([actor_byte; 16])),
254 },
255 BatchIndex::FIRST,
256 )
257 }
258
259 fn element(byte: u8) -> ElementId {
260 ElementId::from_uuid(uuid::Uuid::from_bytes([byte; 16]))
261 }
262
263 fn with_block(state: &mut DocState, id: ElementId, at: WriteOrder) {
264 state.ensure(id, ElementKind::Block, at);
265 set(state, id, PropWrite::Parent(ElementId::DOCUMENT), at);
266 }
267
268 fn set(state: &mut DocState, id: ElementId, value: PropWrite, at: WriteOrder) -> Applied {
271 state
272 .write(id, value.tag(), Some(value), at)
273 .expect("the element exists")
274 }
275
276 #[test]
277 fn a_stale_write_loses_and_leaves_the_value_alone() {
278 let mut state = DocState::new();
279 let id = element(1);
280 with_block(&mut state, id, order(1, 1));
281
282 assert_eq!(
283 set(&mut state, id, PropWrite::Accent(9), order(5, 1)),
284 Applied::Won
285 );
286 assert_eq!(
287 set(&mut state, id, PropWrite::Accent(2), order(3, 1)),
288 Applied::LostToNewer,
289 "a write ordered earlier must not land on a later one"
290 );
291 assert_eq!(state.get(id, PropTag::Accent), Some(&PropWrite::Accent(9)));
292 }
293
294 #[test]
297 fn two_writes_commute() {
298 let id = element(1);
299 let (early, late) = (
300 (PropWrite::Accent(1), order(4, 1)),
301 (PropWrite::Accent(2), order(6, 1)),
302 );
303
304 let mut forwards = DocState::new();
305 with_block(&mut forwards, id, order(1, 1));
306 set(&mut forwards, id, early.0.clone(), early.1);
307 set(&mut forwards, id, late.0.clone(), late.1);
308
309 let mut backwards = DocState::new();
310 with_block(&mut backwards, id, order(1, 1));
311 set(&mut backwards, id, late.0.clone(), late.1);
312 set(&mut backwards, id, early.0.clone(), early.1);
313
314 assert_eq!(forwards, backwards);
315 assert_eq!(
316 forwards.get(id, PropTag::Accent),
317 Some(&PropWrite::Accent(2))
318 );
319 }
320
321 #[test]
322 fn deleting_and_restoring_resolve_by_order_not_arrival() {
323 let id = element(1);
324 let mut delete_last = DocState::new();
325 with_block(&mut delete_last, id, order(1, 1));
326 delete_last.set_liveness(id, Liveness::Deleted, order(9, 1));
327 delete_last.set_liveness(id, Liveness::Live, order(5, 1));
328
329 let mut restore_last = DocState::new();
330 with_block(&mut restore_last, id, order(1, 1));
331 restore_last.set_liveness(id, Liveness::Live, order(5, 1));
332 restore_last.set_liveness(id, Liveness::Deleted, order(9, 1));
333
334 assert_eq!(delete_last, restore_last);
335 assert!(!delete_last.element(id).expect("still present").is_live());
336 assert!(
337 delete_last.live(id).is_none(),
338 "a tombstone is present but not part of the document"
339 );
340 }
341
342 #[test]
343 fn children_come_back_in_creation_order() {
344 let mut state = DocState::new();
345 let parent = element(1);
346 with_block(&mut state, parent, order(1, 1));
347
348 let (first, second) = (element(9), element(2));
350 state.ensure(first, ElementKind::Block, order(4, 1));
351 set(&mut state, first, PropWrite::Parent(parent), order(4, 1));
352 state.ensure(second, ElementKind::Block, order(7, 1));
353 set(&mut state, second, PropWrite::Parent(parent), order(7, 1));
354
355 assert!(first > second, "id order must differ from creation order");
356 assert_eq!(state.children(parent), vec![first, second]);
357 }
358
359 #[test]
360 fn a_tombstoned_child_leaves_its_parents_list() {
361 let mut state = DocState::new();
362 let parent = element(1);
363 let child = element(2);
364 with_block(&mut state, parent, order(1, 1));
365 state.ensure(child, ElementKind::Block, order(2, 1));
366 set(&mut state, child, PropWrite::Parent(parent), order(2, 1));
367 assert_eq!(state.children(parent), vec![child]);
368
369 state.set_liveness(child, Liveness::Deleted, order(3, 1));
370 assert!(state.children(parent).is_empty());
371 }
372
373 #[test]
376 fn a_parent_cycle_is_reported_unrooted_rather_than_looping() {
377 let mut state = DocState::new();
378 let (a, b) = (element(1), element(2));
379 state.ensure(a, ElementKind::Block, order(1, 1));
380 state.ensure(b, ElementKind::Block, order(2, 1));
381 set(&mut state, a, PropWrite::Parent(b), order(3, 1));
382 set(&mut state, b, PropWrite::Parent(a), order(4, 1));
383
384 assert!(!state.is_rooted(a));
385 assert!(!state.is_rooted(b));
386 }
387
388 #[test]
389 fn an_element_parented_to_the_document_is_rooted() {
390 let mut state = DocState::new();
391 let id = element(1);
392 with_block(&mut state, id, order(1, 1));
393 assert!(state.is_rooted(id));
394 }
395
396 #[test]
399 fn re_creating_keeps_the_earliest_creation_order() {
400 let mut state = DocState::new();
401 let id = element(1);
402 state.ensure(id, ElementKind::Block, order(5, 1));
403 state.ensure(id, ElementKind::Block, order(9, 1));
404 assert_eq!(state.element(id).expect("present").created(), order(5, 1));
405 }
406}