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 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}