use std::borrow::Borrow;
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::marker::PhantomData;
use std::str::FromStr;
use std::vec;
use uuid::Uuid;
pub use error::*;
use crate::serializer::Serializer;
use crate::storage::Storage;
mod error;
type IndexDocument = HashMap<String, HashSet<Uuid>>;
#[derive(Debug, Clone)]
pub struct Index<T, S, R> {
id: Uuid,
storage: S,
_t: PhantomData<T>,
_r: PhantomData<R>,
}
impl<T, S, R> Index<T, S, R>
where S: Storage,
R: Serializer {
pub fn new(storage: S) -> Self {
Self::with_id(storage, Uuid::nil())
}
pub fn with_id(storage: S, id: Uuid) -> Self {
Self {
id,
storage,
_t: PhantomData,
_r: PhantomData,
}
}
pub fn find<Q>(&self, value: &Q) -> Result<HashSet<Uuid>>
where T: Borrow<Q>,
Q: Hash + ToString + ?Sized {
let mut index_document = self.read()?;
let value = value.to_string();
index_document.remove(&value).ok_or_else(|| IndexError::not_found())
}
pub fn find_all(&self) -> Result<IndexIterator<T>>
where T: FromStr {
IndexIterator::new(self.read()?)
}
pub fn add(&mut self, id: Uuid, value: &T) -> Result<()>
where T: Hash + ToString {
let mut index_document = self.read()?;
let mut has_changed = false;
has_changed = has_changed || index_document.entry(value.to_string()).or_insert_with(|| {
has_changed = true;
Default::default()
}).insert(id);
if has_changed {
self.write(index_document)?;
}
Ok(())
}
pub fn remove<Q>(&mut self, id: Uuid, value: &Q) -> Result<bool>
where T: Borrow<Q>,
Q: Hash + ToString + ?Sized {
let mut index_document = self.read()?;
let value = value.to_string();
let mut has_changed = false;
if let Some(ids) = index_document.get_mut(&value) {
has_changed = ids.remove(&id);
if ids.is_empty() { index_document.remove(&value); }
}
if has_changed { self.write(index_document)?; }
Ok(has_changed)
}
pub fn remove_id(&mut self, id: Uuid) -> Result<bool> {
let mut index_document = self.read()?;
let mut has_changed = false;
index_document.retain(|_, it| {
has_changed = has_changed || it.remove(&id);
it.len() > 0
});
if has_changed { self.write(index_document)?; }
Ok(has_changed)
}
pub fn remove_value<Q>(&mut self, value: &Q) -> Result<HashSet<Uuid>>
where T: Borrow<Q>,
Q: Hash + ToString + ?Sized {
let mut index_document = self.read()?;
match index_document.remove(&value.to_string()) {
Some(ids) => {
self.write(index_document)?;
Ok(ids)
}
None => {
Ok(Default::default())
}
}
}
pub fn clear(&mut self) -> Result<()> {
self.write(Default::default())
}
fn read(&self) -> Result<IndexDocument> {
match self.storage.read(self.id) {
Ok(reader) => Ok(R::deserialize(reader)?),
Err(e) if e.is_not_found() => Ok(Default::default()),
Err(e) => Err(e.into())
}
}
fn write(&mut self, index_document: IndexDocument) -> Result<()> {
Ok(R::serialize(self.storage.write(self.id)?, &index_document)?)
}
}
#[derive(Debug)]
pub struct IndexIterator<T> {
iterator: vec::IntoIter<(HashSet<Uuid>, T)>,
}
impl<T> IndexIterator<T>
where T: FromStr {
fn new(index_document: IndexDocument) -> Result<Self> {
let mut items = Vec::with_capacity(index_document.len());
for (value, ids) in index_document.into_iter() {
match T::from_str(&value) {
Ok(value) => items.push((ids, value)),
Err(_) => return Err(IndexError::syntax(format!("index value could not be parsed : {}", &value)))
}
}
Ok(Self {
iterator: items.into_iter()
})
}
}
impl<T> Iterator for IndexIterator<T> {
type Item = (HashSet<Uuid>, T);
fn next(&mut self) -> Option<Self::Item> {
self.iterator.next()
}
}