1use alloc::{
2 boxed::Box,
3 collections::BTreeSet,
4 string::{String, ToString},
5 vec::Vec,
6};
7use core::iter;
8
9use vm_core::{
10 Felt, FieldElement, Word,
11 utils::{ByteReader, ByteWriter, Deserializable, Serializable},
12};
13use vm_processor::{DeserializationError, Digest};
14
15use super::{
16 InitStorageData, MapEntry, StorageValueName, TemplateRequirementsIter,
17 placeholder::{PlaceholderTypeRequirement, TEMPLATE_REGISTRY, TemplateType},
18};
19use crate::account::{StorageMap, component::template::AccountComponentTemplateError};
20
21#[derive(Debug, Clone, PartialEq, Eq)]
30#[allow(clippy::large_enum_variant)]
31pub enum WordRepresentation {
32 Template {
37 r#type: TemplateType,
39 name: StorageValueName,
41 description: Option<String>,
43 },
44
45 Value {
50 name: Option<StorageValueName>,
52 description: Option<String>,
54 value: [FeltRepresentation; 4],
56 },
57}
58
59impl WordRepresentation {
60 pub fn new_template(r#type: TemplateType, name: StorageValueName) -> Self {
62 WordRepresentation::Template { name, description: None, r#type }
63 }
64
65 pub fn new_value(
67 value: impl Into<[FeltRepresentation; 4]>,
68 name: Option<StorageValueName>,
69 ) -> Self {
70 WordRepresentation::Value {
71 name,
72 description: None,
73 value: value.into(),
74 }
75 }
76
77 pub fn with_description(self, description: impl Into<String>) -> Self {
79 match self {
80 WordRepresentation::Template { r#type, name, .. } => WordRepresentation::Template {
81 r#type,
82 name,
83 description: Some(description.into()),
84 },
85 WordRepresentation::Value { name, value, .. } => WordRepresentation::Value {
86 name,
87 description: Some(description.into()),
88 value,
89 },
90 }
91 }
92
93 pub fn name(&self) -> Option<&StorageValueName> {
97 match self {
98 WordRepresentation::Template { name, .. } => Some(name),
99 WordRepresentation::Value { name, .. } => name.as_ref(),
100 }
101 }
102
103 pub fn description(&self) -> Option<&str> {
106 match self {
107 WordRepresentation::Template { description, .. } => description.as_deref(),
108 WordRepresentation::Value { description, .. } => description.as_deref(),
109 }
110 }
111
112 pub fn word_type(&self) -> TemplateType {
114 match self {
115 WordRepresentation::Template { r#type, .. } => r#type.clone(),
116 WordRepresentation::Value { .. } => TemplateType::native_word(),
117 }
118 }
119
120 pub fn value(&self) -> Option<&[FeltRepresentation; 4]> {
123 match self {
124 WordRepresentation::Value { value, .. } => Some(value),
125 WordRepresentation::Template { .. } => None,
126 }
127 }
128
129 pub fn template_requirements(
136 &self,
137 placeholder_prefix: StorageValueName,
138 ) -> TemplateRequirementsIter<'_> {
139 let placeholder_key =
140 placeholder_prefix.with_suffix(self.name().unwrap_or(&StorageValueName::empty()));
141 match self {
142 WordRepresentation::Template { description, r#type, .. } => Box::new(iter::once((
144 placeholder_key,
145 PlaceholderTypeRequirement {
146 description: description.clone(),
147 r#type: r#type.clone(),
148 },
149 ))),
150 WordRepresentation::Value { value, .. } => Box::new(
152 value
153 .iter()
154 .flat_map(move |felt| felt.template_requirements(placeholder_key.clone())),
155 ),
156 }
157 }
158
159 pub(crate) fn try_build_word(
165 &self,
166 init_storage_data: &InitStorageData,
167 placeholder_prefix: StorageValueName,
168 ) -> Result<Word, AccountComponentTemplateError> {
169 match self {
170 WordRepresentation::Template { name: placeholder_key, r#type, .. } => {
171 let placeholder_path = placeholder_prefix.with_suffix(placeholder_key);
172 let maybe_value = init_storage_data.get(&placeholder_path);
173 if let Some(value) = maybe_value {
174 let parsed_value = TEMPLATE_REGISTRY
175 .try_parse_word(r#type, value)
176 .map_err(AccountComponentTemplateError::StorageValueParsingError)?;
177
178 Ok(parsed_value)
179 } else {
180 Err(AccountComponentTemplateError::PlaceholderValueNotProvided(
181 placeholder_path,
182 ))
183 }
184 },
185 WordRepresentation::Value { value, name, .. } => {
186 let mut result = [Felt::ZERO; 4];
187
188 for (index, felt_repr) in value.iter().enumerate() {
189 let placeholder = placeholder_prefix
190 .clone()
191 .with_suffix(&name.clone().unwrap_or(StorageValueName::empty()));
192 result[index] = felt_repr.try_build_felt(init_storage_data, placeholder)?;
193 }
194 Ok(result)
196 },
197 }
198 }
199
200 pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
202 let type_exists = TEMPLATE_REGISTRY.contains_word_type(&self.word_type());
204 if !type_exists {
205 return Err(AccountComponentTemplateError::InvalidType(
206 self.word_type().to_string(),
207 "Word".into(),
208 ));
209 }
210
211 if let Some(felts) = self.value() {
212 for felt in felts {
213 felt.validate()?;
214 }
215 }
216
217 Ok(())
218 }
219}
220
221impl Serializable for WordRepresentation {
222 fn write_into<W: ByteWriter>(&self, target: &mut W) {
223 match self {
224 WordRepresentation::Template { name, description, r#type } => {
225 target.write_u8(0);
226 target.write(name);
227 target.write(description);
228 target.write(r#type);
229 },
230 WordRepresentation::Value { name, description, value } => {
231 target.write_u8(1);
232 target.write(name);
233 target.write(description);
234 target.write(value);
235 },
236 }
237 }
238}
239
240impl Deserializable for WordRepresentation {
241 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
242 let tag = source.read_u8()?;
243 match tag {
244 0 => {
245 let name = StorageValueName::read_from(source)?;
246 let description = Option::<String>::read_from(source)?;
247 let r#type = TemplateType::read_from(source)?;
248 Ok(WordRepresentation::Template { name, description, r#type })
249 },
250 1 => {
251 let name = Option::<StorageValueName>::read_from(source)?;
252 let description = Option::<String>::read_from(source)?;
253 let value = <[FeltRepresentation; 4]>::read_from(source)?;
254 Ok(WordRepresentation::Value { name, description, value })
255 },
256 other => Err(DeserializationError::InvalidValue(format!(
257 "Unknown tag for WordRepresentation: {}",
258 other
259 ))),
260 }
261 }
262}
263
264impl From<[FeltRepresentation; 4]> for WordRepresentation {
265 fn from(value: [FeltRepresentation; 4]) -> Self {
266 WordRepresentation::new_value(value, Option::<StorageValueName>::None)
267 }
268}
269
270impl From<[Felt; 4]> for WordRepresentation {
271 fn from(value: [Felt; 4]) -> Self {
272 WordRepresentation::new_value(
273 value.map(FeltRepresentation::from),
274 Option::<StorageValueName>::None,
275 )
276 }
277}
278
279#[derive(Debug, Clone, PartialEq, Eq)]
289pub enum FeltRepresentation {
290 Value {
295 name: Option<StorageValueName>,
297 description: Option<String>,
299 value: Felt,
301 },
302
303 Template {
309 r#type: TemplateType,
311 name: StorageValueName,
313 description: Option<String>,
315 },
316}
317
318impl FeltRepresentation {
319 pub fn new_value(value: impl Into<Felt>, name: Option<StorageValueName>) -> FeltRepresentation {
321 FeltRepresentation::Value {
322 value: value.into(),
323 name,
324 description: None,
325 }
326 }
327
328 pub fn new_template(r#type: TemplateType, name: StorageValueName) -> FeltRepresentation {
332 FeltRepresentation::Template { name, description: None, r#type }
333 }
334
335 pub fn with_description(self, description: impl Into<String>) -> Self {
337 match self {
338 FeltRepresentation::Template { r#type, name, .. } => FeltRepresentation::Template {
339 r#type,
340 name,
341 description: Some(description.into()),
342 },
343 FeltRepresentation::Value { name, value, .. } => FeltRepresentation::Value {
344 name,
345 description: Some(description.into()),
346 value,
347 },
348 }
349 }
350
351 pub fn felt_type(&self) -> TemplateType {
353 match self {
354 FeltRepresentation::Template { r#type, .. } => r#type.clone(),
355 FeltRepresentation::Value { .. } => TemplateType::native_felt(),
356 }
357 }
358
359 pub(crate) fn try_build_felt(
364 &self,
365 init_storage_data: &InitStorageData,
366 placeholder_prefix: StorageValueName,
367 ) -> Result<Felt, AccountComponentTemplateError> {
368 match self {
369 FeltRepresentation::Template { name, r#type, .. } => {
370 let placeholder_key = placeholder_prefix.with_suffix(name);
371 let raw_value = init_storage_data.get(&placeholder_key).ok_or(
372 AccountComponentTemplateError::PlaceholderValueNotProvided(placeholder_key),
373 )?;
374
375 Ok(TEMPLATE_REGISTRY
376 .try_parse_felt(r#type, raw_value)
377 .map_err(AccountComponentTemplateError::StorageValueParsingError)?)
378 },
379 FeltRepresentation::Value { value, .. } => Ok(*value),
380 }
381 }
382
383 pub fn template_requirements(
389 &self,
390 placeholder_prefix: StorageValueName,
391 ) -> TemplateRequirementsIter<'_> {
392 match self {
393 FeltRepresentation::Template { name, description, r#type } => Box::new(iter::once((
394 placeholder_prefix.with_suffix(name),
395 PlaceholderTypeRequirement {
396 description: description.clone(),
397 r#type: r#type.clone(),
398 },
399 ))),
400 _ => Box::new(iter::empty()),
401 }
402 }
403
404 pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
406 let type_exists = TEMPLATE_REGISTRY.contains_felt_type(&self.felt_type());
408 if !type_exists {
409 return Err(AccountComponentTemplateError::InvalidType(
410 self.felt_type().to_string(),
411 "Felt".into(),
412 ));
413 }
414 Ok(())
415 }
416}
417
418impl From<Felt> for FeltRepresentation {
419 fn from(value: Felt) -> Self {
420 FeltRepresentation::new_value(value, Option::<StorageValueName>::None)
421 }
422}
423
424impl Default for FeltRepresentation {
425 fn default() -> Self {
426 FeltRepresentation::new_value(Felt::default(), Option::<StorageValueName>::None)
427 }
428}
429
430impl Serializable for FeltRepresentation {
431 fn write_into<W: ByteWriter>(&self, target: &mut W) {
432 match self {
433 FeltRepresentation::Value { name, description, value } => {
434 target.write_u8(0);
435 target.write(name);
436 target.write(description);
437 target.write(value);
438 },
439 FeltRepresentation::Template { name, description, r#type } => {
440 target.write_u8(1);
441 target.write(name);
442 target.write(description);
443 target.write(r#type);
444 },
445 }
446 }
447}
448
449impl Deserializable for FeltRepresentation {
450 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
451 let tag = source.read_u8()?;
452 match tag {
453 0 => {
454 let name = Option::<StorageValueName>::read_from(source)?;
455 let description = Option::<String>::read_from(source)?;
456 let value = Felt::read_from(source)?;
457 Ok(FeltRepresentation::Value { value, name, description })
458 },
459 1 => {
460 let name = StorageValueName::read_from(source)?;
461 let description = Option::<String>::read_from(source)?;
462 let r#type = TemplateType::read_from(source)?;
463 Ok(FeltRepresentation::Template { r#type, name, description })
464 },
465 other => Err(DeserializationError::InvalidValue(format!(
466 "Unknown tag for FeltRepresentation: {}",
467 other
468 ))),
469 }
470 }
471}
472
473#[derive(Debug, Clone, PartialEq, Eq)]
478#[cfg_attr(feature = "std", derive(::serde::Deserialize, ::serde::Serialize))]
479pub struct MapRepresentation {
480 name: StorageValueName,
482 description: Option<String>,
484 entries: Vec<MapEntry>,
486}
487
488impl MapRepresentation {
489 pub fn new(entries: Vec<MapEntry>, name: impl Into<StorageValueName>) -> Self {
491 Self {
492 entries,
493 name: name.into(),
494 description: None,
495 }
496 }
497
498 pub fn with_description(self, description: impl Into<String>) -> Self {
500 MapRepresentation {
501 name: self.name,
502 entries: self.entries,
503 description: Some(description.into()),
504 }
505 }
506
507 pub fn template_requirements(&self) -> TemplateRequirementsIter<'_> {
510 Box::new(
511 self.entries
512 .iter()
513 .flat_map(move |entry| entry.template_requirements(self.name.clone())),
514 )
515 }
516
517 pub fn entries(&self) -> &[MapEntry] {
519 &self.entries
520 }
521
522 pub fn name(&self) -> &StorageValueName {
524 &self.name
525 }
526
527 pub fn description(&self) -> Option<&String> {
529 self.description.as_ref()
530 }
531
532 pub fn len(&self) -> usize {
534 self.entries.len()
535 }
536
537 pub fn is_empty(&self) -> bool {
539 self.entries.is_empty()
540 }
541
542 pub fn try_build_map(
547 &self,
548 init_storage_data: &InitStorageData,
549 ) -> Result<StorageMap, AccountComponentTemplateError> {
550 let entries = self
551 .entries
552 .iter()
553 .map(|map_entry| {
554 let key = map_entry.key().try_build_word(init_storage_data, self.name().clone())?;
555 let value =
556 map_entry.value().try_build_word(init_storage_data, self.name().clone())?;
557 Ok((key.into(), value))
558 })
559 .collect::<Result<Vec<(Digest, Word)>, _>>()?;
560
561 StorageMap::with_entries(entries)
562 .map_err(|err| AccountComponentTemplateError::StorageMapHasDuplicateKeys(Box::new(err)))
563 }
564
565 pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
570 let mut seen_keys = BTreeSet::new();
571 for entry in self.entries() {
572 entry.key().validate()?;
576 entry.value().validate()?;
577 if let Ok(key) = entry
578 .key()
579 .try_build_word(&InitStorageData::default(), StorageValueName::empty())
580 {
581 let key: Digest = key.into();
582 if !seen_keys.insert(key) {
583 return Err(AccountComponentTemplateError::StorageMapHasDuplicateKeys(
584 Box::from(format!("key `{key}` is duplicated")),
585 ));
586 }
587 };
588 }
589 Ok(())
590 }
591}
592
593impl From<MapRepresentation> for Vec<MapEntry> {
594 fn from(value: MapRepresentation) -> Self {
595 value.entries
596 }
597}
598
599impl Serializable for MapRepresentation {
600 fn write_into<W: ByteWriter>(&self, target: &mut W) {
601 self.entries.write_into(target);
602 self.name.write_into(target);
603 self.description.write_into(target);
604 }
605}
606
607impl Deserializable for MapRepresentation {
608 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
609 let entries = Vec::<MapEntry>::read_from(source)?;
610 let name = StorageValueName::read_from(source)?;
611 let description = Option::<String>::read_from(source)?;
612 Ok(Self { entries, name, description })
613 }
614}