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