use std::borrow::Cow;
use std::marker::PhantomData;
use super::{StorageKey, StorageValue, Snapshot, Fork, Iter};
use storage::indexes_metadata::{self, IndexType, INDEXES_METADATA_TABLE_NAME};
#[derive(Debug)]
pub struct BaseIndex<T> {
name: String,
prefix: Option<Vec<u8>>,
is_mutable: bool,
index_type: IndexType,
view: T,
}
pub struct BaseIndexIter<'a, K, V> {
base_iter: Iter<'a>,
base_prefix_len: usize,
prefix: Vec<u8>,
ended: bool,
_k: PhantomData<K>,
_v: PhantomData<V>,
}
impl<T> BaseIndex<T>
where
T: AsRef<Snapshot>,
{
pub fn new<S: AsRef<str>>(name: S, index_type: IndexType, view: T) -> Self {
assert_valid_name(&name);
indexes_metadata::assert_index_type(name.as_ref(), index_type, view.as_ref());
BaseIndex {
name: name.as_ref().to_string(),
prefix: None,
is_mutable: false,
index_type,
view,
}
}
pub fn with_prefix<S: AsRef<str>>(
name: S,
prefix: Vec<u8>,
index_type: IndexType,
view: T,
) -> Self {
assert_valid_name(&name);
indexes_metadata::assert_index_type(name.as_ref(), index_type, view.as_ref());
BaseIndex {
name: name.as_ref().to_string(),
prefix: Some(prefix),
is_mutable: false,
index_type,
view,
}
}
pub(crate) fn indexes_metadata(view: T) -> Self {
BaseIndex {
name: INDEXES_METADATA_TABLE_NAME.to_string(),
prefix: None,
is_mutable: true,
index_type: IndexType::Map,
view,
}
}
fn prefixed_key<K: StorageKey + ?Sized>(&self, key: &K) -> Vec<u8> {
match self.prefix {
Some(ref prefix) => {
let mut v = vec![0; prefix.len() + key.size()];
v[..prefix.len()].copy_from_slice(prefix);
key.write(&mut v[prefix.len()..]);
v
}
None => {
let mut v = vec![0; key.size()];
key.write(&mut v);
v
}
}
}
pub fn get<K, V>(&self, key: &K) -> Option<V>
where
K: StorageKey + ?Sized,
V: StorageValue,
{
self.view
.as_ref()
.get(&self.name, &self.prefixed_key(key))
.map(|v| StorageValue::from_bytes(Cow::Owned(v)))
}
pub fn contains<K>(&self, key: &K) -> bool
where
K: StorageKey + ?Sized,
{
self.view.as_ref().contains(
&self.name,
&self.prefixed_key(key),
)
}
pub fn iter<P, K, V>(&self, subprefix: &P) -> BaseIndexIter<K, V>
where
P: StorageKey,
K: StorageKey,
V: StorageValue,
{
let iter_prefix = self.prefixed_key(subprefix);
BaseIndexIter {
base_iter: self.view.as_ref().iter(&self.name, &iter_prefix),
base_prefix_len: self.prefix.as_ref().map_or(0, |p| p.len()),
prefix: iter_prefix,
ended: false,
_k: PhantomData,
_v: PhantomData,
}
}
pub fn iter_from<P, F, K, V>(&self, subprefix: &P, from: &F) -> BaseIndexIter<K, V>
where
P: StorageKey,
F: StorageKey + ?Sized,
K: StorageKey,
V: StorageValue,
{
let iter_prefix = self.prefixed_key(subprefix);
let iter_from = self.prefixed_key(from);
BaseIndexIter {
base_iter: self.view.as_ref().iter(&self.name, &iter_from),
base_prefix_len: self.prefix.as_ref().map_or(0, |p| p.len()),
prefix: iter_prefix,
ended: false,
_k: PhantomData,
_v: PhantomData,
}
}
}
impl<'a> BaseIndex<&'a mut Fork> {
fn set_index_type(&mut self) {
if !self.is_mutable {
indexes_metadata::set_index_type(&self.name, self.index_type, &mut self.view);
self.is_mutable = true;
}
}
pub fn put<K, V>(&mut self, key: &K, value: V)
where
K: StorageKey,
V: StorageValue,
{
self.set_index_type();
let key = self.prefixed_key(key);
self.view.put(&self.name, key, value.into_bytes());
}
pub fn remove<K>(&mut self, key: &K)
where
K: StorageKey + ?Sized,
{
self.set_index_type();
let key = self.prefixed_key(key);
self.view.remove(&self.name, key);
}
pub fn clear(&mut self) {
self.set_index_type();
self.view.remove_by_prefix(&self.name, self.prefix.as_ref());
}
}
impl<'a, K, V> Iterator for BaseIndexIter<'a, K, V>
where
K: StorageKey,
V: StorageValue,
{
type Item = (K::Owned, V);
fn next(&mut self) -> Option<Self::Item> {
if self.ended {
return None;
}
if let Some((k, v)) = self.base_iter.next() {
if k.starts_with(&self.prefix) {
return Some((
K::read(&k[self.base_prefix_len..]),
V::from_bytes(Cow::Borrowed(v)),
));
}
}
self.ended = true;
None
}
}
impl<'a, K, V> ::std::fmt::Debug for BaseIndexIter<'a, K, V> {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "BaseIndexIter(..)")
}
}
fn is_valid_name<S: AsRef<str>>(name: S) -> bool {
name.as_ref().as_bytes().iter().all(|c| match *c {
48...57 | 65...90 | 97...122 | 95 | 46 => true,
_ => false,
})
}
fn assert_valid_name<S: AsRef<str>>(name: S) {
if !is_valid_name(name) {
panic!("Wrong characters using in name. Use: a-zA-Z0-9 and _");
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_index_name_validator() {
assert!(is_valid_name("index_name"));
assert!(is_valid_name("_index_name"));
assert!(is_valid_name("AinDex_name_"));
assert!(is_valid_name("core.index_name1Z"));
assert!(is_valid_name("configuration.indeX_1namE"));
assert!(is_valid_name("1index_Namez"));
assert!(!is_valid_name("index-name"));
assert!(!is_valid_name("_index-name"));
assert!(!is_valid_name("индекс_name_"));
assert!(!is_valid_name("core.index_имя3"));
assert!(!is_valid_name("indeX_1namE-"));
assert!(!is_valid_name("1in!dex_Namez"));
}
#[test]
fn check_valid_name() {
assert_valid_name("valid_name");
}
#[test]
#[should_panic(expected = "Wrong characters using in name. Use: a-zA-Z0-9 and _")]
fn check_invalid_name() {
assert_valid_name("invalid-name");
}
}