use persy::PRes;
use persy::{IndexType, Persy, PersyError};
use std::{borrow::Cow, marker::PhantomData, ops::RangeBounds};
pub struct Iter<K, V>(pub(crate) persy::IndexIter<K, V>)
where
K: IndexType,
V: IndexType;
impl<K, V> Iterator for Iter<K, V>
where
K: IndexType,
V: IndexType,
{
type Item = (K, persy::Value<V>);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
pub struct KeysIter<K, V>(
pub(crate) std::iter::Map<persy::IndexIter<K, V>, fn((K, persy::Value<V>)) -> K>,
)
where
K: IndexType,
V: IndexType;
impl<K, V> Iterator for KeysIter<K, V>
where
K: IndexType,
V: IndexType,
{
type Item = K;
#[inline]
fn next(&mut self) -> Option<K> {
self.0.next()
}
}
pub trait KV<K, V>
where
K: IndexType,
V: IndexType,
{
fn clear(&self) -> PRes<()>;
fn insert(&self, key: K, value: V) -> PRes<()>;
fn keys(&self) -> PRes<KeysIter<K, V>>;
fn remove(&self, key: K) -> PRes<()>;
}
pub struct BaseKV<K, V>(
Persy,
Cow<'static, str>,
persy::ValueMode,
PhantomData<(K, V)>,
);
impl<K, V> Clone for BaseKV<K, V> {
fn clone(&self) -> Self {
BaseKV(self.0.clone(), self.1.clone(), self.2.clone(), PhantomData)
}
}
impl<K, V> BaseKV<K, V>
where
K: IndexType,
V: IndexType,
{
pub fn new(p: &str, idxn: impl Into<Cow<'static, str>>, vm: persy::ValueMode) -> PRes<Self> {
Self::new_intern(p, idxn.into(), vm)
}
pub(crate) fn new_intern(p: &str, idxn: Cow<'static, str>, vm: persy::ValueMode) -> PRes<Self> {
match Persy::create(p) {
Ok(_) => {}
Err(PersyError::Io(ref e)) if e.kind() == std::io::ErrorKind::AlreadyExists => {}
Err(e) => return Err(e),
}
Self::with_backend_intern(Persy::open(p, persy::Config::new())?, idxn, vm)
}
pub fn with_backend(
persy: Persy,
idxn: impl Into<Cow<'static, str>>,
vm: persy::ValueMode,
) -> PRes<Self> {
Self::with_backend_intern(persy, idxn.into(), vm)
}
pub(crate) fn with_backend_intern(
persy: Persy,
idxn: Cow<'static, str>,
vm: persy::ValueMode,
) -> PRes<Self> {
let ridxn = idxn.as_ref();
if !persy.exists_index(ridxn)? {
let mut tx = persy.begin()?;
persy.create_index::<K, V>(&mut tx, ridxn, vm.clone())?;
let prepared = persy.prepare_commit(tx)?;
persy.commit(prepared)?;
}
Ok(BaseKV(persy, idxn, vm, PhantomData))
}
pub fn get(&self, key: &K) -> PRes<Option<persy::Value<V>>> {
self.0.get::<K, V>(self.1.as_ref(), key)
}
#[inline]
pub fn iter(&self) -> PRes<Iter<K, V>> {
self.range(..)
}
pub fn range<R>(&self, r: R) -> PRes<Iter<K, V>>
where
R: RangeBounds<K>,
{
self.0.range::<K, V, _>(self.1.as_ref(), r).map(Iter)
}
}
impl<K, V> KV<K, V> for BaseKV<K, V>
where
K: IndexType,
V: IndexType,
{
fn clear(&self) -> PRes<()> {
let mut tx = self.0.begin()?;
self.0.drop_index(&mut tx, self.1.as_ref())?;
self.0
.create_index::<K, V>(&mut tx, self.1.as_ref(), self.2.clone())?;
let prepared = self.0.prepare_commit(tx)?;
self.0.commit(prepared)
}
fn insert(&self, key: K, value: V) -> PRes<()> {
let mut tx = self.0.begin()?;
self.0.put::<K, V>(&mut tx, self.1.as_ref(), key, value)?;
let prepared = self.0.prepare_commit(tx)?;
self.0.commit(prepared)
}
#[inline]
fn keys(&self) -> PRes<KeysIter<K, V>> {
fn first_of2<A, B>(x: (A, B)) -> A {
x.0
}
Ok(KeysIter(self.range(..)?.0.map(first_of2)))
}
fn remove(&self, key: K) -> PRes<()> {
let mut tx = self.0.begin()?;
self.0.remove::<K, V>(&mut tx, self.1.as_ref(), key, None)?;
let prepared = self.0.prepare_commit(tx)?;
self.0.commit(prepared)
}
}