From d8734bda32bb0883bfa9c7822ca8132c4b82e14f Mon Sep 17 00:00:00 2001 From: librelois <c@elo.tf> Date: Wed, 11 Nov 2020 20:31:40 +0100 Subject: [PATCH] [feat] kv_typed: add backend memory_singleton --- rust-libs/tools/kv_typed/src/as_bytes.rs | 9 + rust-libs/tools/kv_typed/src/backend.rs | 1 + .../kv_typed/src/backend/memory_singleton.rs | 182 ++++++++++++++++++ rust-libs/tools/kv_typed/src/explorer.rs | 10 + rust-libs/tools/kv_typed/src/from_bytes.rs | 6 + rust-libs/tools/kv_typed/src/key.rs | 3 + rust-libs/tools/kv_typed/src/lib.rs | 3 +- 7 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 rust-libs/tools/kv_typed/src/backend/memory_singleton.rs diff --git a/rust-libs/tools/kv_typed/src/as_bytes.rs b/rust-libs/tools/kv_typed/src/as_bytes.rs index b7734bb7c..bfa37e87f 100644 --- a/rust-libs/tools/kv_typed/src/as_bytes.rs +++ b/rust-libs/tools/kv_typed/src/as_bytes.rs @@ -28,6 +28,15 @@ impl KeyAsBytes for () { } fn fill_bytes(&self, _: &mut [u8]) {} } +impl KeyAsBytes for EmptyKey { + fn as_bytes<T, F: FnMut(&[u8]) -> T>(&self, mut f: F) -> T { + f(&[]) + } + fn fill_bytes_size(&self) -> Option<usize> { + Some(0) + } + fn fill_bytes(&self, _: &mut [u8]) {} +} impl ValueAsBytes for EmptyValue { fn as_bytes<T, F: FnMut(&[u8]) -> Result<T, KvError>>(&self, mut f: F) -> Result<T, KvError> { f(&[]) diff --git a/rust-libs/tools/kv_typed/src/backend.rs b/rust-libs/tools/kv_typed/src/backend.rs index c55eaec03..6cfaa9f10 100644 --- a/rust-libs/tools/kv_typed/src/backend.rs +++ b/rust-libs/tools/kv_typed/src/backend.rs @@ -20,6 +20,7 @@ pub mod leveldb; #[cfg(feature = "lmdb_backend")] pub mod lmdb; pub mod memory; +pub mod memory_singleton; #[cfg(feature = "mock")] pub mod mock; #[cfg(feature = "sled_backend")] diff --git a/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs b/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs new file mode 100644 index 000000000..2c41ab4f9 --- /dev/null +++ b/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs @@ -0,0 +1,182 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +//! Memory backend for KV Typed, + +use crate::*; + +#[derive(Clone, Copy, Debug)] +pub struct MemSingleton; + +#[derive(Clone, Copy, Debug, Default)] +pub struct MemSingletonConf { + phantom: PhantomData<()>, +} + +type KeyBytes = IVec; +type ValueBytes = IVec; + +impl Backend for MemSingleton { + const NAME: &'static str = "mem_singleton"; + type Col = MemCol; + type Conf = MemSingletonConf; + + fn open(_conf: &Self::Conf) -> KvResult<Self> { + Ok(MemSingleton) + } + fn open_col(&mut self, _conf: &Self::Conf, _col_name: &str) -> KvResult<Self::Col> { + Ok(MemCol(None)) + } +} + +#[derive(Debug, Default)] +pub struct MemBatch(Option<IVec>); + +impl BackendBatch for MemBatch { + fn upsert(&mut self, _k: &[u8], v: &[u8]) { + self.0 = Some(v.into()); + } + + fn remove(&mut self, _k: &[u8]) { + self.0 = None; + } +} + +#[derive(Clone, Debug)] +pub struct MemCol(Option<ValueBytes>); + +impl BackendCol for MemCol { + type Batch = MemBatch; + type KeyBytes = KeyBytes; + type ValueBytes = ValueBytes; + type Iter = MemIter; + + #[inline(always)] + fn new_batch() -> Self::Batch { + MemBatch::default() + } + #[inline(always)] + fn clear(&mut self) -> KvResult<()> { + self.0 = None; + Ok(()) + } + #[inline(always)] + fn count(&self) -> KvResult<usize> { + if self.0.is_some() { + Ok(1) + } else { + Ok(0) + } + } + #[inline(always)] + fn get<K: Key, V: Value>(&self, _k: &K) -> KvResult<Option<V>> { + self.0 + .as_ref() + .map(|bytes| V::from_bytes(bytes).map_err(|e| KvError::DeserError(format!("{}", e)))) + .transpose() + } + #[inline(always)] + fn get_ref<K: Key, V: ValueZc, D, F: Fn(&V::Ref) -> KvResult<D>>( + &self, + _k: &K, + f: F, + ) -> KvResult<Option<D>> { + self.0 + .as_ref() + .map(|bytes| { + if let Some(layout_verified) = + zerocopy::LayoutVerified::<_, V::Ref>::new(bytes.as_ref()) + { + f(&layout_verified) + } else { + Err(KvError::DeserError( + "Bytes are invalid length or alignment.".to_owned(), + )) + } + }) + .transpose() + } + #[inline(always)] + fn get_ref_slice<K: Key, V: ValueSliceZc, D, F: Fn(&[V::Elem]) -> KvResult<D>>( + &self, + _k: &K, + f: F, + ) -> KvResult<Option<D>> { + self.0 + .as_ref() + .map(|bytes| { + if let Some(layout_verified) = + zerocopy::LayoutVerified::<_, [V::Elem]>::new_slice(&bytes[V::prefix_len()..]) + { + f(&layout_verified) + } else { + Err(KvError::DeserError( + "Bytes are invalid length or alignment.".to_owned(), + )) + } + }) + .transpose() + } + #[inline(always)] + fn delete<K: Key>(&mut self, _k: &K) -> KvResult<()> { + self.0 = None; + Ok(()) + } + #[inline(always)] + fn put<K: Key, V: Value>(&mut self, _k: &K, value: &V) -> KvResult<()> { + value.as_bytes(|value_bytes| { + self.0 = Some(value_bytes.into()); + Ok(()) + }) + } + #[inline(always)] + fn write_batch(&mut self, inner_batch: Self::Batch) -> KvResult<()> { + self.0 = inner_batch.0; + Ok(()) + } + #[inline(always)] + fn iter<K: Key, V: Value>(&self, _: RangeBytes) -> Self::Iter { + MemIter(self.0.clone()) + } + #[inline(always)] + fn save(&self) -> KvResult<()> { + Ok(()) + } +} + +pub struct MemIter(Option<ValueBytes>); + +impl Debug for MemIter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("MemIter").field("0", &"???").finish() + } +} +impl Iterator for MemIter { + type Item = Result<(KeyBytes, ValueBytes), DynErr>; + + #[inline(always)] + fn next(&mut self) -> Option<Self::Item> { + self.0.take().map(|v| Ok((KeyBytes::default(), v))) + } +} + +impl ReversableIterator for MemIter { + #[inline(always)] + fn reverse(self) -> Self { + self + } +} + +impl BackendIter<IVec, IVec> for MemIter {} diff --git a/rust-libs/tools/kv_typed/src/explorer.rs b/rust-libs/tools/kv_typed/src/explorer.rs index 49bfd9ef3..d07ff02b6 100644 --- a/rust-libs/tools/kv_typed/src/explorer.rs +++ b/rust-libs/tools/kv_typed/src/explorer.rs @@ -27,6 +27,16 @@ impl ExplorableKey for () { } } +impl ExplorableKey for EmptyKey { + fn from_explorer_str(_: &str) -> Result<Self, StringErr> { + Ok(EmptyKey) + } + + fn to_explorer_string(&self) -> KvResult<String> { + Ok(String::with_capacity(0)) + } +} + impl ExplorableKey for String { fn from_explorer_str(source: &str) -> Result<Self, StringErr> { Ok(source.to_owned()) diff --git a/rust-libs/tools/kv_typed/src/from_bytes.rs b/rust-libs/tools/kv_typed/src/from_bytes.rs index 1ec49096a..ab05f4a5b 100644 --- a/rust-libs/tools/kv_typed/src/from_bytes.rs +++ b/rust-libs/tools/kv_typed/src/from_bytes.rs @@ -14,7 +14,13 @@ impl FromBytes for () { Ok(()) } } +impl FromBytes for EmptyKey { + type Err = std::convert::Infallible; + fn from_bytes(_: &[u8]) -> Result<Self, Self::Err> { + Ok(EmptyKey) + } +} impl FromBytes for EmptyValue { type Err = std::convert::Infallible; diff --git a/rust-libs/tools/kv_typed/src/key.rs b/rust-libs/tools/kv_typed/src/key.rs index 7d820dfa7..91e764c78 100644 --- a/rust-libs/tools/kv_typed/src/key.rs +++ b/rust-libs/tools/kv_typed/src/key.rs @@ -60,3 +60,6 @@ impl<T> Key for T where + Sized { } + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct EmptyKey; diff --git a/rust-libs/tools/kv_typed/src/lib.rs b/rust-libs/tools/kv_typed/src/lib.rs index eee1e7e68..8d7ff66cc 100644 --- a/rust-libs/tools/kv_typed/src/lib.rs +++ b/rust-libs/tools/kv_typed/src/lib.rs @@ -60,6 +60,7 @@ pub mod prelude { #[cfg(feature = "lmdb_backend")] pub use crate::backend::lmdb::{Lmdb, LmdbConf}; pub use crate::backend::memory::{Mem, MemConf}; + pub use crate::backend::memory_singleton::{MemSingleton, MemSingletonConf}; #[cfg(feature = "mock")] pub use crate::backend::mock::{MockBackend, MockBackendCol, MockBackendIter}; #[cfg(feature = "sled_backend")] @@ -80,7 +81,7 @@ pub mod prelude { pub use crate::iter::{ keys::KvIterKeys, values::KvIterValues, EntryIter, KvIter, ResultIter, ReversableIterator, }; - pub use crate::key::Key; + pub use crate::key::{EmptyKey, Key}; pub use crate::subscription::{NewSubscribers, Subscriber, Subscribers}; pub use crate::transactional_read::{TransactionalRead, TxColRo}; pub use crate::transactional_write::{DbTxCollectionRw, TransactionalWrite, TxColRw}; -- GitLab