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