use crate::db::RawDB; use lmdb::{Cursor, RwTransaction, Transaction, WriteFlags}; use rkyv::{AlignedVec, Archive, Archived}; use std::fmt; use std::fmt::{Debug, Display, Formatter}; use std::marker::PhantomData; use crate::db; #[derive(Clone)] /// Packed, sendable resource state pub struct ArchivedValue { /// State is encoded using rkyv making it trivially serializable data: AlignedVec, _marker: PhantomData, } impl ArchivedValue { pub fn new(data: AlignedVec) -> Self { Self { data, _marker: PhantomData, } } pub fn build(data: &[u8]) -> Self { let mut v = AlignedVec::with_capacity(data.len()); v.extend_from_slice(data); Self::new(v) } pub fn as_mut(&mut self) -> &mut AlignedVec { &mut self.data } pub fn as_slice(&self) -> &[u8] { self.data.as_slice() } pub fn as_mut_slice(&mut self) -> &mut [u8] { self.data.as_mut_slice() } } impl AsRef> for ArchivedValue { fn as_ref(&self) -> &Archived { unsafe { rkyv::archived_root::(self.as_slice()) } } } // // Debug implementation shows wrapping SendState // impl Debug for ArchivedValue where ::Archived: Debug, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_tuple("SendState").field(self.as_ref()).finish() } } // // Display implementation hides wrapping SendState // impl Display for ArchivedValue where ::Archived: Display, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(self.as_ref(), f) } } /// Adapter trait handling de-/serialization /// /// Values must be read from raw, unaligned byte buffers provided by LMDB. pub trait Adapter { type Item; /// Decode data from a short-lived byte buffer into a durable format fn decode(data: &[u8]) -> Self::Item; fn encoded_len(item: &Self::Item) -> usize; fn encode_into(item: &Self::Item, buf: &mut [u8]); } #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] pub struct AlignedAdapter(PhantomData); impl Adapter for AlignedAdapter { type Item = ArchivedValue; fn decode(data: &[u8]) -> Self::Item { ArchivedValue::build(data) } fn encoded_len(item: &Self::Item) -> usize { item.as_slice().len() } fn encode_into(item: &Self::Item, buf: &mut [u8]) { buf.copy_from_slice(item.as_slice()) } } #[derive(Debug, Clone)] #[repr(transparent)] /// `Typed` database, allowing storing a typed value /// /// Values must be serialized into and deserialized from raw byte buffers. /// This is handled by a stateless [Adapter] given by the type parameter `A` pub struct DB { db: RawDB, _marker: PhantomData, } impl DB { pub fn new(db: RawDB) -> Self { Self { db, _marker: PhantomData, } } } impl DB { pub fn get( &self, txn: &T, key: &impl AsRef<[u8]>, ) -> Result, db::Error> { Ok(self.db.get(txn, key)?.map(A::decode)) } pub fn put( &self, txn: &mut RwTransaction, key: &impl AsRef<[u8]>, value: &A::Item, flags: WriteFlags, ) -> Result<(), db::Error> { let len = A::encoded_len(value); let buf = self.db.reserve(txn, key, len, flags)?; assert_eq!(buf.len(), len, "Reserved buffer is not of requested size!"); A::encode_into(value, buf); Ok(()) } pub fn del(&self, txn: &mut RwTransaction, key: &impl AsRef<[u8]>) -> Result<(), db::Error> { self.db.del::<_, &[u8]>(txn, key, None) } pub fn clear(&self, txn: &mut RwTransaction) -> Result<(), db::Error> { self.db.clear(txn) } pub fn get_all<'txn, T: Transaction>( &self, txn: &'txn T, ) -> Result, db::Error> { let mut cursor = self.db.open_ro_cursor(txn)?; let it = cursor.iter_start(); Ok(it.filter_map(|buf| buf.ok().map(|(kbuf, vbuf)| (kbuf, A::decode(vbuf))))) } }