1#[cfg(not(feature = "mock-storage"))]
14use soroban_sdk::storage::{Instance, Persistent, Temporary};
15
16#[cfg(feature = "mock-storage")]
17pub use crate::mock_storage::{
18 with_instance_storage, with_persistent_storage, with_temporary_storage,
19};
20
21use soroban_sdk::{Env, IntoVal, TryFromVal, Val};
22
23use core::marker::PhantomData;
24
25#[inline]
27#[cfg(not(feature = "mock-storage"))]
28pub fn with_instance_storage<F, T>(env: &Env, f: F) -> T
29where
30 F: FnOnce(&Instance) -> T,
31{
32 f(&env.storage().instance())
33}
34
35#[inline]
37#[cfg(not(feature = "mock-storage"))]
38pub fn with_persistent_storage<F, T>(env: &Env, f: F) -> T
39where
40 F: FnOnce(&Persistent) -> T,
41{
42 f(&env.storage().persistent())
43}
44
45#[inline]
47#[cfg(not(feature = "mock-storage"))]
48pub fn with_temporary_storage<F, T>(env: &Env, f: F) -> T
49where
50 F: FnOnce(&Temporary) -> T,
51{
52 f(&env.storage().temporary())
53}
54
55pub struct StorageProxy<'a, K, T>
57where
58 K: 'a + IntoVal<Env, Val> + TryFromVal<Env, Val>,
59{
60 key: &'a K,
61 _data: PhantomData<*const T>,
62}
63
64impl<'a, K, T> StorageProxy<'a, K, T>
65where
66 K: IntoVal<Env, Val> + TryFromVal<Env, Val>,
67{
68 fn new(key: &'a K) -> Self {
69 StorageProxy {
70 key,
71 _data: PhantomData,
72 }
73 }
74
75 pub fn get_key(&self) -> &'a K {
76 self.key
77 }
78}
79
80pub trait StorageOps<T> {
82 fn get(&self, env: &Env) -> Option<T>;
83 fn set(&self, env: &Env, data: &T);
84 fn remove(&self, env: &Env);
85 fn has(&self, env: &Env) -> bool;
86 fn extend_ttl(&self, env: &Env, threshold: u32, extend_to: u32);
87}
88
89pub fn get<'a, K, T>(env: &Env, key: &'a K) -> Option<T>
90where
91 StorageProxy<'a, K, T>: StorageOps<T>,
92 K: IntoVal<Env, Val> + TryFromVal<Env, Val> + ?Sized,
93{
94 StorageProxy::<'a, K, T>::new(key).get(env)
95}
96
97pub fn get_or_else<'a, K, T, F, R>(env: &Env, key: &'a K, handler: F) -> R
98where
99 StorageProxy<'a, K, T>: StorageOps<T>,
100 K: IntoVal<Env, Val> + TryFromVal<Env, Val> + ?Sized,
101 F: FnOnce(Option<T>) -> R,
102{
103 handler(StorageProxy::<'a, K, T>::new(key).get(env))
104}
105
106pub fn set<'a, K, T>(env: &Env, key: &'a K, data: &T)
107where
108 StorageProxy<'a, K, T>: StorageOps<T>,
109 K: IntoVal<Env, Val> + TryFromVal<Env, Val> + ?Sized,
110{
111 StorageProxy::<'a, K, T>::new(key).set(env, data);
112}
113
114pub fn has<'a, K, T>(env: &Env, key: &'a K) -> bool
115where
116 StorageProxy<'a, K, T>: StorageOps<T>,
117 K: IntoVal<Env, Val> + TryFromVal<Env, Val> + ?Sized,
118{
119 StorageProxy::<'a, K, T>::new(key).has(env)
120}
121
122pub fn remove<'a, K, T>(env: &Env, key: &'a K)
123where
124 StorageProxy<'a, K, T>: StorageOps<T>,
125 K: IntoVal<Env, Val> + TryFromVal<Env, Val> + ?Sized,
126{
127 StorageProxy::<'a, K, T>::new(key).remove(env);
128}
129
130pub fn extend_ttl<'a, K, T>(
131 env: &Env,
132 key: &'a K,
133 threshold: u32,
134 extend_to: u32,
135) where
136 StorageProxy<'a, K, T>: StorageOps<T>,
137 K: IntoVal<Env, Val> + TryFromVal<Env, Val> + ?Sized,
138{
139 StorageProxy::<'a, K, T>::new(key).extend_ttl(env, threshold, extend_to);
140}
141
142#[macro_export]
143macro_rules! impl_key_constraint {
144 ($key_type:ty, $key_trait:ident) => {
145 pub trait $key_trait {}
146 impl $key_trait for $key_type {}
147 };
148}
149
150#[macro_export]
151macro_rules! impl_storage {
152 (Instance, $data_type:ty $(, $key_trait:ident)?) => {
153 impl<'a, K> $crate::storage::StorageOps<$data_type>
154 for $crate::storage::StorageProxy<'a, K, $data_type>
155 where
156 K: $( $key_trait + )? soroban_sdk::IntoVal<soroban_sdk::Env, soroban_sdk::Val>
157 + soroban_sdk::TryFromVal<soroban_sdk::Env, soroban_sdk::Val>,
158 {
159 fn get(&self, env: &soroban_sdk::Env) -> Option<$data_type> {
160 $crate::storage::with_instance_storage(env, |storage| storage.get(self.get_key()))
161 }
162
163 fn set(&self, env: &soroban_sdk::Env, data: &$data_type) {
164 $crate::storage::with_instance_storage(env, |storage| {
165 storage.set(self.get_key(), data)
166 });
167 }
168
169 fn remove(&self, env: &soroban_sdk::Env) {
170 $crate::storage::with_instance_storage(env, |storage| {
171 storage.remove(self.get_key())
172 });
173 }
174
175 fn has(&self, env: &soroban_sdk::Env) -> bool {
176 $crate::storage::with_instance_storage(env, |storage| storage.has(self.get_key()))
177 }
178
179 fn extend_ttl(&self, env: &Env, threshold: u32, extend_to: u32) {
180 $crate::storage::with_instance_storage(env, |storage| {
181 storage.extend_ttl(
182 threshold,
183 extend_to,
184 )
185 });
186 }
187 }
188 };
189 (Persistent, $data_type:ty $(, $key_type:ident)?) => {
190 impl<'a, K> $crate::storage::StorageOps<$data_type>
191 for $crate::storage::StorageProxy<'a, K, $data_type>
192 where
193 K: $( $key_type + )? soroban_sdk::IntoVal<soroban_sdk::Env, soroban_sdk::Val>
194 + soroban_sdk::TryFromVal<soroban_sdk::Env, soroban_sdk::Val>,
195 {
196 fn get(&self, env: &soroban_sdk::Env) -> Option<$data_type> {
197 $crate::storage::with_persistent_storage(env, |storage| storage.get(self.get_key()))
198 }
199
200 fn set(&self, env: &soroban_sdk::Env, data: &$data_type) {
201 $crate::storage::with_persistent_storage(env, |storage| {
202 storage.set(self.get_key(), data)
203 });
204 }
205
206 fn remove(&self, env: &soroban_sdk::Env) {
207 $crate::storage::with_persistent_storage(env, |storage| {
208 storage.remove(self.get_key())
209 });
210 }
211
212 fn has(&self, env: &soroban_sdk::Env) -> bool {
213 $crate::storage::with_persistent_storage(env, |storage| storage.has(self.get_key()))
214 }
215
216 fn extend_ttl(&self, env: &Env, threshold: u32, extend_to: u32) {
217 $crate::storage::with_persistent_storage(env, |storage| {
218 storage.extend_ttl(
219 self.get_key(),
220 threshold,
221 extend_to,
222 )
223 });
224 }
225 }
226 };
227 (Temporary, $data_type:ty $(, $key_type:ident)?) => {
228 impl<'a, K> $crate::storage::StorageOps<$data_type>
229 for $crate::storage::StorageProxy<'a, K, $data_type>
230 where
231 K: $( $key_type + )? soroban_sdk::IntoVal<soroban_sdk::Env, soroban_sdk::Val>
232 + soroban_sdk::TryFromVal<soroban_sdk::Env, soroban_sdk::Val>,
233 {
234 fn get(&self, env: &soroban_sdk::Env) -> Option<$data_type> {
235 $crate::storage::with_temporary_storage(env, |storage| storage.get(self.get_key()))
236 }
237
238 fn set(&self, env: &soroban_sdk::Env, data: &$data_type) {
239 $crate::storage::with_temporary_storage(env, |storage| {
240 storage.set(self.get_key(), data)
241 });
242 }
243
244 fn remove(&self, env: &soroban_sdk::Env) {
245 $crate::storage::with_temporary_storage(env, |storage| {
246 storage.remove(self.get_key())
247 });
248 }
249
250 fn has(&self, env: &soroban_sdk::Env) -> bool {
251 $crate::storage::with_temporary_storage(env, |storage| storage.has(self.get_key()))
252 }
253
254 fn extend_ttl(&self, env: &Env, threshold: u32, extend_to: u32) {
255 $crate::storage::with_temporary_storage(env, |storage| {
256 storage.extend_ttl(
257 self.get_key(),
258 threshold,
259 extend_to,
260 )
261 });
262 }
263 }
264 };
265}