diff --git a/rust-libs/tools/kv_typed/src/as_bytes.rs b/rust-libs/tools/kv_typed/src/as_bytes.rs index b7734bb7c50d53388cf569a7679f3f42288712c7..bfa37e87fb1520bdee0fd348876a8fcdaad7fa15 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 c55eaec039501eec43a30f68c80c364122cb2c15..6cfaa9f10cced54d39918ec55a9a676bb4cb2e2b 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 0000000000000000000000000000000000000000..2c41ab4f91e9ba0c2862534a420f04c65d28ea12 --- /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 49bfd9ef34a9dee09077ebac231d4e6a6eebd495..d07ff02b693c594fa2b2205f3a15a4260fcd76de 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 1ec49096a8f7cf1c8f99739cbcbda352203d76b8..ab05f4a5bcebfbb3cae250e3a7cdeab15c4dc097 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 7d820dfa7b4453454f5a0642e0e76bd8dd96d929..91e764c78f4cdbb53ad584ffe32fa320ea0e5202 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 eee1e7e6887e36b4f9cce78cd4c81c72f40ff6f8..8d7ff66cc408fa2619d6af54a0a428e86b961865 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};