use crate::{
error::PIRes,
id::IndexId,
index::{
config::{IndexOrd, IndexTypeInternal, Indexes},
keeper_tx::ExternalRefs,
tree::{
IndexApply,
key_changes::{KeyChanges, ValueChange},
nodes::compare,
},
},
};
use std::{
any::Any,
ops::{Bound, RangeBounds},
vec::IntoIter,
};
pub struct TxIndexChangesDynamic {
value: Box<dyn Any>,
apply: Box<dyn Applier>,
}
impl TxIndexChangesDynamic {
pub fn new<K: IndexTypeInternal + 'static, V: IndexTypeInternal + 'static>() -> Self {
Self {
value: Box::new(TypedTxIndexChanges::<K, V>::new()),
apply: Box::new(ApplierImpl::<K, V>::new()),
}
}
pub fn put<K: IndexOrd + Clone + 'static, V: IndexOrd + Clone + 'static>(&mut self, k: K, v: V) {
if let Some(values) = self.value.downcast_mut::<TypedTxIndexChanges<K, V>>() {
values.put(k, v);
}
}
pub fn remove<K: IndexOrd + Clone + 'static, V: IndexOrd + Clone + 'static>(&mut self, k: K, v: Option<V>) {
if let Some(values) = self.value.downcast_mut::<TypedTxIndexChanges<K, V>>() {
values.remove(k, v);
}
}
pub fn get<K: IndexOrd + Clone + 'static, V: IndexOrd + Clone + 'static>(
&self,
k: &K,
) -> Option<Vec<ValueChange<V>>> {
if let Some(values) = self.value.downcast_ref::<TypedTxIndexChanges<K, V>>() {
values.get(k)
} else {
None
}
}
pub fn range<K, V, R>(&self, range: R) -> IntoIter<K>
where
K: IndexOrd + Clone + 'static,
V: IndexOrd + Clone + 'static,
R: RangeBounds<K>,
{
if let Some(values) = self.value.downcast_ref::<TypedTxIndexChanges<K, V>>() {
values.range(range)
} else {
Vec::new().into_iter()
}
}
pub fn apply(&self, store: ExternalRefs<'_>, index_id: &IndexId) -> PIRes<()> {
self.apply.apply(store, index_id, &self.value)
}
}
struct TypedTxIndexChanges<K, V> {
values: Vec<KeyChanges<K, V>>,
}
impl<K, V> TypedTxIndexChanges<K, V> {
fn new() -> Self {
Self {
values: Default::default(),
}
}
}
impl<K: IndexOrd + Clone, V: IndexOrd + Clone> TypedTxIndexChanges<K, V> {
fn put(&mut self, k: K, v: V) {
match self.values.binary_search_by(|n| compare(&n.k, &k)) {
Ok(index) => {
self.values[index].put(v);
}
Err(index) => {
self.values.insert(index, KeyChanges::new(k, vec![ValueChange::Add(v)]));
}
}
}
fn remove(&mut self, k: K, v: Option<V>) {
match self.values.binary_search_by(|n| compare(&n.k, &k)) {
Ok(index) => {
self.values[index].remove(v);
}
Err(index) => {
self.values
.insert(index, KeyChanges::new(k, vec![ValueChange::Remove(v)]));
}
}
}
fn get(&self, k: &K) -> Option<Vec<ValueChange<V>>> {
match self.values.binary_search_by(|n| compare(&n.k, k)) {
Ok(index) => Some(self.values[index].changes()),
Err(_) => None,
}
}
fn get_all(&self) -> Vec<KeyChanges<K, V>> {
self.values.clone()
}
pub fn range<R>(&self, range: R) -> IntoIter<K>
where
R: RangeBounds<K>,
{
let v = &self.values;
let index = match range.start_bound() {
Bound::Included(k) => match v.binary_search_by(|n| compare(&n.k, k)) {
Ok(index) => Bound::Included(index),
Err(index) => Bound::Included(index),
},
Bound::Excluded(k) => match v.binary_search_by(|n| compare(&n.k, 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.k, k)) {
Ok(index) => Bound::Included(index),
Err(index) => Bound::Excluded(index),
},
Bound::Excluded(k) => match v.binary_search_by(|n| compare(&n.k, 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| val.k.clone())
.collect::<Vec<_>>()
.into_iter()
}
}
trait Applier {
fn apply(&self, persy: ExternalRefs<'_>, index: &IndexId, values: &Box<dyn Any>) -> PIRes<()>;
}
struct ApplierImpl<K, V> {
ph: std::marker::PhantomData<(K, V)>,
}
impl<K, V> ApplierImpl<K, V> {
fn new() -> Self {
Self { ph: Default::default() }
}
}
impl<K: IndexTypeInternal + 'static, V: IndexTypeInternal + 'static> Applier for ApplierImpl<K, V> {
fn apply(&self, store: ExternalRefs<'_>, index_id: &IndexId, values: &Box<dyn Any>) -> PIRes<()> {
if let Some(val) = values.downcast_ref::<TypedTxIndexChanges<K, V>>() {
let changes = val.get_all();
let mut index = Indexes::get_index_keeper_tx::<K, V>(store, index_id)?;
index.apply(&changes)?;
index.update_changed()?;
}
Ok(())
}
}