crdt_woot/
woot.rs

1use crate::crdt::{ListCrdt, OpSet};
2
3pub trait Woot: ListCrdt {
4    fn left(op: &Self::OpUnit) -> Option<Self::OpId>;
5    fn right(op: &Self::OpUnit) -> Option<Self::OpId>;
6    fn get_pos_of(container: &Self::Container, op_id: Self::OpId) -> usize;
7}
8
9pub fn integrate<T: Woot>(
10    container: &mut T::Container,
11    to_insert: T::OpUnit,
12    left: Option<T::OpId>,
13    right: Option<T::OpId>,
14) {
15    let mut set = T::Set::default();
16    let mut empty_between_left_and_right = true;
17    for ref op in T::iter(container, left, right) {
18        if (left.is_some() && T::contains(op, left.unwrap()))
19            || (right.is_some() && T::contains(op, right.unwrap()))
20        {
21            continue;
22        }
23
24        empty_between_left_and_right = false;
25        set.insert(op);
26    }
27
28    if empty_between_left_and_right {
29        match right {
30            Some(right) => T::insert_at(container, to_insert, T::get_pos_of(container, right)),
31            None => T::insert_at(container, to_insert, T::len(container)),
32        }
33        return;
34    }
35
36    let mut prev = left;
37    let mut next = right;
38    for ref iter_op in T::iter(container, left, right).filter(|op| {
39        let left = T::left(op);
40        let right = T::right(op);
41        (left.is_none() || !set.contain(left.unwrap()))
42            && (right.is_none() || !set.contain(right.unwrap()))
43    }) {
44        if Some(T::id(iter_op)) == left || Some(T::id(iter_op)) == right {
45            // left cannot be next, and right cannot be prev
46            continue;
47        }
48
49        if T::cmp_id(iter_op, &to_insert).is_lt() {
50            prev = Some(T::id(iter_op));
51        } else {
52            next = Some(T::id(iter_op));
53            break;
54        }
55    }
56
57    integrate::<T>(container, to_insert, prev, next);
58}