Lay down some more structs
This commit is contained in:
parent
900122d131
commit
fdd82b2fef
2
src/database.rs
Normal file
2
src/database.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub(crate) mod raw;
|
||||
pub(crate) mod wrapped;
|
16
src/database/raw.rs
Normal file
16
src/database/raw.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use libmdbx::{Database, Environment, WriteMap};
|
||||
use ouroboros::self_referencing;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[self_referencing(pub_extras)]
|
||||
pub struct RawTable<K: ?Sized, V: ?Sized> {
|
||||
pub mdbx_env: Arc<Environment<WriteMap>>,
|
||||
|
||||
#[borrows(mdbx_env)]
|
||||
#[covariant]
|
||||
pub mdbx_db: Database<'this>,
|
||||
|
||||
pub(crate) phantom_k: PhantomData<K>,
|
||||
pub(crate) phantom_v: PhantomData<V>,
|
||||
}
|
7
src/database/wrapped.rs
Normal file
7
src/database/wrapped.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use crate::database::raw::RawTable;
|
||||
|
||||
pub struct WrappedTable<K, V> {
|
||||
pub raw: RawTable<[u8], [u8]>,
|
||||
pub k_wrapper: K,
|
||||
pub v_wrapper: V,
|
||||
}
|
@ -1,30 +1,60 @@
|
||||
use crate::database::raw::{RawTable, RawTableTryBuilder};
|
||||
use crate::database::wrapped::WrappedTable;
|
||||
use crate::wrapper::{ByteWrapper, ZeroCopyByteWrapper};
|
||||
use anyhow::{ensure, Context};
|
||||
use libmdbx::{DatabaseFlags, Environment, WriteMap};
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use libmdbx::{Database, Environment, EnvironmentKind, WriteMap};
|
||||
|
||||
pub struct Env {
|
||||
pub mdbx_env: Environment<WriteMap>,
|
||||
pub mdbx_env: Arc<Environment<WriteMap>>,
|
||||
}
|
||||
|
||||
#[self_referencing]
|
||||
pub struct Table {
|
||||
pub mdbx_env: Arc<Env>,
|
||||
|
||||
#[borrows(mdbx_env)]
|
||||
#[covariant]
|
||||
pub mdbx_db: Database<'this>
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// - raw if wanted
|
||||
// - serde if wanted
|
||||
// - compression if wanted
|
||||
// - ??? does it make sense to offer ALL these things in one interface; could the raw stuff
|
||||
// be done slightly differently?
|
||||
|
||||
impl Env {
|
||||
pub fn open_table(&self, name: &str, flags: ()) -> anyhow::Result<Table> {
|
||||
todo!()
|
||||
pub fn open_raw_table<K: ZeroCopyByteWrapper + ?Sized, V: ZeroCopyByteWrapper + ?Sized>(
|
||||
&self,
|
||||
name: Option<&str>,
|
||||
_flags: (),
|
||||
) -> anyhow::Result<RawTable<K, V>> {
|
||||
Ok(RawTableTryBuilder {
|
||||
mdbx_env: self.mdbx_env.clone(),
|
||||
mdbx_db_builder: |mdbx_env: &Arc<Environment<WriteMap>>| {
|
||||
let txn = mdbx_env
|
||||
.begin_rw_txn()
|
||||
.context("Can't start RW transaction")?;
|
||||
// TODO database flags
|
||||
let db = txn
|
||||
.create_db(name, DatabaseFlags::empty())
|
||||
.context("Can't open database")?;
|
||||
txn.prime_for_permaopen(db);
|
||||
|
||||
let (_bool, mut dbs) = txn.commit_and_rebind_open_dbs()?;
|
||||
|
||||
ensure!(dbs.len() == 1);
|
||||
|
||||
let mdbx_db = dbs.pop().context("Expected database!")?;
|
||||
|
||||
Ok(mdbx_db)
|
||||
},
|
||||
phantom_k: PhantomData::default(),
|
||||
phantom_v: PhantomData::default(),
|
||||
}
|
||||
.try_build()?)
|
||||
}
|
||||
|
||||
pub fn open_
|
||||
}
|
||||
pub fn open_wrapped_table<K: ByteWrapper, V: ByteWrapper>(
|
||||
&self,
|
||||
name: Option<&str>,
|
||||
flags: (),
|
||||
k_wrapper: K,
|
||||
v_wrapper: V,
|
||||
) -> anyhow::Result<WrappedTable<K, V>> {
|
||||
let raw_table = self.open_raw_table(name, flags)?;
|
||||
|
||||
Ok(WrappedTable {
|
||||
raw: raw_table,
|
||||
k_wrapper,
|
||||
v_wrapper,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
mod environment;
|
||||
pub(crate) mod database;
|
||||
pub(crate) mod environment;
|
||||
pub(crate) mod wrapper;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
83
src/wrapper.rs
Normal file
83
src/wrapper.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use anyhow::anyhow;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Mutex;
|
||||
use zstd::bulk::{Compressor, Decompressor};
|
||||
|
||||
pub trait ByteWrapper {
|
||||
type Item;
|
||||
|
||||
fn load_from_db_bytes(&self, bytes: &[u8]) -> anyhow::Result<Self::Item>;
|
||||
fn dump_to_db_bytes(&self, item: &Self::Item) -> anyhow::Result<Vec<u8>>;
|
||||
}
|
||||
|
||||
pub struct SerdeBareWrapper<T> {
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Serialize + DeserializeOwned> ByteWrapper for SerdeBareWrapper<T> {
|
||||
type Item = T;
|
||||
|
||||
fn load_from_db_bytes(&self, bytes: &[u8]) -> anyhow::Result<Self::Item> {
|
||||
Ok(serde_bare::from_slice(bytes)?)
|
||||
}
|
||||
|
||||
fn dump_to_db_bytes(&self, item: &Self::Item) -> anyhow::Result<Vec<u8>> {
|
||||
Ok(serde_bare::to_vec(item)?)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CompressorWrapper<T> {
|
||||
inner: T,
|
||||
compressor: Mutex<Compressor<'static>>,
|
||||
decompressor: Mutex<Decompressor<'static>>,
|
||||
}
|
||||
|
||||
impl<T: ByteWrapper> ByteWrapper for CompressorWrapper<T> {
|
||||
type Item = T::Item;
|
||||
|
||||
fn load_from_db_bytes(&self, bytes: &[u8]) -> anyhow::Result<Self::Item> {
|
||||
let mut decompressor = self
|
||||
.decompressor
|
||||
.lock()
|
||||
.map_err(|_| anyhow!("Can't lock decompressor"))?;
|
||||
// TODO be more sensible about capacity. 8× should be good though.
|
||||
let raw_bytes = decompressor.decompress(bytes, bytes.len() * 8)?;
|
||||
Ok(self.inner.load_from_db_bytes(&raw_bytes)?)
|
||||
}
|
||||
|
||||
fn dump_to_db_bytes(&self, item: &Self::Item) -> anyhow::Result<Vec<u8>> {
|
||||
let raw_bytes = self.inner.dump_to_db_bytes(item)?;
|
||||
let mut compressor = self
|
||||
.compressor
|
||||
.lock()
|
||||
.map_err(|_| anyhow!("Can't lock compressor"))?;
|
||||
Ok(compressor.compress(&raw_bytes)?)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ZeroCopyByteWrapper {
|
||||
fn as_byte_slice(&self) -> &[u8];
|
||||
fn from_byte_slice(bytes: &[u8]) -> anyhow::Result<&Self>;
|
||||
}
|
||||
|
||||
impl ZeroCopyByteWrapper for [u8] {
|
||||
fn as_byte_slice(&self) -> &[u8] {
|
||||
self
|
||||
}
|
||||
|
||||
fn from_byte_slice(bytes: &[u8]) -> anyhow::Result<&Self> {
|
||||
Ok(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl ZeroCopyByteWrapper for str {
|
||||
fn as_byte_slice(&self) -> &[u8] {
|
||||
self.as_bytes()
|
||||
}
|
||||
|
||||
fn from_byte_slice(bytes: &[u8]) -> anyhow::Result<&Self> {
|
||||
Ok(std::str::from_utf8(bytes)?)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user