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 for WordRepresentation: {}",
251 other
252 ))),
253 }
254 }
255}
256
257impl From<[FeltRepresentation; 4]> for WordRepresentation {
258 fn from(value: [FeltRepresentation; 4]) -> Self {
259 WordRepresentation::new_value(value, Option::<FieldIdentifier>::None)
260 }
261}
262
263impl From<[Felt; 4]> for WordRepresentation {
264 fn from(value: [Felt; 4]) -> Self {
265 WordRepresentation::new_value(
266 value.map(FeltRepresentation::from),
267 Option::<FieldIdentifier>::None,
268 )
269 }
270}
271
272#[derive(Debug, Clone, PartialEq, Eq)]
282pub enum FeltRepresentation {
283 Value {
288 identifier: Option<FieldIdentifier>,
291 value: Felt,
293 },
294
295 Template {
301 r#type: TemplateType,
303 identifier: FieldIdentifier,
306 },
307}
308
309impl FeltRepresentation {
310 pub fn new_value(value: impl Into<Felt>, name: Option<StorageValueName>) -> Self {
312 FeltRepresentation::Value {
313 value: value.into(),
314 identifier: name.map(FieldIdentifier::with_name),
315 }
316 }
317
318 pub fn new_template(r#type: TemplateType, name: StorageValueName) -> Self {
322 FeltRepresentation::Template {
323 r#type,
324 identifier: FieldIdentifier::with_name(name),
325 }
326 }
327
328 pub fn with_description(self, description: impl Into<String>) -> Self {
330 match self {
331 FeltRepresentation::Template { r#type, identifier } => FeltRepresentation::Template {
332 r#type,
333 identifier: FieldIdentifier {
334 name: identifier.name,
335 description: Some(description.into()),
336 },
337 },
338 FeltRepresentation::Value { identifier, value } => FeltRepresentation::Value {
339 identifier: identifier.map(|id| FieldIdentifier {
340 name: id.name,
341 description: Some(description.into()),
342 }),
343 value,
344 },
345 }
346 }
347
348 pub fn felt_type(&self) -> TemplateType {
350 match self {
351 FeltRepresentation::Template { r#type, .. } => r#type.clone(),
352 FeltRepresentation::Value { .. } => TemplateType::native_felt(),
353 }
354 }
355
356 pub(crate) fn try_build_felt(
361 &self,
362 init_storage_data: &InitStorageData,
363 placeholder_prefix: StorageValueName,
364 ) -> Result<Felt, AccountComponentTemplateError> {
365 match self {
366 FeltRepresentation::Template { identifier, r#type } => {
367 let placeholder_key = placeholder_prefix.with_suffix(&identifier.name);
368 let raw_value = init_storage_data.get(&placeholder_key).ok_or(
369 AccountComponentTemplateError::PlaceholderValueNotProvided(placeholder_key),
370 )?;
371
372 Ok(TEMPLATE_REGISTRY
373 .try_parse_felt(r#type, raw_value)
374 .map_err(AccountComponentTemplateError::StorageValueParsingError)?)
375 },
376 FeltRepresentation::Value { value, .. } => Ok(*value),
377 }
378 }
379
380 pub fn template_requirements(
386 &self,
387 placeholder_prefix: StorageValueName,
388 ) -> TemplateRequirementsIter<'_> {
389 match self {
390 FeltRepresentation::Template { identifier, r#type } => Box::new(iter::once((
391 placeholder_prefix.with_suffix(&identifier.name),
392 PlaceholderTypeRequirement {
393 description: identifier.description.clone(),
394 r#type: r#type.clone(),
395 },
396 ))),
397 _ => Box::new(iter::empty()),
398 }
399 }
400
401 pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
403 let type_exists = TEMPLATE_REGISTRY.contains_felt_type(&self.felt_type());
405 if !type_exists {
406 return Err(AccountComponentTemplateError::InvalidType(
407 self.felt_type().to_string(),
408 "Felt".into(),
409 ));
410 }
411 Ok(())
412 }
413}
414
415impl From<Felt> for FeltRepresentation {
416 fn from(value: Felt) -> Self {
417 FeltRepresentation::new_value(value, Option::<StorageValueName>::None)
418 }
419}
420
421impl Default for FeltRepresentation {
422 fn default() -> Self {
423 FeltRepresentation::new_value(Felt::default(), Option::<StorageValueName>::None)
424 }
425}
426
427impl Serializable for FeltRepresentation {
428 fn write_into<W: ByteWriter>(&self, target: &mut W) {
429 match self {
430 FeltRepresentation::Value { identifier, value } => {
431 target.write_u8(0);
432 target.write(identifier);
433 target.write(value);
434 },
435 FeltRepresentation::Template { identifier, r#type } => {
436 target.write_u8(1);
437 target.write(identifier);
438 target.write(r#type);
439 },
440 }
441 }
442}
443
444impl Deserializable for FeltRepresentation {
445 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
446 let tag = source.read_u8()?;
447 match tag {
448 0 => {
449 let identifier = Option::<FieldIdentifier>::read_from(source)?;
450 let value = Felt::read_from(source)?;
451 Ok(FeltRepresentation::Value { value, identifier })
452 },
453 1 => {
454 let identifier = FieldIdentifier::read_from(source)?;
455 let r#type = TemplateType::read_from(source)?;
456 Ok(FeltRepresentation::Template { r#type, identifier })
457 },
458 other => Err(DeserializationError::InvalidValue(format!(
459 "Unknown tag for FeltRepresentation: {}",
460 other
461 ))),
462 }
463 }
464}
465
466#[derive(Debug, Clone, PartialEq, Eq)]
471#[cfg_attr(feature = "std", derive(::serde::Deserialize, ::serde::Serialize))]
472pub struct MapRepresentation {
473 identifier: FieldIdentifier,
476 entries: Vec<MapEntry>,
478}
479
480impl MapRepresentation {
481 pub fn new(entries: Vec<MapEntry>, name: impl Into<StorageValueName>) -> Self {
483 Self {
484 entries,
485 identifier: FieldIdentifier::with_name(name.into()),
486 }
487 }
488
489 pub fn with_description(self, description: impl Into<String>) -> Self {
491 MapRepresentation {
492 entries: self.entries,
493 identifier: FieldIdentifier {
494 name: self.identifier.name,
495 description: Some(description.into()),
496 },
497 }
498 }
499
500 pub fn template_requirements(&self) -> TemplateRequirementsIter<'_> {
503 Box::new(
504 self.entries
505 .iter()
506 .flat_map(move |entry| entry.template_requirements(self.identifier.name.clone())),
507 )
508 }
509
510 pub fn entries(&self) -> &[MapEntry] {
512 &self.entries
513 }
514
515 pub fn name(&self) -> &StorageValueName {
517 &self.identifier.name
518 }
519
520 pub fn description(&self) -> Option<&String> {
522 self.identifier.description.as_ref()
523 }
524
525 pub fn len(&self) -> usize {
527 self.entries.len()
528 }
529
530 pub fn is_empty(&self) -> bool {
532 self.entries.is_empty()
533 }
534
535 pub fn try_build_map(
540 &self,
541 init_storage_data: &InitStorageData,
542 ) -> Result<StorageMap, AccountComponentTemplateError> {
543 let entries = self
544 .entries
545 .iter()
546 .map(|map_entry| {
547 let key = map_entry
548 .key()
549 .try_build_word(init_storage_data, self.identifier.name.clone())?;
550 let value = map_entry
551 .value()
552 .try_build_word(init_storage_data, self.identifier.name.clone())?;
553 Ok((key.into(), value))
554 })
555 .collect::<Result<Vec<(Digest, Word)>, _>>()?;
556
557 StorageMap::with_entries(entries)
558 .map_err(|err| AccountComponentTemplateError::StorageMapHasDuplicateKeys(Box::new(err)))
559 }
560
561 pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
566 let mut seen_keys = BTreeSet::new();
567 for entry in self.entries() {
568 entry.key().validate()?;
569 entry.value().validate()?;
570 if let Ok(key) = entry
571 .key()
572 .try_build_word(&InitStorageData::default(), StorageValueName::empty())
573 {
574 let key: Digest = key.into();
575 if !seen_keys.insert(key) {
576 return Err(AccountComponentTemplateError::StorageMapHasDuplicateKeys(
577 Box::from(format!("key `{key}` is duplicated")),
578 ));
579 }
580 };
581 }
582 Ok(())
583 }
584}
585
586impl From<MapRepresentation> for Vec<MapEntry> {
587 fn from(value: MapRepresentation) -> Self {
588 value.entries
589 }
590}
591
592impl Serializable for MapRepresentation {
593 fn write_into<W: ByteWriter>(&self, target: &mut W) {
594 self.entries.write_into(target);
595 target.write(&self.identifier);
596 }
597}
598
599impl Deserializable for MapRepresentation {
600 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
601 let entries = Vec::<MapEntry>::read_from(source)?;
602 let identifier = FieldIdentifier::read_from(source)?;
603 Ok(Self { entries, identifier })
604 }
605}
606
607#[derive(Debug, Clone, PartialEq, Eq)]
615pub enum MultiWordRepresentation {
616 Value {
619 identifier: FieldIdentifier,
621 values: Vec<[FeltRepresentation; 4]>,
623 },
624}
625
626impl MultiWordRepresentation {
627 pub fn num_words(&self) -> usize {
629 match self {
630 MultiWordRepresentation::Value { values, .. } => values.len(),
631 }
632 }
633
634 pub fn validate(&self) -> Result<(), AccountComponentTemplateError> {
636 match self {
637 MultiWordRepresentation::Value { values, .. } => {
638 for slot_word in values {
639 for felt_in_slot in slot_word {
640 felt_in_slot.validate()?;
641 }
642 }
643 },
644 }
645 Ok(())
646 }
647}
648
649impl Serializable for MultiWordRepresentation {
650 fn write_into<W: ByteWriter>(&self, target: &mut W) {
651 match self {
652 MultiWordRepresentation::Value { identifier, values } => {
653 target.write_u8(0u8);
654 target.write(identifier);
655 target.write(values);
656 },
657 }
658 }
659}
660impl Deserializable for MultiWordRepresentation {
661 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
662 let variant_tag = source.read_u8()?;
663 match variant_tag {
664 0 => {
665 let identifier: FieldIdentifier = source.read()?;
666 let values: Vec<[FeltRepresentation; 4]> = source.read()?;
667 Ok(MultiWordRepresentation::Value { identifier, values })
668 },
669 _ => Err(DeserializationError::InvalidValue(format!(
670 "unknown variant tag `{}` for MultiWordRepresentation",
671 variant_tag
672 ))),
673 }
674 }
675}