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 FieldIdentifier, 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 identifier: FieldIdentifier,
40 },
41
42 Value {
47 identifier: Option<FieldIdentifier>,
48 value: [FeltRepresentation; 4],
50 },
51}
52
53impl WordRepresentation {
54 pub fn new_template(r#type: TemplateType, identifier: FieldIdentifier) -> Self {
56 WordRepresentation::Template { r#type, identifier }
57 }
58
59 pub fn new_value(
61 value: impl Into<[FeltRepresentation; 4]>,
62 identifier: Option<FieldIdentifier>,
63 ) -> Self {
64 WordRepresentation::Value { identifier, value: value.into() }
65 }
66
67 pub fn with_description(self, description: impl Into<String>) -> Self {
69 match self {
70 WordRepresentation::Template { r#type, identifier } => WordRepresentation::Template {
71 r#type,
72 identifier: FieldIdentifier {
73 name: identifier.name,
74 description: Some(description.into()),
75 },
76 },
77 WordRepresentation::Value { identifier, value } => WordRepresentation::Value {
78 identifier: identifier.map(|id| FieldIdentifier {
79 name: id.name,
80 description: Some(description.into()),
81 }),
82 value,
83 },
84 }
85 }
86
87 pub fn name(&self) -> Option<&StorageValueName> {
91 match self {
92 WordRepresentation::Template { identifier, .. } => Some(&identifier.name),
93 WordRepresentation::Value { identifier, .. } => identifier.as_ref().map(|id| &id.name),
94 }
95 }
96
97 pub fn description(&self) -> Option<&str> {
100 match self {
101 WordRepresentation::Template { identifier, .. } => identifier.description.as_deref(),
102 WordRepresentation::Value { identifier, .. } => {
103 identifier.as_ref().and_then(|id| id.description.as_deref())
104 },
105 }
106 }
107
108 pub fn word_type(&self) -> TemplateType {
110 match self {
111 WordRepresentation::Template { r#type, .. } => r#type.clone(),
112 WordRepresentation::Value { .. } => TemplateType::native_word(),
113 }
114 }
115
116 pub fn value(&self) -> Option<&[FeltRepresentation; 4]> {
119 match self {
120 WordRepresentation::Value { value, .. } => Some(value),
121 WordRepresentation::Template { .. } => None,
122 }
123 }
124
125 pub fn template_requirements(
132 &self,
133 placeholder_prefix: StorageValueName,
134 ) -> TemplateRequirementsIter<'_> {
135 let placeholder_key =
136 placeholder_prefix.with_suffix(self.name().unwrap_or(&StorageValueName::empty()));
137 match self {
138 WordRepresentation::Template { identifier, r#type } => Box::new(iter::once((
139 placeholder_key,
140 PlaceholderTypeRequirement {
141 description: identifier.description.clone(),
142 r#type: r#type.clone(),
143 },
144 ))),
145 WordRepresentation::Value { value, .. } => Box::new(
146 value
147 .iter()
148 .flat_map(move |felt| felt.template_requirements(placeholder_key.clone())),
149 ),
150 }
151 }
152
153 pub(crate) fn try_build_word(
159 &self,
160 init_storage_data: &InitStorageData,
161 placeholder_prefix: StorageValueName,
162 ) -> Result<Word, AccountComponentTemplateError> {
163 match self {
164 WordRepresentation::Template { identifier, r#type } => {
165 let placeholder_path = placeholder_prefix.with_suffix(&identifier.name);
166 let maybe_value = init_storage_data.get(&placeholder_path);
167 if let Some(value) = maybe_value {
168 let parsed_value = TEMPLATE_REGISTRY
169 .try_parse_word(r#type, value)
170 .map_err(AccountComponentTemplateError::StorageValueParsingError)?;
171
172 Ok(parsed_value)
173 } else {
174 Err(AccountComponentTemplateError::PlaceholderValueNotProvided(
175 placeholder_path,
176 ))
177 }
178 },
179 WordRepresentation::Value { value, identifier } => {
180 let mut result = [Felt::ZERO; 4];
181
182 for (index, felt_repr) in value.iter().enumerate() {
183 let placeholder = placeholder_prefix.clone().with_suffix(
184 identifier
185 .as_ref()
186 .map(|id| &id.name)
187 .unwrap_or(&StorageValueName::empty()),
188 );
189 result[index] = felt_repr.try_build_felt(init_storage_data, placeholder)?;
190 }
191 Ok(result)
193 },
194 }
195 }
196
197 pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
199 let type_exists = TEMPLATE_REGISTRY.contains_word_type(&self.word_type());
201 if !type_exists {
202 return Err(AccountComponentTemplateError::InvalidType(
203 self.word_type().to_string(),
204 "Word".into(),
205 ));
206 }
207
208 if let Some(felts) = self.value() {
209 for felt in felts {
210 felt.validate()?;
211 }
212 }
213
214 Ok(())
215 }
216}
217
218impl Serializable for WordRepresentation {
219 fn write_into<W: ByteWriter>(&self, target: &mut W) {
220 match self {
221 WordRepresentation::Template { identifier, r#type } => {
222 target.write_u8(0);
223 target.write(identifier);
224 target.write(r#type);
225 },
226 WordRepresentation::Value { identifier, value } => {
227 target.write_u8(1);
228 target.write(identifier);
229 target.write(value);
230 },
231 }
232 }
233}
234
235impl Deserializable for WordRepresentation {
236 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
237 let tag = source.read_u8()?;
238 match tag {
239 0 => {
240 let identifier = FieldIdentifier::read_from(source)?;
241 let r#type = TemplateType::read_from(source)?;
242 Ok(WordRepresentation::Template { identifier, r#type })
243 },
244 1 => {
245 let identifier = Option::<FieldIdentifier>::read_from(source)?;
246 let value = <[FeltRepresentation; 4]>::read_from(source)?;
247 Ok(WordRepresentation::Value { identifier, value })
248 },
249 other => Err(DeserializationError::InvalidValue(format!(
250 "unknown tag '{other}' for WordRepresentation"
251 ))),
252 }
253 }
254}
255
256impl From<[FeltRepresentation; 4]> for WordRepresentation {
257 fn from(value: [FeltRepresentation; 4]) -> Self {
258 WordRepresentation::new_value(value, Option::<FieldIdentifier>::None)
259 }
260}
261
262impl From<[Felt; 4]> for WordRepresentation {
263 fn from(value: [Felt; 4]) -> Self {
264 WordRepresentation::new_value(
265 value.map(FeltRepresentation::from),
266 Option::<FieldIdentifier>::None,
267 )
268 }
269}
270
271#[derive(Debug, Clone, PartialEq, Eq)]
281pub enum FeltRepresentation {
282 Value {
287 identifier: Option<FieldIdentifier>,
290 value: Felt,
292 },
293
294 Template {
300 r#type: TemplateType,
302 identifier: FieldIdentifier,
305 },
306}
307
308impl FeltRepresentation {
309 pub fn new_value(value: impl Into<Felt>, name: Option<StorageValueName>) -> Self {
311 FeltRepresentation::Value {
312 value: value.into(),
313 identifier: name.map(FieldIdentifier::with_name),
314 }
315 }
316
317 pub fn new_template(r#type: TemplateType, name: StorageValueName) -> Self {
321 FeltRepresentation::Template {
322 r#type,
323 identifier: FieldIdentifier::with_name(name),
324 }
325 }
326
327 pub fn with_description(self, description: impl Into<String>) -> Self {
329 match self {
330 FeltRepresentation::Template { r#type, identifier } => FeltRepresentation::Template {
331 r#type,
332 identifier: FieldIdentifier {
333 name: identifier.name,
334 description: Some(description.into()),
335 },
336 },
337 FeltRepresentation::Value { identifier, value } => FeltRepresentation::Value {
338 identifier: identifier.map(|id| FieldIdentifier {
339 name: id.name,
340 description: Some(description.into()),
341 }),
342 value,
343 },
344 }
345 }
346
347 pub fn felt_type(&self) -> TemplateType {
349 match self {
350 FeltRepresentation::Template { r#type, .. } => r#type.clone(),
351 FeltRepresentation::Value { .. } => TemplateType::native_felt(),
352 }
353 }
354
355 pub(crate) fn try_build_felt(
360 &self,
361 init_storage_data: &InitStorageData,
362 placeholder_prefix: StorageValueName,
363 ) -> Result<Felt, AccountComponentTemplateError> {
364 match self {
365 FeltRepresentation::Template { identifier, r#type } => {
366 let placeholder_key = placeholder_prefix.with_suffix(&identifier.name);
367 let raw_value = init_storage_data.get(&placeholder_key).ok_or(
368 AccountComponentTemplateError::PlaceholderValueNotProvided(placeholder_key),
369 )?;
370
371 Ok(TEMPLATE_REGISTRY
372 .try_parse_felt(r#type, raw_value)
373 .map_err(AccountComponentTemplateError::StorageValueParsingError)?)
374 },
375 FeltRepresentation::Value { value, .. } => Ok(*value),
376 }
377 }
378
379 pub fn template_requirements(
385 &self,
386 placeholder_prefix: StorageValueName,
387 ) -> TemplateRequirementsIter<'_> {
388 match self {
389 FeltRepresentation::Template { identifier, r#type } => Box::new(iter::once((
390 placeholder_prefix.with_suffix(&identifier.name),
391 PlaceholderTypeRequirement {
392 description: identifier.description.clone(),
393 r#type: r#type.clone(),
394 },
395 ))),
396 _ => Box::new(iter::empty()),
397 }
398 }
399
400 pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
402 let type_exists = TEMPLATE_REGISTRY.contains_felt_type(&self.felt_type());
404 if !type_exists {
405 return Err(AccountComponentTemplateError::InvalidType(
406 self.felt_type().to_string(),
407 "Felt".into(),
408 ));
409 }
410 Ok(())
411 }
412}
413
414impl From<Felt> for FeltRepresentation {
415 fn from(value: Felt) -> Self {
416 FeltRepresentation::new_value(value, Option::<StorageValueName>::None)
417 }
418}
419
420impl Default for FeltRepresentation {
421 fn default() -> Self {
422 FeltRepresentation::new_value(Felt::default(), Option::<StorageValueName>::None)
423 }
424}
425
426impl Serializable for FeltRepresentation {
427 fn write_into<W: ByteWriter>(&self, target: &mut W) {
428 match self {
429 FeltRepresentation::Value { identifier, value } => {
430 target.write_u8(0);
431 target.write(identifier);
432 target.write(value);
433 },
434 FeltRepresentation::Template { identifier, r#type } => {
435 target.write_u8(1);
436 target.write(identifier);
437 target.write(r#type);
438 },
439 }
440 }
441}
442
443impl Deserializable for FeltRepresentation {
444 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
445 let tag = source.read_u8()?;
446 match tag {
447 0 => {
448 let identifier = Option::<FieldIdentifier>::read_from(source)?;
449 let value = Felt::read_from(source)?;
450 Ok(FeltRepresentation::Value { value, identifier })
451 },
452 1 => {
453 let identifier = FieldIdentifier::read_from(source)?;
454 let r#type = TemplateType::read_from(source)?;
455 Ok(FeltRepresentation::Template { r#type, identifier })
456 },
457 other => Err(DeserializationError::InvalidValue(format!(
458 "unknown tag '{other}' for FeltRepresentation"
459 ))),
460 }
461 }
462}
463
464#[derive(Debug, Clone, PartialEq, Eq)]
469#[cfg_attr(feature = "std", derive(::serde::Deserialize, ::serde::Serialize))]
470pub struct MapRepresentation {
471 identifier: FieldIdentifier,
474 entries: Vec<MapEntry>,
476}
477
478impl MapRepresentation {
479 pub fn new(entries: Vec<MapEntry>, name: impl Into<StorageValueName>) -> Self {
481 Self {
482 entries,
483 identifier: FieldIdentifier::with_name(name.into()),
484 }
485 }
486
487 pub fn with_description(self, description: impl Into<String>) -> Self {
489 MapRepresentation {
490 entries: self.entries,
491 identifier: FieldIdentifier {
492 name: self.identifier.name,
493 description: Some(description.into()),
494 },
495 }
496 }
497
498 pub fn template_requirements(&self) -> TemplateRequirementsIter<'_> {
501 Box::new(
502 self.entries
503 .iter()
504 .flat_map(move |entry| entry.template_requirements(self.identifier.name.clone())),
505 )
506 }
507
508 pub fn entries(&self) -> &[MapEntry] {
510 &self.entries
511 }
512
513 pub fn name(&self) -> &StorageValueName {
515 &self.identifier.name
516 }
517
518 pub fn description(&self) -> Option<&String> {
520 self.identifier.description.as_ref()
521 }
522
523 pub fn len(&self) -> usize {
525 self.entries.len()
526 }
527
528 pub fn is_empty(&self) -> bool {
530 self.entries.is_empty()
531 }
532
533 pub fn try_build_map(
538 &self,
539 init_storage_data: &InitStorageData,
540 ) -> Result<StorageMap, AccountComponentTemplateError> {
541 let entries = self
542 .entries
543 .iter()
544 .map(|map_entry| {
545 let key = map_entry
546 .key()
547 .try_build_word(init_storage_data, self.identifier.name.clone())?;
548 let value = map_entry
549 .value()
550 .try_build_word(init_storage_data, self.identifier.name.clone())?;
551 Ok((key.into(), value))
552 })
553 .collect::<Result<Vec<(Digest, Word)>, _>>()?;
554
555 StorageMap::with_entries(entries)
556 .map_err(|err| AccountComponentTemplateError::StorageMapHasDuplicateKeys(Box::new(err)))
557 }
558
559 pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
564 let mut seen_keys = BTreeSet::new();
565 for entry in self.entries() {
566 entry.key().validate()?;
567 entry.value().validate()?;
568 if let Ok(key) = entry
569 .key()
570 .try_build_word(&InitStorageData::default(), StorageValueName::empty())
571 {
572 let key: Digest = key.into();
573 if !seen_keys.insert(key) {
574 return Err(AccountComponentTemplateError::StorageMapHasDuplicateKeys(
575 Box::from(format!("key `{key}` is duplicated")),
576 ));
577 }
578 };
579 }
580 Ok(())
581 }
582}
583
584impl From<MapRepresentation> for Vec<MapEntry> {
585 fn from(value: MapRepresentation) -> Self {
586 value.entries
587 }
588}
589
590impl Serializable for MapRepresentation {
591 fn write_into<W: ByteWriter>(&self, target: &mut W) {
592 self.entries.write_into(target);
593 target.write(&self.identifier);
594 }
595}
596
597impl Deserializable for MapRepresentation {
598 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
599 let entries = Vec::<MapEntry>::read_from(source)?;
600 let identifier = FieldIdentifier::read_from(source)?;
601 Ok(Self { entries, identifier })
602 }
603}
604
605#[derive(Debug, Clone, PartialEq, Eq)]
613pub enum MultiWordRepresentation {
614 Value {
617 identifier: FieldIdentifier,
619 values: Vec<[FeltRepresentation; 4]>,
621 },
622}
623
624impl MultiWordRepresentation {
625 pub fn num_words(&self) -> usize {
627 match self {
628 MultiWordRepresentation::Value { values, .. } => values.len(),
629 }
630 }
631
632 pub fn validate(&self) -> Result<(), AccountComponentTemplateError> {
634 match self {
635 MultiWordRepresentation::Value { values, .. } => {
636 for slot_word in values {
637 for felt_in_slot in slot_word {
638 felt_in_slot.validate()?;
639 }
640 }
641 },
642 }
643 Ok(())
644 }
645}
646
647impl Serializable for MultiWordRepresentation {
648 fn write_into<W: ByteWriter>(&self, target: &mut W) {
649 match self {
650 MultiWordRepresentation::Value { identifier, values } => {
651 target.write_u8(0u8);
652 target.write(identifier);
653 target.write(values);
654 },
655 }
656 }
657}
658impl Deserializable for MultiWordRepresentation {
659 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
660 let variant_tag = source.read_u8()?;
661 match variant_tag {
662 0 => {
663 let identifier: FieldIdentifier = source.read()?;
664 let values: Vec<[FeltRepresentation; 4]> = source.read()?;
665 Ok(MultiWordRepresentation::Value { identifier, values })
666 },
667 _ => Err(DeserializationError::InvalidValue(format!(
668 "unknown variant tag '{variant_tag}' for MultiWordRepresentation"
669 ))),
670 }
671 }
672}