persy 1.8.0

Transactional Persistence Engine
Documentation
use crate::{
    error::PIRes,
    id::{IndexId, PersyId},
    index::{
        bytevec::ByteVec,
        config::{IndexOrd, IndexTypeInternal, Indexes},
        keeper_tx::ExternalRefs,
        string_wrapper::StringWrapper,
        tree::{
            IndexApply,
            key_changes::{KeyChanges, ValueChange},
            nodes::compare,
        },
    },
};

use std::{
    ops::{Bound, RangeBounds},
    vec::IntoIter,
};

pub(crate) fn apply_to_index<'a, K, V>(
    store: ExternalRefs<'a>,
    index_id: &IndexId,
    keys: &[(K, Changes)],
    values: &[V],
) -> PIRes<()>
where
    K: IndexTypeInternal,
    V: IndexTypeInternal,
{
    let changes: Vec<_> = keys
        .iter()
        .map(|(k, c)| {
            let vals: Vec<_> = c
                .changes
                .iter()
                .map(|ch| match *ch {
                    Change::Add(pos) => ValueChange::Add(values[pos].clone()),
                    Change::Remove(pos) => ValueChange::Remove(pos.map(|p| values[p].clone())),
                })
                .collect();
            KeyChanges::new(k.clone(), vals)
        })
        .collect();
    let mut index = Indexes::get_index_keeper_tx::<K, V>(store, index_id)?;
    index.apply(&changes)?;
    index.update_changed()?;
    Ok(())
}

#[derive(Clone)]
pub enum Change {
    Add(usize),
    Remove(Option<usize>),
}

#[derive(Clone)]
pub struct Changes {
    pub(crate) changes: Vec<Change>,
}

impl Changes {
    fn new(change: Change) -> Changes {
        Changes { changes: vec![change] }
    }
    fn push(&mut self, change: Change) {
        self.changes.push(change);
    }
}

pub struct TxIndexChangesEnum(EntriesContainer, ValueContainer);

impl TxIndexChangesEnum {
    pub fn new<K: IndexTypeInternal, V: IndexTypeInternal>() -> Self {
        let values = V::new_values();
        let keys = K::new_entries();
        TxIndexChangesEnum(keys, values)
    }
    pub fn put<K: IndexTypeInternal, V: IndexTypeInternal>(&mut self, k: K, v: V) {
        let pos = add_value(&mut self.1, v);
        add_entry(&mut self.0, k, Change::Add(pos));
    }

    pub fn remove<K: IndexTypeInternal, V: IndexTypeInternal>(&mut self, k: K, v: Option<V>) {
        let pos = v.map(|val| add_value(&mut self.1, val));
        add_entry(&mut self.0, k, Change::Remove(pos));
    }

    pub(crate) fn get<K: IndexTypeInternal, V: IndexTypeInternal>(&self, k: &K) -> Option<Vec<ValueChange<V>>> {
        get_changes(&self.0, k).map(|c| resolve_values(&self.1, c))
    }

    pub fn apply(&self, store: ExternalRefs<'_>, index_id: &IndexId) -> PIRes<()> {
        eapplier(&self.0, &self.1, index_id, store)?;
        Ok(())
    }

    pub fn range<K, V, R>(&self, range: R) -> IntoIter<K>
    where
        K: IndexTypeInternal,
        V: IndexTypeInternal,
        R: RangeBounds<K>,
    {
        resolve_range(&self.0, range)
    }
}

pub(crate) fn add_value<V: Extractor>(values: &mut ValueContainer, val: V) -> usize {
    let v = V::get_vec_mut(values);
    let l = v.len();
    v.push(val);
    l
}
pub(crate) fn resolve_values<V: Extractor>(values: &ValueContainer, changes: Changes) -> Vec<ValueChange<V>> {
    let v = V::get_vec(values);
    changes
        .changes
        .iter()
        .map(|c| match c {
            Change::Add(p) => ValueChange::Add(v[*p].clone()),
            Change::Remove(o) => ValueChange::Remove(o.map(|p| v[p].clone())),
        })
        .collect()
}
pub(crate) fn add_entry<K: Extractor>(entries: &mut EntriesContainer, k: K, change: Change) {
    let v = K::get_entries_mut(entries).expect("wrong match from the type and the value container");
    match v.binary_search_by(|n| compare(&n.0, &k)) {
        Ok(index) => {
            v[index].1.push(change);
        }
        Err(index) => {
            v.insert(index, (k, Changes::new(change)));
        }
    }
}

pub(crate) fn get_changes<K: Extractor>(entries: &EntriesContainer, k: &K) -> Option<Changes> {
    if let Some(v) = K::get_entries(entries) {
        match v.binary_search_by(|n| compare(&n.0, k)) {
            Ok(index) => v.get(index).map(|x| x.1.clone()),
            Err(_) => None,
        }
    } else {
        None
    }
}

pub(crate) fn resolve_range<T: Extractor, R>(entries: &EntriesContainer, range: R) -> IntoIter<T>
where
    R: RangeBounds<T>,
{
    let v = T::get_entries(entries).expect("wrong match from the type and the value container");
    let index = match range.start_bound() {
        Bound::Included(k) => match v.binary_search_by(|n| compare(&n.0, k)) {
            Ok(index) => Bound::Included(index),
            Err(index) => Bound::Included(index),
        },
        Bound::Excluded(k) => match v.binary_search_by(|n| compare(&n.0, k)) {
            Ok(index) => Bound::Excluded(index),
            Err(index) => Bound::Excluded(index),
        },
        Bound::Unbounded => Bound::Unbounded,
    };
    let end_index = match range.end_bound() {
        Bound::Included(k) => match v.binary_search_by(|n| compare(&n.0, k)) {
            Ok(index) => Bound::Included(index),
            Err(index) => Bound::Excluded(index),
        },
        Bound::Excluded(k) => match v.binary_search_by(|n| compare(&n.0, k)) {
            Ok(index) => Bound::Excluded(index),
            Err(index) => Bound::Excluded(index),
        },
        Bound::Unbounded => Bound::Unbounded,
    };
    let start = match index {
        Bound::Included(start) => start,
        Bound::Excluded(start) => start + 1,
        Bound::Unbounded => 0,
    };

    let end = match end_index {
        Bound::Included(end) => end + 1,
        Bound::Excluded(end) => end,
        Bound::Unbounded => v.len(),
    };

    v.get(start..end)
        .expect("the range is every time valid")
        .iter()
        .map(|(val, _): &(T, _)| val.clone())
        .collect::<Vec<_>>()
        .into_iter()
}

macro_rules! impl_index_data_type {
    ($t:ty, $v:path, $v2:path) => {
        impl Extractor for $t {
            fn get_vec_mut(vc: &mut ValueContainer) -> &mut Vec<$t> {
                if let $v(v) = vc {
                    v
                } else {
                    panic!("wrong match from type and value container")
                }
            }
            fn get_vec(vc: &ValueContainer) -> &Vec<$t> {
                if let $v(v) = vc {
                    v
                } else {
                    panic!("wrong match from type and value container")
                }
            }

            fn get_entries(vc: &EntriesContainer) -> Option<&Vec<($t, Changes)>> {
                if let $v2(v) = vc { Some(v) } else { None }
            }
            fn get_entries_mut(vc: &mut EntriesContainer) -> Option<&mut Vec<($t, Changes)>> {
                if let $v2(v) = vc { Some(v) } else { None }
            }
            fn new_entries() -> EntriesContainer {
                $v2(Vec::new())
            }

            fn new_values() -> ValueContainer {
                $v(Vec::new())
            }
        }
    };
}

pub trait Extractor: IndexOrd + Sized + Clone {
    fn get_vec_mut(vc: &mut ValueContainer) -> &mut Vec<Self>;
    fn get_vec(vc: &ValueContainer) -> &Vec<Self>;
    fn get_entries(vc: &EntriesContainer) -> Option<&Vec<(Self, Changes)>>;
    fn get_entries_mut(vc: &mut EntriesContainer) -> Option<&mut Vec<(Self, Changes)>>;
    fn new_entries() -> EntriesContainer;
    fn new_values() -> ValueContainer;
}

macro_rules! container_enums {
    ($($variant:ident<$t:ty>),+,) => {
        #[derive(Clone)]
        pub enum EntriesContainer {
            $(
            $variant(Vec<($t, Changes)>),
            )+
        }

        #[derive(Clone)]
        pub enum ValueContainer {
            $(
            $variant(Vec<$t>),
            )+
        }

        pub(crate) fn eapplier<'a>(
            keys: &EntriesContainer,
            values: &ValueContainer,
            index_id: &IndexId,
            store: ExternalRefs<'a>,
        ) -> PIRes<()> {
            match keys {
                $(
                EntriesContainer::$variant(k) => valapplier::<$t>(values, k, index_id, store),
                )+
            }
        }

        fn valapplier<'a, K>(
            values: &ValueContainer,
            k: &[(K, Changes)],
            index_id: &IndexId,
            store: ExternalRefs<'a>,
        ) -> PIRes<()>
        where
            K: IndexTypeInternal,
        {
            match values {
                $(
                ValueContainer::$variant(v) => apply_to_index::<K, $t>(store, index_id, k, v),
                )+
            }
        }

        $(
            impl_index_data_type!($t, ValueContainer::$variant, EntriesContainer::$variant);
        )+
    }
}

container_enums!(
    U8<u8>,
    U16<u16>,
    U32<u32>,
    U64<u64>,
    U128<u128>,
    I8<i8>,
    I16<i16>,
    I32<i32>,
    I64<i64>,
    I128<i128>,
    F32W<f32>,
    F64W<f64>,
    StringWrapper<StringWrapper>,
    PersyId<PersyId>,
    ByteVec<ByteVec>,
);