rol 0.1.0

replicated object log
Documentation
use std::sync::Arc;

mod object;

pub use object::{Oid, Object};

pub struct Db<O: Object + ?Sized> {
    mapping: Vec<u64>,
    ops: Vec<ObjectOp<O>>
}

impl<O: Object + ?Sized> Db<O> {
    pub fn new() -> Self {
        Self {
            mapping: Vec::new(),
            ops: Vec::new()
        }
    }
    pub fn get(&self, oid: Oid, max_offset: u64) -> Option<Arc<O>> {
        let idx: usize = oid.0.try_into().unwrap();
        let mut offset = *self.mapping.get(idx)?;
        let mut changes = vec![];
        let mut obj = loop {
            match &self.ops[offset as usize] {
                ObjectOp::Put( _ , obj ) => break obj.clone(),
                ObjectOp::Patch { prev_offset, change, .. } => {
                    if max_offset >= offset {
                        changes.push(change);
                    }
                    offset = *prev_offset;
                }
            }
        };
        if offset > max_offset { return None; }
        if changes.len() > 0 { 
            Arc::make_mut(&mut obj).apply(changes.as_slice());
        }
        Some(obj)
    }
    pub fn patch(&mut self, oid: Oid, change: O::Change) {
        let idx: usize = oid.0.try_into().unwrap();
        let prev_offset = self.mapping[idx];
        let offset = self.ops.len();
        self.ops.push(ObjectOp::Patch {
            oid,
            prev_offset,
            change
        });
        self.mapping[idx] = offset as u64;
    }
    pub fn replace(&mut self, oid: Oid, obj: Arc<O>) {
        let idx: usize = oid.0.try_into().unwrap();
        let offset = self.ops.len();
        self.ops.push(ObjectOp::Put(oid, obj));
        self.mapping[idx] = offset as u64;
    }
    pub fn insert(&mut self, obj: Arc<O>) -> Oid {
        let idx = self.mapping.len();
        let oid = Oid(idx as u64);
        let offset = self.ops.len() as u64;
        self.ops.push(ObjectOp::Put(oid, obj));
        self.mapping.push(offset);
        oid
    }
}

pub enum ObjectOp<O: Object + ?Sized> {
    Put(Oid, Arc<O>),
    Patch {
        oid: Oid,
        prev_offset: u64,
        change: O::Change
    }
}

#[cfg(test)]
mod test {
    use std::sync::Arc;

    use crate::{Object, Db};

    #[test]
    fn test() {
        #[derive(Clone, Debug, PartialEq, Eq)]
        struct L(Vec<&'static str>);

        impl Object for L {
            type Change = &'static str;

            fn apply(&mut self, changes: &[&&'static str]) {
                for s in changes.iter().rev() {
                    self.0.push(**s);
                }
            }
        }

        let mut db = Db::new();
        
        let o1 = db.insert(Arc::new(L(vec![])));
        let o2 = db.insert(Arc::new(L(vec!["d"])));

        db.patch(o1, "a");
        db.patch(o2, "e");
        db.patch(o1, "b");
        db.patch(o1, "c");

        assert_eq!(db.get(o1, 5), Some(Arc::new(L(vec!["a", "b", "c"]))));
        assert_eq!(db.get(o1, 1000), Some(Arc::new(L(vec!["a", "b", "c"]))));
        assert_eq!(db.get(o2, 5), Some(Arc::new(L(vec!["d", "e"]))));
        assert_eq!(db.get(o1, 3), Some(Arc::new(L(vec!["a"]))));

        db.replace(o1, Arc::new(L(vec!["1", "2", "3"])));
        db.patch(o1, "4");

        assert_eq!(db.get(o1, 5), None);
        assert_eq!(db.get(o1, 6), Some(Arc::new(L(vec!["1", "2", "3"]))));
        assert_eq!(db.get(o1, 1000), Some(Arc::new(L(vec!["1", "2", "3", "4"]))));
    }
}