pub mod collections;
pub mod index;
#[doc(hidden)]
#[macro_export]
macro_rules! fast {
(
$fast:ident on $item:ident {
$( $store:tt: $store_type:ty => $item_field:tt $(.$item_field_func:ident)? ), + $(,)*
}
) => {
{
#[derive(Default)]
struct $fast {
$(
$store: $store_type,
)+
_items_: $crate::collections::rw::list_base::TriggerList<$item>,
}
impl $fast {
#[allow(dead_code)]
fn insert(&mut self, item: $item) -> usize {
use $crate::index::store::Store;
self._items_.push(item, |it: &$item, pos: usize| {
$(
self.$store.insert(
it.$item_field$(.$item_field_func())?,
pos
);
)+
})
}
#[allow(dead_code)]
fn update<U>(&mut self, pos: usize, update: U) -> bool
where
U: Fn(&mut $item)
{
use $crate::index::store::{Filterable, Store};
self._items_.get_mut(pos).map_or(false, |it| {
$(
let $store: <$store_type as Filterable>::Key = it.$item_field$(.$item_field_func())?;
)+
update(it);
$(
self.$store.update($store, pos, it.$item_field$(.$item_field_func())?);
)+
true
})
}
#[allow(dead_code)]
fn remove(&mut self, pos: usize) -> Option<$item> {
use $crate::index::store::Store;
use $crate::collections::rw::list_base::StoreOp;
self._items_.remove(pos, |trigger, it, idx| match trigger {
StoreOp::Delete => { $( self.$store.delete(it.$item_field$(.$item_field_func())?, &idx); )+ }
StoreOp::Insert => { $( self.$store.insert(it.$item_field$(.$item_field_func())?, idx); )+ }
})
}
#[allow(dead_code)]
fn iter(&self) -> impl Iterator<Item = &'_ $item> {
self._items_.iter()
}
$(
#[allow(dead_code)]
fn $store(&self) -> $crate::collections::Retriever<'_, $store_type, Vec<$item>> {
$crate::collections::Retriever::new(&self.$store, &self._items_)
}
)+
}
$fast::default()
}
};
}
#[cfg(test)]
mod tests {
use crate::{
fast,
index::{filter::Filter, map::MapIndex, store::Filterable, uint::UIntIndex},
};
#[derive(Debug, Eq, PartialEq)]
struct Car(usize, String);
#[test]
fn one_indexed_list_delete_item() {
let mut cars = fast!(Cars on Car {id: UIntIndex => 0});
cars.insert(Car(0, "Porsche".into()));
cars.insert(Car(1, "BMW".into()));
cars.insert(Car(2, "Porsche".into()));
cars.insert(Car(3, "Audi".into()));
cars.insert(Car(4, "VW".into()));
cars.insert(Car(5, "VW".into()));
let r = cars.iter().collect::<Vec<_>>();
assert_eq!(
vec![
&Car(0, "Porsche".into()),
&Car(1, "BMW".into()),
&Car(2, "Porsche".into()),
&Car(3, "Audi".into()),
&Car(4, "VW".into()),
&Car(5, "VW".into())
],
r
);
assert_eq!(Car(3, "Audi".into()), cars.remove(3).unwrap());
let r = cars.iter().collect::<Vec<_>>();
assert_eq!(
vec![
&Car(0, "Porsche".into()),
&Car(1, "BMW".into()),
&Car(2, "Porsche".into()),
&Car(5, "VW".into()),
&Car(4, "VW".into())
],
r
);
let r = cars.id().get_many([1, 3, 5]).collect::<Vec<_>>();
assert_eq!(vec![&Car(1, "BMW".into()), &Car(5, "VW".into())], r);
}
#[test]
fn one_indexed_list_idx() {
let mut cars = fast!(Cars on Car {id: UIntIndex => 0});
cars.insert(Car(2, "BMW".into()));
cars.insert(Car(5, "Audi".into()));
cars.insert(Car(2, "VW".into()));
cars.insert(Car(99, "Porsche".into()));
let r = cars.id().get(&2).collect::<Vec<_>>();
assert_eq!(vec![&Car(2, "BMW".into()), &Car(2, "VW".into())], r);
{
let mut r = cars.id().get_many(2..6);
assert_eq!(Some(&Car(2, "BMW".into())), r.next());
assert_eq!(Some(&Car(2, "VW".into())), r.next());
assert_eq!(Some(&Car(5, "Audi".into())), r.next());
assert_eq!(None, r.next());
}
let r = cars
.id()
.filter(|f| f.eq(&2) | f.eq(&100))
.collect::<Vec<_>>();
assert_eq!(&[&Car(2, "BMW".into()), &Car(2, "VW".into())], &r[..]);
assert_eq!(None, cars.id().get(&100).next());
cars.update(cars.id.get(&99)[0], |c| c.0 += 1);
let r = cars.id().get(&100).collect::<Vec<_>>();
assert_eq!(vec![&Car(100, "Porsche".into())], r);
assert!(cars.id().get(&100).next().is_some());
cars.remove(cars.id.get(&100)[0]);
assert_eq!(None, cars.id().get(&100).next());
}
#[test]
fn one_indexed_list_idx_min_max() {
let mut cars = fast!(Cars on Car {id: UIntIndex => 0});
cars.insert(Car(2, "BMW".into()));
cars.insert(Car(5, "Audi".into()));
cars.insert(Car(2, "VW".into()));
cars.insert(Car(99, "Porsche".into()));
let r = cars.id().get(&2).collect::<Vec<_>>();
assert_eq!(vec![&Car(2, "BMW".into()), &Car(2, "VW".into())], r);
use crate::index::store::MetaData;
assert_eq!(2, cars.id.meta().min_key());
assert_eq!(99, cars.id.meta().max_key());
}
#[test]
fn fast() {
let mut fast_cars = fast!(
FastCars on Car {
id: UIntIndex => 0,
id_map: MapIndex<usize> => 0,
name: MapIndex => 1.clone,
}
);
fast_cars.insert(Car(1, "Mercedes".into()));
fast_cars.insert(Car(4, "Porsche".into()));
let fid = Filter(&fast_cars.id);
let fname = Filter(&fast_cars.name);
assert_eq!([0], fast_cars.id_map.get(&1));
assert_eq!([1], fid.eq(&4) | fname.eq(&"Porsche".into()));
}
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
enum Gender {
Male,
Female,
#[default]
None,
}
impl From<Gender> for usize {
fn from(g: Gender) -> Self {
match g {
Gender::None => 0,
Gender::Male => 1,
Gender::Female => 2,
}
}
}
struct Person {
pk: usize,
multi: u16,
name: String,
gender: Gender,
}
impl Person {
fn new(pk: usize, multi: u16, name: &str, gender: Gender) -> Self {
Self {
pk,
multi,
name: name.to_string(),
gender,
}
}
}
#[test]
fn person_indices() {
use Gender::*;
let mut persons = fast!(
Persons on Person {
pk: UIntIndex => pk,
multi: UIntIndex<u16> => multi,
name: MapIndex => name.clone,
gender: UIntIndex<Gender> => gender.into,
}
);
persons.insert(Person::new(3, 7, "Jasmin", Female));
persons.insert(Person::new(41, 7, "Mario", Male));
persons.insert(Person::new(111, 234, "Paul", Male));
assert_eq!([1], persons.pk.get(&41));
assert_eq!([0], persons.pk.get(&3));
assert!(persons.pk.get(&101).is_empty());
assert_eq!([0, 1], persons.multi.get(&7));
let f = Filter(&persons.multi);
assert_eq!([0, 1], f.eq(&3) | f.eq(&7));
assert_eq!([0], persons.name.get(&"Jasmin".into()));
let f = Filter(&persons.name);
assert_eq!([0, 1], f.eq(&"Jasmin".into()) | f.eq(&"Mario".into()));
assert_eq!([1, 2], persons.gender.get(&Male));
assert_eq!([0], persons.gender.get(&Female));
}
#[test]
fn different_idxs() {
use crate::index::store::Store;
use Gender::*;
let p = Person::new(0, 0, "Julia", Female);
let mut gender = UIntIndex::<Gender>::default();
gender.insert(p.gender, 1);
gender.insert(Male, 2);
gender.insert(None, 0);
let mut name = MapIndex::default();
name.insert(p.name.as_ref(), 1);
name.insert("b", 2);
name.insert("z", 0);
let fname = Filter(&name);
let fgender = Filter(&gender);
assert_eq!([1], fgender.eq(&Female) & fname.eq(&"Julia"));
assert_eq!(
[0, 1],
fname.eq(&"z") | fgender.eq(&Female) & fname.eq(&"Julia")
);
}
}