Skip to main content

tw_storage_extra/cow/
indexed_map_ref.rs

1/// Another varaint of cw-storage-plus IndexedMap. Using reference of indexes instead of owned to
2/// avoid cloning/rebuilding as accessor and remove trait bound of new constructor to make it constant.
3///
4/// Modified from:
5/// https://github.com/CosmWasm/cw-plus/blob/v0.9.1/packages/storage-plus/src/indexed_map.rs
6use cosmwasm_std::{StdError, StdResult, Storage};
7use cw_storage_plus::{IndexList, Map, Path, Prefix, Prefixer, PrimaryKey};
8use serde::{de::DeserializeOwned, Serialize};
9
10pub struct IndexedMapRef<'a, K, T, I> {
11    pk_namespace: &'a [u8],
12    primary: Map<'a, K, T>,
13    idx: &'a I,
14}
15
16impl<'a, K, T, I> IndexedMapRef<'a, K, T, I> {
17    pub const fn new(pk_namespace: &'a str, indexes: &'a I) -> Self {
18        Self {
19            pk_namespace: pk_namespace.as_bytes(),
20            primary: Map::new(pk_namespace),
21            idx: indexes,
22        }
23    }
24}
25
26impl<'a, K, T, I> IndexedMapRef<'a, K, T, I>
27where
28    K: PrimaryKey<'a>,
29    T: Serialize + DeserializeOwned + Clone,
30    I: IndexList<T>,
31{
32    pub fn key(&self, k: K) -> Path<T> {
33        self.primary.key(k)
34    }
35
36    pub fn save(&self, store: &mut dyn Storage, key: K, data: &T) -> StdResult<()> {
37        let old_data = self.may_load(store, key.clone())?;
38        self.replace(store, key, Some(data), old_data.as_ref())
39    }
40
41    pub fn remove(&self, store: &mut dyn Storage, key: K) -> StdResult<()> {
42        let old_data = self.may_load(store, key.clone())?;
43        self.replace(store, key, None, old_data.as_ref())
44    }
45
46    pub fn replace(
47        &self,
48        store: &mut dyn Storage,
49        key: K,
50        data: Option<&T>,
51        old_data: Option<&T>,
52    ) -> StdResult<()> {
53        let pk = key.joined_key();
54        if let Some(old) = old_data {
55            for index in self.idx.get_indexes() {
56                index.remove(store, &pk, old)?;
57            }
58        }
59        if let Some(updated) = data {
60            for index in self.idx.get_indexes() {
61                index.save(store, &pk, updated)?;
62            }
63            self.primary.save(store, key, updated)?;
64        } else {
65            self.primary.remove(store, key);
66        }
67        Ok(())
68    }
69
70    pub fn update<A, E>(&self, store: &mut dyn Storage, key: K, action: A) -> Result<T, E>
71    where
72        A: FnOnce(Option<T>) -> Result<T, E>,
73        E: From<StdError>,
74    {
75        let input = self.may_load(store, key.clone())?;
76        let old_val = input.clone();
77        let output = action(input)?;
78        self.replace(store, key, Some(&output), old_val.as_ref())?;
79        Ok(output)
80    }
81
82    pub fn load(&self, store: &dyn Storage, key: K) -> StdResult<T> {
83        self.primary.load(store, key)
84    }
85
86    pub fn may_load(&self, store: &dyn Storage, key: K) -> StdResult<Option<T>> {
87        self.primary.may_load(store, key)
88    }
89
90    pub fn prefix(&self, p: K::Prefix) -> Prefix<T> {
91        Prefix::new(self.pk_namespace, &p.prefix())
92    }
93
94    pub fn sub_prefix(&self, p: K::SubPrefix) -> Prefix<T> {
95        Prefix::new(self.pk_namespace, &p.prefix())
96    }
97}