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>,
);