miden_objects/account/component/template/storage/
toml.rs1use alloc::{
2 string::{String, ToString},
3 vec::Vec,
4};
5use core::fmt;
6
7use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
8use vm_core::Felt;
9use vm_processor::Digest;
10
11use super::{
12 FeltRepresentation, MapRepresentation, StorageEntry, StoragePlaceholder, WordRepresentation,
13};
14use crate::{
15 account::AccountComponentMetadata, errors::AccountComponentTemplateError,
16 utils::parse_hex_string_as_word,
17};
18
19impl AccountComponentMetadata {
23 pub fn from_toml(toml_string: &str) -> Result<Self, AccountComponentTemplateError> {
32 let component: AccountComponentMetadata = toml::from_str(toml_string)
33 .map_err(AccountComponentTemplateError::DeserializationError)?;
34 component.validate()?;
35 Ok(component)
36 }
37
38 pub fn as_toml(&self) -> Result<String, AccountComponentTemplateError> {
40 let toml = toml::to_string(self).unwrap();
41 Ok(toml)
42 }
43}
44
45impl serde::Serialize for WordRepresentation {
49 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
50 where
51 S: serde::Serializer,
52 {
53 use serde::ser::SerializeSeq;
54 match self {
55 WordRepresentation::Value(word) => {
56 let word = Digest::from(word);
58 serializer.serialize_str(&word.to_string())
59 },
60 WordRepresentation::Array(words) => {
61 let mut seq = serializer.serialize_seq(Some(4))?;
62 for word in words {
63 seq.serialize_element(word)?;
64 }
65 seq.end()
66 },
67 WordRepresentation::Template(key) => key.serialize(serializer),
68 }
69 }
70}
71
72impl<'de> serde::Deserialize<'de> for WordRepresentation {
73 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
74 where
75 D: serde::Deserializer<'de>,
76 {
77 use serde::de::{Error, SeqAccess, Visitor};
78 struct WordRepresentationVisitor;
79
80 impl<'de> Visitor<'de> for WordRepresentationVisitor {
81 type Value = WordRepresentation;
82
83 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
84 formatter.write_str("a single hex/decimal Word or an array of 4 elements")
85 }
86
87 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
88 where
89 E: Error,
90 {
91 if let Ok(tk) = StoragePlaceholder::try_from(value) {
93 return Ok(WordRepresentation::Template(tk));
94 }
95
96 let word = parse_hex_string_as_word(value).map_err(|_err| {
98 E::invalid_value(
99 serde::de::Unexpected::Str(value),
100 &"a valid hexadecimal string or storage placeholder (in '{{key}}' format)",
101 )
102 })?;
103
104 Ok(WordRepresentation::Value(word))
105 }
106
107 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
108 where
109 A: SeqAccess<'de>,
110 {
111 let mut elements = Vec::with_capacity(4);
112 while let Some(felt_repr) = seq.next_element::<FeltRepresentation>()? {
113 elements.push(felt_repr);
114 }
115
116 if elements.len() == 4 {
117 let array: [FeltRepresentation; 4] =
118 elements.clone().try_into().map_err(|_| {
119 Error::invalid_length(
120 elements.len(),
121 &"expected an array of 4 elements",
122 )
123 })?;
124 Ok(WordRepresentation::Array(array))
125 } else {
126 Err(Error::invalid_length(elements.len(), &"expected an array of 4 elements"))
127 }
128 }
129 }
130
131 deserializer.deserialize_any(WordRepresentationVisitor)
132 }
133}
134
135impl<'de> serde::Deserialize<'de> for FeltRepresentation {
139 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
140 where
141 D: serde::Deserializer<'de>,
142 {
143 let value = String::deserialize(deserializer)?;
144 if let Some(hex_str) = value.strip_prefix("0x").or_else(|| value.strip_prefix("0X")) {
145 let felt_value = u64::from_str_radix(hex_str, 16).map_err(serde::de::Error::custom)?;
146 Ok(FeltRepresentation::Hexadecimal(Felt::new(felt_value)))
147 } else if let Ok(decimal_value) = value.parse::<u64>() {
148 Ok(FeltRepresentation::Decimal(
149 Felt::try_from(decimal_value).map_err(serde::de::Error::custom)?,
150 ))
151 } else if let Ok(key) = StoragePlaceholder::try_from(&value) {
152 Ok(FeltRepresentation::Template(key))
153 } else {
154 Err(serde::de::Error::custom(
155 "deserialized string value is not a valid variant of FeltRepresentation",
156 ))
157 }
158 }
159}
160
161impl serde::Serialize for FeltRepresentation {
162 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
163 where
164 S: serde::Serializer,
165 {
166 match self {
167 FeltRepresentation::Hexadecimal(felt) => {
168 let output = format!("0x{:x}", felt.as_int());
169 serializer.serialize_str(&output)
170 },
171 FeltRepresentation::Decimal(felt) => {
172 let output = felt.as_int().to_string();
173 serializer.serialize_str(&output)
174 },
175 FeltRepresentation::Template(key) => key.serialize(serializer),
176 }
177 }
178}
179
180impl serde::Serialize for StoragePlaceholder {
184 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
185 where
186 S: serde::Serializer,
187 {
188 serializer.serialize_str(&self.to_string())
189 }
190}
191
192impl<'de> serde::Deserialize<'de> for StoragePlaceholder {
193 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
194 where
195 D: serde::Deserializer<'de>,
196 {
197 let s = String::deserialize(deserializer)?;
198 StoragePlaceholder::try_from(s.as_str()).map_err(serde::de::Error::custom)
199 }
200}
201
202#[derive(serde::Deserialize, serde::Serialize)]
207#[serde(untagged)]
208enum StorageValues {
209 Words(Vec<WordRepresentation>),
211 MapEntries(MapRepresentation),
213}
214
215impl StorageValues {
216 pub fn is_list_of_words(&self) -> bool {
217 match self {
218 StorageValues::Words(_) => true,
219 StorageValues::MapEntries(_) => false,
220 }
221 }
222
223 pub fn into_words(self) -> Option<Vec<WordRepresentation>> {
224 match self {
225 StorageValues::Words(vec) => Some(vec),
226 StorageValues::MapEntries(_) => None,
227 }
228 }
229
230 pub fn into_map_entries(self) -> Option<MapRepresentation> {
231 match self {
232 StorageValues::Words(_) => None,
233 StorageValues::MapEntries(map) => Some(map),
234 }
235 }
236
237 pub fn len(&self) -> Option<usize> {
238 match self {
239 StorageValues::Words(vec) => Some(vec.len()),
240 StorageValues::MapEntries(map) => map.len(),
241 }
242 }
243}
244
245#[derive(Default, Deserialize, Serialize)]
250struct RawStorageEntry {
251 name: String,
252 description: Option<String>,
253 slot: Option<u8>,
254 slots: Option<Vec<u8>>,
255 value: Option<WordRepresentation>,
256 values: Option<StorageValues>,
257}
258
259impl From<StorageEntry> for RawStorageEntry {
260 fn from(entry: StorageEntry) -> Self {
261 match entry {
262 StorageEntry::Value { name, description, slot, value } => RawStorageEntry {
263 name,
264 description,
265 slot: Some(slot),
266 value: Some(value),
267 ..Default::default()
268 },
269 StorageEntry::Map { name, description, slot, map: values } => RawStorageEntry {
270 name,
271 description,
272 slot: Some(slot),
273 values: Some(StorageValues::MapEntries(values)),
274 ..Default::default()
275 },
276 StorageEntry::MultiSlot { name, description, slots, values } => RawStorageEntry {
277 name,
278 description,
279 slots: Some(slots),
280 values: Some(StorageValues::Words(values)),
281 ..Default::default()
282 },
283 }
284 }
285}
286
287impl Serialize for StorageEntry {
288 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
289 where
290 S: Serializer,
291 {
292 let raw_storage_entry: RawStorageEntry = self.clone().into();
293 raw_storage_entry.serialize(serializer)
294 }
295}
296
297impl<'de> Deserialize<'de> for StorageEntry {
298 fn deserialize<D>(deserializer: D) -> Result<StorageEntry, D::Error>
299 where
300 D: Deserializer<'de>,
301 {
302 let raw = RawStorageEntry::deserialize(deserializer)?;
303
304 let slot_present = raw.slot.is_some();
306 let value_present = raw.value.is_some();
307
308 match (raw.slots, raw.values) {
310 (None, None) => {
311 Ok(StorageEntry::Value {
314 name: raw.name,
315 description: raw.description,
316 slot: raw
317 .slot
318 .ok_or(D::Error::custom("missing 'slot' field for single-slot entry"))?,
319 value: raw
320 .value
321 .ok_or(D::Error::custom("missing 'value' field for single-slot entry"))?,
322 })
323 },
324 (Some(_), None) => {
325 Err(D::Error::custom("`slots` is defined but no `values` field was found"))
326 },
327 (None, Some(values)) => {
328 if value_present {
334 return Err(D::Error::custom(
335 "fields 'value' and 'values' are mutually exclusive",
336 ));
337 }
338
339 let map_entries = values
340 .into_map_entries()
341 .ok_or_else(|| D::Error::custom("invalid 'values' for map entry"))?;
342
343 Ok(StorageEntry::Map {
344 name: raw.name,
345 description: raw.description,
346 slot: raw.slot.ok_or(D::Error::missing_field("slot"))?,
347 map: map_entries,
348 })
349 },
350 (Some(slots), Some(values)) => {
351 if slot_present {
357 return Err(D::Error::custom(
358 "fields 'slot' and 'slots' are mutually exclusive",
359 ));
360 }
361 if value_present {
362 return Err(D::Error::custom(
363 "fields 'value' and 'values' are mutually exclusive",
364 ));
365 }
366
367 let has_list_of_values = values.is_list_of_words();
368 if has_list_of_values {
369 let slots_count = slots.len();
370 let values_count = values.len().expect("checked that it's a list of values");
371 if slots_count != values_count {
372 return Err(D::Error::custom(format!(
373 "number of slots ({}) does not match number of values ({}) for multi-slot storage entry",
374 slots_count, values_count
375 )));
376 }
377 }
378
379 Ok(StorageEntry::MultiSlot {
380 name: raw.name,
381 description: raw.description,
382 slots,
383 values: values
384 .into_words()
385 .ok_or_else(|| D::Error::custom("invalid values for multi-slot"))?,
386 })
387 },
388 }
389 }
390}