cojson 0.6.0

Collaborative JSON (A high performance CRDT)
Documentation
use std::cmp::Ordering;

use super::ops::Op;

pub fn noncausal_sort(a: &Op, b: &Op) -> Ordering {
    a.time
        .cmp(&b.time)
        .then_with(|| a.id.0.cmp(&b.id.0))
        .then_with(|| a.id.1.cmp(&b.id.1))
}

pub(crate) fn only_in_first_sorted_list<
    T: Clone,
    L: IndexableList<T>,
    F: Fn(&T, &T) -> Ordering,
>(
    a: &L,
    b: &L,
    compare: F,
) -> Vec<T> {
    if b.size() == 0 {
        return a.iter().cloned().collect();
    }

    let mut result = vec![];

    let mut maybe_a_item = a.at(0);
    let mut maybe_b_item = b.at(0);

    let mut i_a = 0;
    let mut i_b = 0;

    while let Some(a_item) = maybe_a_item {
        if let Some(b_item) = maybe_b_item {
            let ordering = compare(a_item, b_item);

            match ordering {
                Ordering::Less => {
                    // missing in B
                    result.push(a_item.clone());
                    i_a += 1;
                    maybe_a_item = a.at(i_a);
                }
                Ordering::Greater => {
                    // missing in A, ignore
                    i_b += 1;
                    maybe_b_item = b.at(i_b);
                }
                Ordering::Equal => {
                    i_a += 1;
                    maybe_a_item = a.at(i_a);
                    i_b += 1;
                    maybe_b_item = b.at(i_b);
                }
            }
        } else {
            result.push(a_item.clone());
            i_a += 1;
            maybe_a_item = a.at(i_a);
        }
    }

    result
}

pub(crate) fn search_from_back<T, L: IndexableList<T>, F: Fn(&T, &T) -> Ordering>(
    list: &L,
    item: &T,
    compare: F,
) -> Result<usize, usize> {
    let mut insertion_pos = list.size();
    while insertion_pos > 0 {
        let prev = list
            .at(insertion_pos - 1)
            .expect("Should have never entered for loop if no deletes.");
        let ordering = compare(prev, item);
        match ordering {
            Ordering::Less => break,
            Ordering::Greater => {}
            Ordering::Equal => return Result::Ok(insertion_pos),
        }
        insertion_pos -= 1;
    }
    Result::Err(insertion_pos)
}

pub(crate) trait IndexableList<T> {
    fn size(&self) -> usize;
    fn at(&self, at: usize) -> Option<&T>;
    fn last(&self) -> Option<&T>;
    fn iter<'a>(&'a self) -> Box<dyn DoubleEndedIterator<Item = &T> + 'a>;
}

impl<T> IndexableList<T> for Box<dyn IndexableList<T>> {
    fn size(&self) -> usize {
        self.as_ref().size()
    }

    fn at(&self, at: usize) -> Option<&T> {
        self.as_ref().at(at)
    }

    fn last(&self) -> Option<&T> {
        self.as_ref().last()
    }

    fn iter<'a>(&'a self) -> Box<dyn DoubleEndedIterator<Item = &T> + 'a> {
        self.as_ref().iter()
    }
}

impl<T: Clone> IndexableList<T> for im::Vector<T> {
    fn size(&self) -> usize {
        self.len()
    }

    fn at(&self, at: usize) -> Option<&T> {
        self.get(at)
    }

    fn last(&self) -> Option<&T> {
        self.last()
    }

    fn iter<'a>(&'a self) -> Box<dyn DoubleEndedIterator<Item = &T> + 'a> {
        Box::new(self.iter())
    }
}