use std::marker::PhantomData;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use sled::Db;
pub mod example;
#[derive(Debug)]
pub enum Error {
SledErr(sled::Error),
}
pub trait TableLayout: Serialize + DeserializeOwned {
fn table_name() -> String;
}
#[derive(Debug)]
pub struct Table<'b, T>
where
T: TableLayout,
{
name: String,
base: &'b Base,
_item_kind: PhantomData<fn(T) -> T>,
}
pub trait TableKey<'t, T>
where
T: TableLayout,
{
fn value(&self, table: &'t Table<T>) -> u64;
}
#[derive(Debug, Clone)]
pub struct KeyRef<'t, 'b, T>
where
T: TableLayout,
{
value: u64,
_table: &'t Table<'b, T>,
}
impl<'t, 'b, T> KeyRef<'t, 'b, T>
where
T: TableLayout,
{
pub fn owned(self) -> KeyOwned<T> {
let Self {
value: index,
_table: _,
} = self;
KeyOwned {
value: index,
_item_kind: PhantomData,
}
}
}
impl<'t, 'b, T> TableKey<'t, T> for KeyRef<'t, 'b, T>
where
T: TableLayout,
{
fn value(&self, _table: &Table<T>) -> u64 {
self.value
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct KeyOwned<T> {
value: u64,
_item_kind: PhantomData<fn() -> T>,
}
impl<'t, 'b, T> TableKey<'t, T> for KeyOwned<T>
where
T: TableLayout,
{
fn value(&self, _table: &Table<T>) -> u64 {
self.value
}
}
impl<'b, T> Table<'b, T>
where
T: TableLayout,
{
fn next_key(&self) -> u64 {
let path = format!("/t/{}/next_key/", &self.name);
let base = &self.base.0;
let serialized = base
.fetch_and_update(path, |s| {
let deserialized: u64 = s.map(|s| bincode::deserialize(s).unwrap()).unwrap_or(0);
let serialized = bincode::serialize(&(deserialized + 1)).unwrap();
Some(serialized)
})
.unwrap();
serialized
.map(|s| bincode::deserialize(&s).unwrap())
.unwrap_or(0)
}
fn table_item_path(&self) -> String {
format!("/t/{}/i/", &self.name)
}
fn insert(&self, key: u64, item: T) -> Option<T> {
let path = self.table_item_path() + &key.to_string();
let serialized = bincode::serialize(&item).unwrap();
let base = &self.base.0;
base.insert(path, serialized)
.unwrap()
.map(|serialized| bincode::deserialize(&serialized).unwrap())
}
pub fn get<'t, K>(&'t self, key: &K) -> Option<T>
where
K: TableKey<'t, T>,
{
let path = self.table_item_path() + &key.value(self).to_string();
let serialized = self.base.0.get(path).unwrap()?;
let deserialized = bincode::deserialize(&serialized).unwrap();
Some(deserialized)
}
pub fn push(&self, element: T) -> KeyRef<T> {
let key = self.next_key();
self.insert(key, element);
KeyRef {
value: key,
_table: self,
}
}
pub fn set<'t, K>(&'t self, key: &K, value: T)
where
K: TableKey<'t, T>,
{
let key = key.value(self);
self.insert(key, value);
}
pub fn delete<'t, K>(&'t self, key: &K)
where
K: TableKey<'t, T>,
{
let path = self.table_item_path() + &key.value(self).to_string();
self.base.0.remove(path).unwrap();
}
pub fn update<'t, K, F>(&'t self, key: &K, op: F)
where
K: TableKey<'t, T>,
F: FnOnce(&mut Option<T>),
{
let mut value = self.get(key);
op(&mut value);
if let Some(value) = value {
self.set(key, value);
} else {
self.delete(key);
}
}
pub fn keys<'t>(&'t self) -> impl Iterator<Item = KeyRef<'t, 'b, T>> {
let prefix = self.table_item_path();
let items = self.base.0.scan_prefix(&prefix);
items.map(move |item| {
let (key, _) = item.unwrap();
let str = String::from_utf8_lossy(&key);
let str = &str[prefix.len()..];
let value = str.parse().unwrap();
KeyRef {
value,
_table: self,
}
})
}
pub fn iter<'t>(&'t self) -> impl Iterator<Item = (KeyRef<'t, 'b, T>, T)> {
self.keys().map(|k| {
let v = self.get(&k).unwrap();
(k, v)
})
}
}
#[derive(Debug, Clone)]
pub struct Base(Db);
impl Base {
pub fn table<T>(&self) -> Table<T>
where
T: TableLayout,
{
let name = T::table_name().to_string();
let _item_kind = PhantomData;
let base = self;
Table {
name,
_item_kind,
base,
}
}
}
pub fn open<P>(path: P) -> Result<Base, Error>
where
P: AsRef<std::path::Path>,
{
let db = sled::open(path).map_err(|e| Error::SledErr(e))?;
Ok(Base(db))
}