You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
70 lines
2.0 KiB
70 lines
2.0 KiB
4 years ago
|
use super::*;
|
||
|
use std::borrow::Borrow;
|
||
|
use std::marker::PhantomData;
|
||
|
use std::iter;
|
||
|
use std::collections::{
|
||
|
btree_map::Range,
|
||
|
VecDeque,
|
||
|
};
|
||
|
use smallvec::SmallVec;
|
||
|
|
||
|
#[derive(Debug)]
|
||
|
pub struct StoreSearchIter<'a, T: ?Sized>(&'a Store, Option<Range<'a, String, ArenaIndex>>, VecDeque<&'a sha256::Sha256Hash>, PhantomData<T>);
|
||
|
|
||
|
// Accessing
|
||
|
impl Store
|
||
|
{
|
||
|
/// Search for all entries with *any* of these provided tags.
|
||
|
///
|
||
|
/// # Notes
|
||
|
/// This is allowed to produce duplicate entries.
|
||
|
pub fn tag_search_many<T: Ord>(&self, tags: impl IntoIterator<Item= T>) -> StoreSearchIter<'_, T>
|
||
|
where String: Borrow<T>
|
||
|
{
|
||
|
let mut sorted: SmallVec<[_; 5]> = tags.into_iter().collect();
|
||
|
sorted.sort();
|
||
|
StoreSearchIter(self, Some(match (sorted.first(), sorted.last()) {
|
||
|
(Some(low), Some(high)) => self.tags.range(low..=high),
|
||
|
_ => return StoreSearchIter(self, None, Default::default(), PhantomData),
|
||
|
}), VecDeque::new(), PhantomData)
|
||
|
}
|
||
|
/// Search for all items with this provided tag.
|
||
|
///
|
||
|
/// # Notes
|
||
|
/// This is allowed to produce duplicate entries, if an entry has two of the same tags.
|
||
|
pub fn tag_search<'a, T: Ord>(&'a self, tag: T) -> StoreSearchIter<'a, T>
|
||
|
where String: Borrow<T>
|
||
|
{
|
||
|
let tag = &tag;
|
||
|
StoreSearchIter(self, Some(self.tags.range(tag..=tag)), VecDeque::new(), PhantomData)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<'a, T: ?Sized> Iterator for StoreSearchIter<'a, T>
|
||
|
{
|
||
|
type Item = &'a Entry;
|
||
|
fn next(&mut self) -> Option<Self::Item>
|
||
|
{
|
||
|
if let Some(range) = &mut self.1 {
|
||
|
if let Some((_, &ti)) = range.next() {
|
||
|
// tag index get
|
||
|
let data_hashes = &self.0.data_hashes;
|
||
|
let iter = self.0.tag_mappings.get(ti)
|
||
|
.map_into_iter()
|
||
|
.filter_map(move |&idx| data_hashes.get(idx));
|
||
|
self.2.extend(iter);
|
||
|
}
|
||
|
} else {
|
||
|
return None;
|
||
|
}
|
||
|
self.2.pop_front().map(|x| self.0.data.get(x)).flatten()
|
||
|
}
|
||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||
|
match self.1 {
|
||
|
None => (0, Some(0)),
|
||
|
Some(_) => (0, None),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
impl<'a, T: ?Sized> iter::FusedIterator for StoreSearchIter<'a, T>{}
|