#![deny(missing_docs)]
#![forbid(unsafe_code)]
pub use persy::PRes;
use persy::{IndexType, Persy, PersyError};
use std::{borrow::Cow, marker::PhantomData, ops::RangeBounds};
mod private {
pub trait Sealed {
}
}
pub struct BaseKV<K, V>(
Persy,
Cow<'static, str>,
persy::ValueMode,
PhantomData<(K, V)>,
);
pub struct MultiKV<K, V>(BaseKV<K, V>);
pub struct SingleKV<K, V>(BaseKV<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> private::Sealed for BaseKV<K, V> { }
impl<K, V> Clone for MultiKV<K, V> {
fn clone(&self) -> Self {
MultiKV(self.0.clone())
}
}
impl<K, V> private::Sealed for MultiKV<K, V> { }
impl<K, V> Clone for SingleKV<K, V> {
fn clone(&self) -> Self {
SingleKV(self.0.clone())
}
}
impl<K, V> private::Sealed for SingleKV<K, V> { }
pub struct Iter<K, V>(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>(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 XKV<K, V> : private::Sealed
where
K: IndexType,
V: IndexType,
{
#[doc(hidden)]
fn underlying_base_kv(&self) -> &BaseKV<K, V>;
#[inline]
fn insert(&self, key: K, value: V) -> PRes<()> {
self.underlying_base_kv().insert(key, value)
}
#[inline]
fn remove(&self, key: K) -> PRes<()> {
self.underlying_base_kv().remove(key)
}
#[inline]
fn clear(&self) -> PRes<()> {
self.underlying_base_kv().clear()
}
#[inline]
fn keys(&self) -> PRes<KeysIter<K, V>> {
self.underlying_base_kv().keys()
}
}
impl<K, V> XKV<K, V> for MultiKV<K, V>
where
K: IndexType,
V: IndexType,
{
#[doc(hidden)]
fn underlying_base_kv(&self) -> &BaseKV<K, V> {
&self.0
}
}
impl<K, V> XKV<K, V> for SingleKV<K, V>
where
K: IndexType,
V: IndexType,
{
#[doc(hidden)]
fn underlying_base_kv(&self) -> &BaseKV<K, V> {
&self.0
}
}
fn first_of2<A, B>(x: (A, B)) -> A {
x.0
}
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),
}
let persy = Persy::open(p, persy::Config::new())?;
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 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)
}
pub 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)
}
pub 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)
}
#[inline]
pub fn keys(&self) -> PRes<KeysIter<K, V>> {
Ok(KeysIter(self.range(..)?.0.map(first_of2)))
}
pub fn get(&self, key: &K) -> PRes<Option<persy::Value<V>>> {
self.0.get::<K, V>(self.1.as_ref(), key)
}
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)
}
#[inline]
pub fn iter(&self) -> PRes<Iter<K, V>> {
self.range(..)
}
}
fn sharpen_value<V>(v: persy::Value<V>) -> Vec<V> {
use persy::Value;
match v {
Value::CLUSTER(x) => x,
Value::SINGLE(x) => vec![x],
}
}
fn flatten_value<V>(v: persy::Value<V>) -> Option<V> {
use persy::Value;
match v {
Value::CLUSTER(x) => x.into_iter().next(),
Value::SINGLE(x) => Some(x),
}
}
impl<K, V> MultiKV<K, V>
where
K: IndexType,
V: IndexType,
{
pub fn new(p: &str, idxn: impl Into<Cow<'static, str>>) -> PRes<Self> {
Ok(Self(BaseKV::new_intern(
p,
idxn.into(),
persy::ValueMode::CLUSTER,
)?))
}
pub fn get(&self, key: &K) -> PRes<Vec<V>> {
Ok(self.0.get(key)?.map(sharpen_value).unwrap_or_else(Vec::new))
}
pub fn iter(&self) -> PRes<impl Iterator<Item = (K, Vec<V>)>> {
Ok(self.0.range(..)?.map(|(k, v)| (k, sharpen_value(v))))
}
}
impl<K, V> SingleKV<K, V>
where
K: IndexType,
V: IndexType,
{
pub fn new(p: &str, idxn: impl Into<Cow<'static, str>>) -> PRes<Self> {
Ok(Self(BaseKV::new_intern(
p,
idxn.into(),
persy::ValueMode::REPLACE,
)?))
}
pub fn get(&self, key: &K) -> PRes<Option<V>> {
Ok(self.0.get(key)?.and_then(flatten_value))
}
pub fn iter(&self) -> PRes<impl Iterator<Item = (K, V)>> {
Ok(self
.0
.range(..)?
.filter_map(|(k, v)| flatten_value(v).map(|v2| (k, v2))))
}
}