1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*!
Simple persistent generic HashMap/Key-value store, using the Persy Index API.

This is in a beta state at the moment.

Basic usage:

```
let test_store = perkv::KV::<String, String>::new("./basic.cab").unwrap();

let _ = test_store.insert("key", "value");
println!("{:?}", test_store.get("key"));
let _ = test_store.remove("key");

# let _ = std::fs::remove_file("./basic.cab");
```

*/

#![deny(missing_docs)]
#![forbid(unsafe_code)]

use bincode::{deserialize, serialize};
use delegate::delegate;
use persawkv::{prelude::*, SingleKV};
pub use persy::PRes;
use persy::{ByteVec, PersyError};
use serde::{de::Deserialize, ser::Serialize};
use std::{borrow::Borrow, marker::PhantomData};

/// The type that represents the key-value store
pub struct KV<K, V>(SingleKV<ByteVec, ByteVec>, PhantomData<(K, V)>);

/// This function casts bincode errors into equivalent persy errors
fn map_encoderr(e: bincode::ErrorKind) -> PersyError {
    use bincode::ErrorKind;
    match e {
        ErrorKind::Io(x) => x.into(),
        ErrorKind::InvalidUtf8Encoding(x) => x.into(),
        x => PersyError::Custom(Box::new(x)),
    }
}

fn encode_kv<T>(x: &T) -> PRes<ByteVec>
where
    T: Serialize + ?Sized,
{
    serialize(x)
        .map_err(|y| *y)
        .map_err(map_encoderr)
        .map(ByteVec)
}

fn decode_kv<'a, T>(x: &'a ByteVec) -> PRes<T>
where
    T: Deserialize<'a>,
{
    deserialize(x.0.as_slice())
        .map_err(|y| *y)
        .map_err(map_encoderr)
}

impl<K, V> Clone for KV<K, V> {
    fn clone(&self) -> Self {
        KV(self.0.clone(), PhantomData)
    }
}

impl<K, V> KV<K, V>
where
    K: Eq + Serialize,
    V: for<'vde> Deserialize<'vde> + Serialize,
{
    /// Creates a new instance of the KV store
    pub fn new(p: &str) -> PRes<KV<K, V>> {
        Ok(KV(SingleKV::new(p, "perkv")?, PhantomData))
    }

    /// Inserts a key-value pair into the KV store
    ///
    /// The key may be any borrowed form of the store's key type, but
    /// [`Eq`] and [`Serialize`] on the borrowed form *must* match those
    /// for the key type. This also applies to value type/store's value type.
    pub fn insert<Q, U>(&self, key: &Q, value: &U) -> PRes<()>
    where
        K: Borrow<Q>,
        Q: Eq + Serialize + ?Sized,
        V: Borrow<U>,
        U: Serialize + ?Sized,
    {
        self.0.insert(encode_kv::<Q>(key)?, encode_kv::<U>(value)?)
    }

    /// Gets the associated value from a key
    ///
    /// The key may be any borrowed form of the store's key type, but
    /// [`Eq`] and [`Serialize`] on the borrowed form *must* match those
    /// for the key type.
    pub fn get<Q>(&self, key: &Q) -> PRes<Option<V>>
    where
        K: Borrow<Q>,
        Q: Eq + Serialize + ?Sized,
    {
        self.0
            .get(&encode_kv::<Q>(key)?)?
            .map(|v| decode_kv::<V>(&v))
            .map_or(Ok(None), |r| r.map(Some))
    }

    /// Removes a key and associated value from the KV store
    ///
    /// The key may be any borrowed form of the store's key type, but
    /// [`Eq`] and [`Serialize`] on the borrowed form *must* match those
    /// for the key type.
    pub fn remove<Q>(&self, key: &Q) -> PRes<()>
    where
        K: Borrow<Q>,
        Q: Eq + Serialize + ?Sized,
    {
        self.0.remove(encode_kv::<Q>(key)?)
    }

    /// Gets all the keys contained in the KV Store
    pub fn keys<B>(&self) -> PRes<B>
    where
        K: for<'kde> Deserialize<'kde>,
        B: std::iter::FromIterator<K>,
    {
        self.0.keys()?.map(|k| decode_kv::<K>(&k)).collect()
    }

    delegate! {
        target self.0 {
            /// Removes all entries from the KV store
            pub fn clear(&self) -> PRes<()>;
        }
    }
}