miden_protocol/account/component/storage/
init_storage_data.rs1use alloc::collections::BTreeMap;
2use alloc::string::{String, ToString};
3use alloc::vec::Vec;
4
5use thiserror::Error;
6
7use super::StorageValueName;
8use super::value_name::StorageValueNameError;
9use crate::account::StorageSlotName;
10use crate::errors::StorageSlotNameError;
11use crate::{Felt, FieldElement, Word};
12
13#[derive(Clone, Debug, PartialEq, Eq)]
19pub enum WordValue {
20 FullyTyped(Word),
22 Atomic(String),
24 Elements([String; 4]),
26}
27
28impl From<Word> for WordValue {
32 fn from(value: Word) -> Self {
33 WordValue::FullyTyped(value)
34 }
35}
36
37impl From<String> for WordValue {
38 fn from(value: String) -> Self {
39 WordValue::Atomic(value)
40 }
41}
42
43impl From<&str> for WordValue {
44 fn from(value: &str) -> Self {
45 WordValue::Atomic(String::from(value))
46 }
47}
48
49impl From<Felt> for WordValue {
50 fn from(value: Felt) -> Self {
52 WordValue::FullyTyped(Word::from([Felt::ZERO, Felt::ZERO, Felt::ZERO, value]))
53 }
54}
55
56impl From<[Felt; 4]> for WordValue {
57 fn from(value: [Felt; 4]) -> Self {
58 WordValue::FullyTyped(Word::from(value))
59 }
60}
61
62impl From<u8> for WordValue {
63 fn from(value: u8) -> Self {
65 WordValue::Atomic(value.to_string())
66 }
67}
68
69impl From<u16> for WordValue {
70 fn from(value: u16) -> Self {
72 WordValue::Atomic(value.to_string())
73 }
74}
75
76impl From<u32> for WordValue {
77 fn from(value: u32) -> Self {
79 WordValue::Atomic(value.to_string())
80 }
81}
82
83impl From<u64> for WordValue {
84 fn from(value: u64) -> Self {
86 WordValue::Atomic(value.to_string())
87 }
88}
89
90impl From<[u32; 4]> for WordValue {
91 fn from(value: [u32; 4]) -> Self {
93 WordValue::FullyTyped(Word::from([
94 Felt::from(value[0]),
95 Felt::from(value[1]),
96 Felt::from(value[2]),
97 Felt::from(value[3]),
98 ]))
99 }
100}
101
102#[derive(Clone, Debug, Default)]
111pub struct InitStorageData {
112 value_entries: BTreeMap<StorageValueName, WordValue>,
114 map_entries: BTreeMap<StorageSlotName, Vec<(WordValue, WordValue)>>,
116}
117
118impl InitStorageData {
119 pub fn new(
128 value_entries: BTreeMap<StorageValueName, WordValue>,
129 map_entries: BTreeMap<StorageSlotName, Vec<(WordValue, WordValue)>>,
130 ) -> Result<Self, InitStorageDataError> {
131 for slot_name in map_entries.keys() {
133 if value_entries.keys().any(|v| v.slot_name() == slot_name) {
134 return Err(InitStorageDataError::ConflictingEntries(slot_name.as_str().into()));
135 }
136 }
137
138 for value_name in value_entries.keys() {
140 if value_name.field_name().is_none() {
141 let has_field_entries = value_entries.keys().any(|other| {
143 other.slot_name() == value_name.slot_name() && other.field_name().is_some()
144 });
145 if has_field_entries {
146 return Err(InitStorageDataError::ConflictingEntries(
147 value_name.slot_name().as_str().into(),
148 ));
149 }
150 }
151 }
152
153 Ok(InitStorageData { value_entries, map_entries })
154 }
155
156 pub fn values(&self) -> &BTreeMap<StorageValueName, WordValue> {
158 &self.value_entries
159 }
160
161 pub fn maps(&self) -> &BTreeMap<StorageSlotName, Vec<(WordValue, WordValue)>> {
163 &self.map_entries
164 }
165
166 pub fn value_entry(&self, name: &StorageValueName) -> Option<&WordValue> {
168 self.value_entries.get(name)
169 }
170
171 pub fn slot_value_entry(&self, slot_name: &StorageSlotName) -> Option<&WordValue> {
173 let name = StorageValueName::from_slot_name(slot_name);
174 self.value_entries.get(&name)
175 }
176
177 pub fn map_entries(&self, slot_name: &StorageSlotName) -> Option<&Vec<(WordValue, WordValue)>> {
179 self.map_entries.get(slot_name)
180 }
181
182 pub fn has_value_entries_for_slot(&self, slot_name: &StorageSlotName) -> bool {
184 self.value_entries.keys().any(|name| name.slot_name() == slot_name)
185 }
186
187 pub fn has_field_entries_for_slot(&self, slot_name: &StorageSlotName) -> bool {
189 self.value_entries
190 .keys()
191 .any(|name| name.slot_name() == slot_name && name.field_name().is_some())
192 }
193
194 pub fn insert_value<N, E>(
213 &mut self,
214 name: N,
215 value: impl Into<WordValue>,
216 ) -> Result<(), InitStorageDataError>
217 where
218 N: TryInto<StorageValueName, Error = E>,
219 InitStorageDataError: From<E>,
220 {
221 let name = name.try_into().map_err(InitStorageDataError::from)?;
222 if self.value_entries.contains_key(&name) {
223 return Err(InitStorageDataError::DuplicateKey(name.to_string()));
224 }
225 if self.map_entries.contains_key(name.slot_name()) {
226 return Err(InitStorageDataError::ConflictingEntries(name.slot_name().as_str().into()));
227 }
228 self.value_entries.insert(name, value.into());
229 Ok(())
230 }
231
232 pub fn set_value<N, E>(
238 &mut self,
239 name: N,
240 value: impl Into<WordValue>,
241 ) -> Result<(), InitStorageDataError>
242 where
243 N: TryInto<StorageValueName, Error = E>,
244 InitStorageDataError: From<E>,
245 {
246 let name = name.try_into().map_err(InitStorageDataError::from)?;
247 if self.map_entries.contains_key(name.slot_name()) {
248 return Err(InitStorageDataError::ConflictingEntries(name.slot_name().as_str().into()));
249 }
250 self.value_entries.insert(name, value.into());
251 Ok(())
252 }
253
254 pub fn insert_map_entry<S, E>(
263 &mut self,
264 slot_name: S,
265 key: impl Into<WordValue>,
266 value: impl Into<WordValue>,
267 ) -> Result<(), InitStorageDataError>
268 where
269 S: TryInto<StorageSlotName, Error = E>,
270 InitStorageDataError: From<E>,
271 {
272 let slot_name = slot_name.try_into().map_err(InitStorageDataError::from)?;
273 if self.has_value_entries_for_slot(&slot_name) {
274 return Err(InitStorageDataError::ConflictingEntries(slot_name.as_str().into()));
275 }
276
277 let key = key.into();
278 if let Some(entries) = self.map_entries.get(&slot_name)
279 && entries.iter().any(|(existing_key, _)| existing_key == &key)
280 {
281 return Err(InitStorageDataError::DuplicateKey(format!(
282 "{}[{key:?}]",
283 slot_name.as_str()
284 )));
285 }
286
287 self.map_entries.entry(slot_name).or_default().push((key, value.into()));
288 Ok(())
289 }
290
291 pub fn set_map_values<S, E>(
297 &mut self,
298 slot_name: S,
299 entries: Vec<(WordValue, WordValue)>,
300 ) -> Result<(), InitStorageDataError>
301 where
302 S: TryInto<StorageSlotName, Error = E>,
303 InitStorageDataError: From<E>,
304 {
305 let slot_name = slot_name.try_into().map_err(InitStorageDataError::from)?;
306 if self.has_value_entries_for_slot(&slot_name) {
307 return Err(InitStorageDataError::ConflictingEntries(slot_name.as_str().into()));
308 }
309 self.map_entries.insert(slot_name, entries);
310 Ok(())
311 }
312
313 pub fn merge_with(&mut self, other: InitStorageData) {
316 self.value_entries.extend(other.value_entries);
317 for (slot_name, entries) in other.map_entries {
318 self.map_entries.entry(slot_name).or_default().extend(entries);
319 }
320 }
321
322 pub fn merge_from(&mut self, other: InitStorageData) {
325 self.merge_with(other);
326 }
327}
328
329#[derive(Debug, Error)]
334pub enum InitStorageDataError {
335 #[error("duplicate init key `{0}`")]
336 DuplicateKey(String),
337 #[error("conflicting init entries for `{0}`")]
338 ConflictingEntries(String),
339 #[error("invalid storage value name")]
340 InvalidValueName(#[from] StorageValueNameError),
341 #[error("invalid storage slot name")]
342 InvalidSlotName(#[from] StorageSlotNameError),
343}
344
345impl From<core::convert::Infallible> for InitStorageDataError {
346 fn from(err: core::convert::Infallible) -> Self {
347 match err {}
348 }
349}