From 4e5c5f9c567c3a1a6e492a7a6c64001e27d81fb2 Mon Sep 17 00:00:00 2001
From: TomL94 <langer.tom7@gmail.com>
Date: Wed, 8 Feb 2023 20:32:18 +0200
Subject: [PATCH 1/2] Implement FuzzyItem

---
 packages/storage/src/fuzzy_item.rs | 105 +++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)
 create mode 100644 packages/storage/src/fuzzy_item.rs

diff --git a/packages/storage/src/fuzzy_item.rs b/packages/storage/src/fuzzy_item.rs
new file mode 100644
index 0000000..bcdcaa3
--- /dev/null
+++ b/packages/storage/src/fuzzy_item.rs
@@ -0,0 +1,105 @@
+use cosmwasm_std::{StdResult, Storage};
+use secret_toolkit_serialization::{Bincode2, Serde};
+use serde::{de::DeserializeOwned, Deserialize, Serialize};
+
+use crate::Item;
+
+#[derive(Serialize, Deserialize)]
+pub struct FuzzyData<T> {
+    data: T,
+    fuzz: u8,
+}
+
+pub struct FuzzyItem<'a, T, Ser = Bincode2>
+where
+    T: Serialize + DeserializeOwned + Copy,
+    Ser: Serde,
+{
+    item: Item<'a, FuzzyData<T>, Ser>,
+    storage: &'a mut dyn Storage,
+}
+
+impl<'a, T: Serialize + DeserializeOwned + Copy, Ser: Serde> FuzzyItem<'a, T, Ser> {
+    pub fn new(item: Item<'a, FuzzyData<T>, Ser>, storage: &'a mut dyn Storage) -> Self {
+        Self { item, storage }
+    }
+
+    pub fn add_suffix(&'a mut self, suffix: &[u8]) -> Self {
+        Self {
+            item: self.item.add_suffix(suffix),
+            storage: self.storage,
+        }
+    }
+}
+
+impl<'a, T, Ser> Drop for FuzzyItem<'a, T, Ser>
+where
+    T: Serialize + DeserializeOwned + Copy,
+    Ser: Serde,
+{
+    fn drop(&mut self) {
+        self.update(|fd| Ok(fd)).unwrap(); // This is not ideal but can't return `StdResult`
+    }
+}
+
+impl<'a, T, Ser> FuzzyItem<'a, T, Ser>
+where
+    T: Serialize + DeserializeOwned + Copy,
+    Ser: Serde,
+{
+    /// save will serialize the model and store, returns an error on serialization issues
+    pub fn save(&mut self, data: &T) -> StdResult<()> {
+        let new_data = match self.item.may_load(self.storage)? {
+            Some(fd) => FuzzyData {
+                data: *data,
+                fuzz: fd.fuzz.wrapping_add(1),
+            },
+            None => FuzzyData {
+                data: *data,
+                fuzz: 0,
+            },
+        };
+
+        self.item.save(self.storage, &new_data)
+    }
+
+    /// userfacing remove function
+    pub fn remove(&mut self) {
+        self.item.remove(self.storage)
+    }
+
+    /// load will return an error if no data is set at the given key, or on parse error
+    pub fn load(&self) -> StdResult<T> {
+        let fuzzy_data = self.item.load(self.storage)?;
+        Ok(fuzzy_data.data)
+    }
+
+    /// may_load will parse the data stored at the key if present, returns `Ok(None)` if no data there.
+    /// returns an error on issues parsing
+    pub fn may_load(&self) -> StdResult<Option<T>> {
+        let maybe_fuzzy_data = self.item.may_load(self.storage)?;
+        Ok(maybe_fuzzy_data.map(|fd| fd.data))
+    }
+
+    /// efficient way to see if any object is currently saved.
+    pub fn is_empty(&self) -> bool {
+        self.item.is_empty(self.storage)
+    }
+
+    /// Loads the data, perform the specified action, and store the result
+    /// in the database. This is shorthand for some common sequences, which may be useful.
+    ///
+    /// It assumes, that data was initialized before, and if it doesn't exist, `Err(StdError::NotFound)`
+    /// is returned.
+    pub fn update<A>(&mut self, action: A) -> StdResult<T>
+    where
+        A: FnOnce(T) -> StdResult<T>,
+    {
+        let mut fuzzy_data = self.item.load(self.storage)?;
+        let input = fuzzy_data.data;
+        fuzzy_data.data = action(input)?;
+        fuzzy_data.fuzz = fuzzy_data.fuzz.wrapping_add(1);
+        self.item.save(self.storage, &fuzzy_data)?;
+        Ok(fuzzy_data.data)
+    }
+}

From 79a069ce563fc77d828bc434bb66f3ddb83f61d7 Mon Sep 17 00:00:00 2001
From: TomL94 <langer.tom7@gmail.com>
Date: Wed, 8 Feb 2023 20:32:28 +0200
Subject: [PATCH 2/2] Add to lib

---
 packages/storage/src/lib.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/packages/storage/src/lib.rs b/packages/storage/src/lib.rs
index c6b0f14..1f17d28 100644
--- a/packages/storage/src/lib.rs
+++ b/packages/storage/src/lib.rs
@@ -2,6 +2,7 @@
 
 pub mod append_store;
 pub mod deque_store;
+pub mod fuzzy_item;
 pub mod item;
 pub mod keymap;
 pub mod keyset;