use crate::collections::{list::ListIndex, View};
use crate::lookup::store::{position::KeyPosition, Lookup, Retriever, Store, ViewCreator};
use std::ops::{Deref, Index};
#[derive(Debug, Clone)]
pub struct LkupList<S, I> {
pub(crate) store: S,
pub(crate) items: I,
}
impl<S, I> LkupList<S, I>
where
S: Store<Pos = usize>,
{
pub fn new<L, P, F, T>(lookup: L, field: F, items: I) -> Self
where
L: Lookup<S, P>,
P: KeyPosition<Pos = usize>,
F: Fn(&T) -> S::Key,
I: AsRef<[T]>,
{
let store = lookup.new_list_store(&field, items.as_ref().iter());
Self { store, items }
}
pub fn contains_lkup_key<Q>(&self, key: Q) -> bool
where
S: Retriever<Q>,
{
self.store.key_exist(key)
}
pub fn get_by_lkup_key<Q>(&self, key: Q) -> impl Iterator<Item = &I::Output>
where
S: Retriever<Q, Pos = usize>,
I: Index<usize>,
{
self.store.pos_by_key(key).iter().map(|p| &self.items[*p])
}
pub fn get_by_many_lkup_keys<It, Q>(&self, keys: It) -> impl Iterator<Item = &I::Output>
where
S: Retriever<Q, Pos = usize>,
I: Index<usize>,
It: IntoIterator<Item = Q>,
{
self.store.pos_by_many_keys(keys).map(|p| &self.items[*p])
}
pub fn lkup_ext(&self) -> &S::Target
where
S: Deref,
{
self.store.deref()
}
pub fn create_lkup_view<'a, It>(&'a self, keys: It) -> View<S::Retriever, ListIndex<'a, I>>
where
It: IntoIterator<Item = <S as ViewCreator<'a>>::Key>,
S: ViewCreator<'a>,
{
let view = self.store.create_view(keys);
View::new(view, ListIndex(&self.items))
}
}
impl<S, I> Deref for LkupList<S, I> {
type Target = I;
fn deref(&self) -> &Self::Target {
&self.items
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::lookup::{hash::HashLookup, index::IndexLookup, store::position::UniqueKeyPosition};
#[derive(Debug, PartialEq, Clone)]
struct Car(u16, String);
impl Car {
fn id(&self) -> u16 {
self.0
}
fn name(&self) -> String {
self.1.clone()
}
}
#[test]
fn lkuplist_u16() {
let items = [Car(99, "Audi".into()), Car(1, "BMW".into())];
let v = LkupList::new(IndexLookup::with_multi_keys(), Car::id, items);
assert_eq!(2, v.len());
assert!(v.contains_lkup_key(1));
assert!(v.contains_lkup_key(99));
assert!(!v.contains_lkup_key(1_000));
assert_eq!(
vec![&Car(1, "BMW".into())],
v.get_by_lkup_key(1).collect::<Vec<_>>()
);
assert_eq!(
vec![&Car(99, "Audi".into())],
v.get_by_lkup_key(99).collect::<Vec<_>>()
);
assert!(v.get_by_lkup_key(98).next().is_none());
assert_eq!(
vec![&Car(1, "BMW".into()), &Car(99, "Audi".into())],
v.get_by_many_lkup_keys([1, 99]).collect::<Vec<_>>()
);
assert_eq!(1, v.lkup_ext().min_key().unwrap());
assert_eq!(99, v.lkup_ext().max_key().unwrap());
assert_eq!(vec![1, 99], v.lkup_ext().keys().collect::<Vec<_>>());
}
#[test]
fn lkuplist_string() {
let items = vec![Car(99, "Audi".into()), Car(0, "BMW".into())];
let v = LkupList::new(HashLookup::with_unique_key(), Car::name, items);
assert!(v.contains_lkup_key("Audi"));
assert!(!v.contains_lkup_key("VW"));
assert_eq!(
vec![&Car(0, "BMW".into())],
v.get_by_lkup_key("BMW").collect::<Vec<_>>()
);
assert_eq!(
vec![&Car(99, "Audi".into()), &Car(0, "BMW".into())],
v.get_by_many_lkup_keys(["Audi", "BMW"]).collect::<Vec<_>>()
);
let keys = v
.lkup_ext()
.keys()
.cloned()
.collect::<std::collections::HashSet<_>>();
assert!(keys.contains("Audi"));
assert!(keys.contains("BMW"));
let view = v.create_lkup_view(["Audi".into()]);
assert!(view.contains_key("Audi"));
assert!(!view.contains_key("BMW"));
assert_eq!(
vec![&Car(99, "Audi".into())],
view.get_by_key("Audi").collect::<Vec<_>>()
);
assert_eq!(
vec![&Car(99, "Audi".into())],
view.get_by_many_keys(["Audi", "BMW", "VW"])
.collect::<Vec<_>>()
);
assert_eq!(
vec![&Car(99, "Audi".into())],
view.items().collect::<Vec<_>>()
);
assert_eq!(vec![&String::from("Audi")], view.keys().collect::<Vec<_>>());
}
#[test]
fn lkuplist_with_key_and_clone() {
let items = [Car(99, "Audi".into()), Car(1, "BMW".into())];
let v = LkupList::new(
IndexLookup::with_key::<UniqueKeyPosition<usize>>(),
Car::id,
items,
);
assert!(v.contains_lkup_key(99));
assert_eq!(&Car(1, "BMW".into()), &v[1]);
let v2 = v.clone();
assert!(v2.contains_lkup_key(99));
assert_eq!(&Car(1, "BMW".into()), &v2[1]);
assert_eq!(
vec![&Car(99, "Audi".into()), &Car(1, "BMW".into())],
v.get_by_many_lkup_keys([99, 1]).collect::<Vec<_>>()
);
}
}