miden_base/types/
storage.rs1use miden_base_sys::bindings::{StorageSlotId, storage};
2use miden_stdlib_sys::{Digest, Felt, Word, felt};
3
4fn padded_word_from_felt(value: Felt) -> Word {
6 Word::new([felt!(0), felt!(0), felt!(0), value])
7}
8
9fn felt_from_padded_word(value: Word) -> Result<Felt, &'static str> {
11 if value[0] != felt!(0) || value[1] != felt!(0) || value[2] != felt!(0) {
12 return Err("expected zero padding in the upper three felts");
13 }
14
15 Ok(value[3])
16}
17
18pub trait WordValue: Sized {
23 fn try_into_word(self) -> Result<Word, &'static str>;
25
26 fn try_from_word(word: Word) -> Result<Self, &'static str>;
28}
29
30impl WordValue for Word {
31 fn try_into_word(self) -> Result<Word, &'static str> {
32 Ok(self)
33 }
34
35 fn try_from_word(word: Word) -> Result<Self, &'static str> {
36 Ok(word)
37 }
38}
39
40impl WordValue for Felt {
41 fn try_into_word(self) -> Result<Word, &'static str> {
42 Ok(padded_word_from_felt(self))
43 }
44
45 fn try_from_word(word: Word) -> Result<Self, &'static str> {
46 felt_from_padded_word(word)
47 }
48}
49
50impl WordValue for Digest {
51 fn try_into_word(self) -> Result<Word, &'static str> {
52 Ok(self.into())
53 }
54
55 fn try_from_word(word: Word) -> Result<Self, &'static str> {
56 Ok(word.try_into().unwrap())
57 }
58}
59
60impl WordValue for miden_base_sys::bindings::AccountId {
61 fn try_into_word(self) -> Result<Word, &'static str> {
62 Ok(self.into())
63 }
64
65 fn try_from_word(word: Word) -> Result<Self, &'static str> {
66 word.try_into()
67 }
68}
69
70impl WordValue for miden_base_sys::bindings::Recipient {
71 fn try_into_word(self) -> Result<Word, &'static str> {
72 Ok(self.into())
73 }
74
75 fn try_from_word(word: Word) -> Result<Self, &'static str> {
76 Ok(word.into())
77 }
78}
79
80impl WordValue for miden_base_sys::bindings::Tag {
81 fn try_into_word(self) -> Result<Word, &'static str> {
82 Ok(self.into())
83 }
84
85 fn try_from_word(word: Word) -> Result<Self, &'static str> {
86 word.try_into()
87 }
88}
89
90impl WordValue for miden_base_sys::bindings::NoteIdx {
91 fn try_into_word(self) -> Result<Word, &'static str> {
92 Ok(self.into())
93 }
94
95 fn try_from_word(word: Word) -> Result<Self, &'static str> {
96 word.try_into()
97 }
98}
99
100impl WordValue for miden_base_sys::bindings::NoteType {
101 fn try_into_word(self) -> Result<Word, &'static str> {
102 Ok(self.into())
103 }
104
105 fn try_from_word(word: Word) -> Result<Self, &'static str> {
106 word.try_into()
107 }
108}
109
110pub trait WordKey: Copy {
115 fn try_into_word(self) -> Result<Word, &'static str>;
117}
118
119impl WordKey for Word {
120 fn try_into_word(self) -> Result<Word, &'static str> {
121 Ok(self)
122 }
123}
124
125impl WordKey for Felt {
126 fn try_into_word(self) -> Result<Word, &'static str> {
127 Ok(padded_word_from_felt(self))
128 }
129}
130
131impl WordKey for miden_base_sys::bindings::AccountId {
132 fn try_into_word(self) -> Result<Word, &'static str> {
133 Ok(self.into())
134 }
135}
136
137impl WordKey for miden_base_sys::bindings::Tag {
138 fn try_into_word(self) -> Result<Word, &'static str> {
139 Ok(self.into())
140 }
141}
142
143impl WordKey for miden_base_sys::bindings::NoteIdx {
144 fn try_into_word(self) -> Result<Word, &'static str> {
145 Ok(self.into())
146 }
147}
148
149impl WordKey for miden_base_sys::bindings::NoteType {
150 fn try_into_word(self) -> Result<Word, &'static str> {
151 Ok(self.into())
152 }
153}
154
155#[derive(Debug, Copy, Clone, PartialEq, Eq)]
157pub struct StorageValue<T: WordValue> {
158 pub slot: StorageSlotId,
160 _marker: core::marker::PhantomData<T>,
161}
162
163impl<T: WordValue> StorageValue<T> {
164 pub const fn new(slot: StorageSlotId) -> Self {
166 Self {
167 slot,
168 _marker: core::marker::PhantomData,
169 }
170 }
171}
172
173impl<T: WordValue> From<StorageSlotId> for StorageValue<T> {
174 fn from(slot: StorageSlotId) -> Self {
175 Self::new(slot)
176 }
177}
178
179impl<T: WordValue> StorageValue<T> {
180 #[inline(always)]
182 pub fn get(&self) -> T {
183 T::try_from_word(storage::get_item(self.slot))
184 .unwrap_or_else(|_| panic!("storage slot {:?} contained an invalid word", self.slot))
185 }
186
187 #[inline(always)]
189 pub fn set(&mut self, value: T) -> T {
190 let value = value
191 .try_into_word()
192 .unwrap_or_else(|_| panic!("failed to convert value for storage slot {:?}", self.slot));
193 T::try_from_word(storage::set_item(self.slot, value))
194 .unwrap_or_else(|_| panic!("storage slot {:?} contained an invalid word", self.slot))
195 }
196}
197
198#[derive(Debug, Copy, Clone, PartialEq, Eq)]
200pub struct StorageMap<K: WordKey, V: WordValue> {
201 pub slot: StorageSlotId,
203 _marker: core::marker::PhantomData<(K, V)>,
204}
205
206impl<K: WordKey, V: WordValue> StorageMap<K, V> {
207 pub const fn new(slot: StorageSlotId) -> Self {
209 Self {
210 slot,
211 _marker: core::marker::PhantomData,
212 }
213 }
214}
215
216impl<K: WordKey, V: WordValue> From<StorageSlotId> for StorageMap<K, V> {
217 fn from(slot: StorageSlotId) -> Self {
218 Self::new(slot)
219 }
220}
221
222impl<K: WordKey, V: WordValue> StorageMap<K, V> {
223 #[inline(always)]
228 pub fn get(&self, key: K) -> V {
229 let key = key.try_into_word().unwrap_or_else(|_| {
230 panic!("failed to convert key for storage map slot {:?}", self.slot)
231 });
232 V::try_from_word(storage::get_map_item(self.slot, &key)).unwrap_or_else(|_| {
233 panic!("storage map slot {:?} contained an invalid word", self.slot)
234 })
235 }
236
237 #[inline(always)]
242 pub fn set(&mut self, key: K, value: V) -> V {
243 let key = key.try_into_word().unwrap_or_else(|_| {
244 panic!("failed to convert key for storage map slot {:?}", self.slot)
245 });
246 let value = value.try_into_word().unwrap_or_else(|_| {
247 panic!("failed to convert value for storage map slot {:?}", self.slot)
248 });
249 V::try_from_word(storage::set_map_item(self.slot, key, value)).unwrap_or_else(|_| {
250 panic!("storage map slot {:?} contained an invalid word", self.slot)
251 })
252 }
253}