miden-objects 0.12.4

Core components of the Miden protocol
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
use alloc::boxed::Box;
use alloc::collections::BTreeSet;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::iter;

use super::placeholder::{PlaceholderTypeRequirement, TEMPLATE_REGISTRY, TemplateType};
use super::{
    FieldIdentifier,
    InitStorageData,
    MapEntry,
    StorageValueName,
    TemplateRequirementsIter,
};
use crate::account::StorageMap;
use crate::account::component::template::AccountComponentTemplateError;
use crate::utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
use crate::{Felt, FieldElement, Word};

// WORDS
// ================================================================================================

/// Defines how a word is represented within the component's storage description.
///
/// Each word representation can be:
/// - A template that defines a type but does not carry a value.
/// - A predefined value that may contain a hardcoded word or a mix of fixed and templated felts.
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)]
pub enum WordRepresentation {
    /// A templated value that serves as a placeholder for instantiation.
    ///
    /// This variant defines a type but does not store a value. The actual value is provided at the
    /// time of instantiation. The name is required to identify this template externally.
    Template {
        /// The type associated with this templated word.
        r#type: TemplateType,
        identifier: FieldIdentifier,
    },

    /// A predefined value that can be used directly within storage.
    ///
    /// This variant may contain either a fully hardcoded word or a structured set of felts, some
    /// of which may themselves be templates.
    Value {
        identifier: Option<FieldIdentifier>,
        /// The 4-felt representation of the stored word.
        value: [FeltRepresentation; 4],
    },
}

impl WordRepresentation {
    /// Constructs a new `Template` variant.
    pub fn new_template(r#type: TemplateType, identifier: FieldIdentifier) -> Self {
        WordRepresentation::Template { r#type, identifier }
    }

    /// Constructs a new `Value` variant.
    pub fn new_value(
        value: impl Into<[FeltRepresentation; 4]>,
        identifier: Option<FieldIdentifier>,
    ) -> Self {
        WordRepresentation::Value { identifier, value: value.into() }
    }

    /// Sets the description of the [`WordRepresentation`] and returns `self`.
    pub fn with_description(self, description: impl Into<String>) -> Self {
        match self {
            WordRepresentation::Template { r#type, identifier } => WordRepresentation::Template {
                r#type,
                identifier: FieldIdentifier {
                    name: identifier.name,
                    description: Some(description.into()),
                },
            },
            WordRepresentation::Value { identifier, value } => WordRepresentation::Value {
                identifier: identifier.map(|id| FieldIdentifier {
                    name: id.name,
                    description: Some(description.into()),
                }),
                value,
            },
        }
    }

    /// Returns the name associated with the word representation.
    /// - For the `Template` variant, it always returns a reference to the name.
    /// - For the `Value` variant, it returns `Some` if a name is present, or `None` otherwise.
    pub fn name(&self) -> Option<&StorageValueName> {
        match self {
            WordRepresentation::Template { identifier, .. } => Some(&identifier.name),
            WordRepresentation::Value { identifier, .. } => identifier.as_ref().map(|id| &id.name),
        }
    }

    /// Returns the description associated with the word representation.
    /// Both variants store an `Option<String>`, which is converted to an `Option<&str>`.
    pub fn description(&self) -> Option<&str> {
        match self {
            WordRepresentation::Template { identifier, .. } => identifier.description.as_deref(),
            WordRepresentation::Value { identifier, .. } => {
                identifier.as_ref().and_then(|id| id.description.as_deref())
            },
        }
    }

    /// Returns the type name.
    pub fn word_type(&self) -> TemplateType {
        match self {
            WordRepresentation::Template { r#type, .. } => r#type.clone(),
            WordRepresentation::Value { .. } => TemplateType::native_word(),
        }
    }

    /// Returns the value (an array of 4 `FeltRepresentation`s) if this is a `Value`
    /// variant; otherwise, returns `None`.
    pub fn value(&self) -> Option<&[FeltRepresentation; 4]> {
        match self {
            WordRepresentation::Value { value, .. } => Some(value),
            WordRepresentation::Template { .. } => None,
        }
    }

    /// Returns an iterator over the word's placeholders.
    ///
    /// For [`WordRepresentation::Value`], it corresponds to the inner iterators (since inner
    /// elements can be templated as well).
    /// For [`WordRepresentation::Template`] it returns the words's placeholder requirements
    /// as defined.
    pub fn template_requirements(
        &self,
        placeholder_prefix: StorageValueName,
    ) -> TemplateRequirementsIter<'_> {
        let placeholder_key =
            placeholder_prefix.with_suffix(self.name().unwrap_or(&StorageValueName::empty()));
        match self {
            WordRepresentation::Template { identifier, r#type } => Box::new(iter::once((
                placeholder_key,
                PlaceholderTypeRequirement {
                    description: identifier.description.clone(),
                    r#type: r#type.clone(),
                },
            ))),
            WordRepresentation::Value { value, .. } => Box::new(
                value
                    .iter()
                    .flat_map(move |felt| felt.template_requirements(placeholder_key.clone())),
            ),
        }
    }

    /// Attempts to convert the [WordRepresentation] into a [Word].
    ///
    /// If the representation is a template, the value is retrieved from
    /// `init_storage_data`, identified by its key. If any of the inner elements
    /// within the value are a template, they are retrieved in the same way.
    pub(crate) fn try_build_word(
        &self,
        init_storage_data: &InitStorageData,
        placeholder_prefix: StorageValueName,
    ) -> Result<Word, AccountComponentTemplateError> {
        match self {
            WordRepresentation::Template { identifier, r#type } => {
                let placeholder_path = placeholder_prefix.with_suffix(&identifier.name);
                let maybe_value = init_storage_data.get(&placeholder_path);
                if let Some(value) = maybe_value {
                    let parsed_value = TEMPLATE_REGISTRY
                        .try_parse_word(r#type, value)
                        .map_err(AccountComponentTemplateError::StorageValueParsingError)?;

                    Ok(parsed_value)
                } else {
                    Err(AccountComponentTemplateError::PlaceholderValueNotProvided(
                        placeholder_path,
                    ))
                }
            },
            WordRepresentation::Value { value, identifier } => {
                let mut result = [Felt::ZERO; 4];

                for (index, felt_repr) in value.iter().enumerate() {
                    let placeholder = placeholder_prefix.clone().with_suffix(
                        identifier
                            .as_ref()
                            .map(|id| &id.name)
                            .unwrap_or(&StorageValueName::empty()),
                    );
                    result[index] = felt_repr.try_build_felt(init_storage_data, placeholder)?;
                }
                // SAFETY: result is guaranteed to have all its 4 indices rewritten
                Ok(Word::from(result))
            },
        }
    }

    /// Validates that the defined type exists and all the inner felt types exist as well
    pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
        // Check that type exists in registry
        let type_exists = TEMPLATE_REGISTRY.contains_word_type(&self.word_type());
        if !type_exists {
            return Err(AccountComponentTemplateError::InvalidType(
                self.word_type().to_string(),
                "Word".into(),
            ));
        }

        if let Some(felts) = self.value() {
            for felt in felts {
                felt.validate()?;
            }
        }

        Ok(())
    }
}

impl Serializable for WordRepresentation {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        match self {
            WordRepresentation::Template { identifier, r#type } => {
                target.write_u8(0);
                target.write(identifier);
                target.write(r#type);
            },
            WordRepresentation::Value { identifier, value } => {
                target.write_u8(1);
                target.write(identifier);
                target.write(value);
            },
        }
    }
}

impl Deserializable for WordRepresentation {
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
        let tag = source.read_u8()?;
        match tag {
            0 => {
                let identifier = FieldIdentifier::read_from(source)?;
                let r#type = TemplateType::read_from(source)?;
                Ok(WordRepresentation::Template { identifier, r#type })
            },
            1 => {
                let identifier = Option::<FieldIdentifier>::read_from(source)?;
                let value = <[FeltRepresentation; 4]>::read_from(source)?;
                Ok(WordRepresentation::Value { identifier, value })
            },
            other => Err(DeserializationError::InvalidValue(format!(
                "unknown tag '{other}' for WordRepresentation"
            ))),
        }
    }
}

impl From<[FeltRepresentation; 4]> for WordRepresentation {
    fn from(value: [FeltRepresentation; 4]) -> Self {
        WordRepresentation::new_value(value, Option::<FieldIdentifier>::None)
    }
}

impl From<[Felt; 4]> for WordRepresentation {
    fn from(value: [Felt; 4]) -> Self {
        WordRepresentation::new_value(
            value.map(FeltRepresentation::from),
            Option::<FieldIdentifier>::None,
        )
    }
}

// FELTS
// ================================================================================================

/// Supported element representations for a component's storage entries.
///
/// Each felt element in a storage entry can either be:
/// - A concrete value that holds a predefined felt.
/// - A template that specifies the type of felt expected, with the actual value to be provided
///   later.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FeltRepresentation {
    /// A concrete felt value.
    ///
    /// This variant holds a felt that is part of the component's storage.
    /// The optional name allows for identification, and the description offers additional context.
    Value {
        /// An optional identifier for this felt value.
        /// An optional explanation of the felt's purpose.
        identifier: Option<FieldIdentifier>,
        /// The actual felt value.
        value: Felt,
    },

    /// A templated felt element.
    ///
    /// This variant specifies the expected type of the felt without providing a concrete value.
    /// The name is required to uniquely identify the template, and an optional description can
    /// further clarify its intended use.
    Template {
        /// The expected type for this felt element.
        r#type: TemplateType,
        /// A unique name for the felt template.
        /// An optional description that explains the purpose of this template.
        identifier: FieldIdentifier,
    },
}

impl FeltRepresentation {
    /// Creates a new [`FeltRepresentation::Value`] variant.
    pub fn new_value(value: impl Into<Felt>, name: Option<StorageValueName>) -> Self {
        FeltRepresentation::Value {
            value: value.into(),
            identifier: name.map(FieldIdentifier::with_name),
        }
    }

    /// Creates a new [`FeltRepresentation::Template`] variant.
    ///
    /// The name will be used for identification at the moment of instantiating the componentn.
    pub fn new_template(r#type: TemplateType, name: StorageValueName) -> Self {
        FeltRepresentation::Template {
            r#type,
            identifier: FieldIdentifier::with_name(name),
        }
    }

    /// Sets the description of the [`FeltRepresentation`] and returns `self`.
    pub fn with_description(self, description: impl Into<String>) -> Self {
        match self {
            FeltRepresentation::Template { r#type, identifier } => FeltRepresentation::Template {
                r#type,
                identifier: FieldIdentifier {
                    name: identifier.name,
                    description: Some(description.into()),
                },
            },
            FeltRepresentation::Value { identifier, value } => FeltRepresentation::Value {
                identifier: identifier.map(|id| FieldIdentifier {
                    name: id.name,
                    description: Some(description.into()),
                }),
                value,
            },
        }
    }

    /// Returns the felt type.
    pub fn felt_type(&self) -> TemplateType {
        match self {
            FeltRepresentation::Template { r#type, .. } => r#type.clone(),
            FeltRepresentation::Value { .. } => TemplateType::native_felt(),
        }
    }

    /// Attempts to convert the [FeltRepresentation] into a [Felt].
    ///
    /// If the representation is a template, the value is retrieved from `init_storage_data`,
    /// identified by its key. Otherwise, the returned value is just the inner element.
    pub(crate) fn try_build_felt(
        &self,
        init_storage_data: &InitStorageData,
        placeholder_prefix: StorageValueName,
    ) -> Result<Felt, AccountComponentTemplateError> {
        match self {
            FeltRepresentation::Template { identifier, r#type } => {
                let placeholder_key = placeholder_prefix.with_suffix(&identifier.name);
                let raw_value = init_storage_data.get(&placeholder_key).ok_or(
                    AccountComponentTemplateError::PlaceholderValueNotProvided(placeholder_key),
                )?;

                Ok(TEMPLATE_REGISTRY
                    .try_parse_felt(r#type, raw_value)
                    .map_err(AccountComponentTemplateError::StorageValueParsingError)?)
            },
            FeltRepresentation::Value { value, .. } => Ok(*value),
        }
    }

    /// Returns an iterator over the felt's template.
    ///
    /// For [`FeltRepresentation::Value`], these is an empty set; for
    /// [`FeltRepresentation::Template`] it returns the felt's placeholder key based on the
    /// felt's name within the component description.
    pub fn template_requirements(
        &self,
        placeholder_prefix: StorageValueName,
    ) -> TemplateRequirementsIter<'_> {
        match self {
            FeltRepresentation::Template { identifier, r#type } => Box::new(iter::once((
                placeholder_prefix.with_suffix(&identifier.name),
                PlaceholderTypeRequirement {
                    description: identifier.description.clone(),
                    r#type: r#type.clone(),
                },
            ))),
            _ => Box::new(iter::empty()),
        }
    }

    /// Validates that the defined Felt type exists
    pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
        // Check that type exists in registry
        let type_exists = TEMPLATE_REGISTRY.contains_felt_type(&self.felt_type());
        if !type_exists {
            return Err(AccountComponentTemplateError::InvalidType(
                self.felt_type().to_string(),
                "Felt".into(),
            ));
        }
        Ok(())
    }
}

impl From<Felt> for FeltRepresentation {
    fn from(value: Felt) -> Self {
        FeltRepresentation::new_value(value, Option::<StorageValueName>::None)
    }
}

impl Default for FeltRepresentation {
    fn default() -> Self {
        FeltRepresentation::new_value(Felt::default(), Option::<StorageValueName>::None)
    }
}

impl Serializable for FeltRepresentation {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        match self {
            FeltRepresentation::Value { identifier, value } => {
                target.write_u8(0);
                target.write(identifier);
                target.write(value);
            },
            FeltRepresentation::Template { identifier, r#type } => {
                target.write_u8(1);
                target.write(identifier);
                target.write(r#type);
            },
        }
    }
}

impl Deserializable for FeltRepresentation {
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
        let tag = source.read_u8()?;
        match tag {
            0 => {
                let identifier = Option::<FieldIdentifier>::read_from(source)?;
                let value = Felt::read_from(source)?;
                Ok(FeltRepresentation::Value { value, identifier })
            },
            1 => {
                let identifier = FieldIdentifier::read_from(source)?;
                let r#type = TemplateType::read_from(source)?;
                Ok(FeltRepresentation::Template { r#type, identifier })
            },
            other => Err(DeserializationError::InvalidValue(format!(
                "unknown tag '{other}' for FeltRepresentation"
            ))),
        }
    }
}

// MAP REPRESENTATION
// ================================================================================================

/// Supported map representations for a component's storage entries.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(::serde::Deserialize, ::serde::Serialize))]
pub enum MapRepresentation {
    /// A map whose contents are provided during instantiation via placeholders.
    Template {
        /// The human-readable identifier of the map slot.
        identifier: FieldIdentifier,
    },
    /// A map with statically defined key/value pairs.
    Value {
        /// The human-readable identifier of the map slot.
        identifier: FieldIdentifier,
        /// Storage map entries, consisting of a list of keys associated with their values.
        entries: Vec<MapEntry>,
    },
}

impl MapRepresentation {
    /// Creates a new `MapRepresentation` from a vector of map entries.
    pub fn new_value(entries: Vec<MapEntry>, name: impl Into<StorageValueName>) -> Self {
        MapRepresentation::Value {
            entries,
            identifier: FieldIdentifier::with_name(name.into()),
        }
    }

    /// Creates a new templated map representation.
    pub fn new_template(name: impl Into<StorageValueName>) -> Self {
        MapRepresentation::Template {
            identifier: FieldIdentifier::with_name(name.into()),
        }
    }

    /// Sets the description of the [`MapRepresentation`] and returns `self`.
    pub fn with_description(self, description: impl Into<String>) -> Self {
        match self {
            MapRepresentation::Template { identifier } => MapRepresentation::Template {
                identifier: FieldIdentifier {
                    name: identifier.name,
                    description: Some(description.into()),
                },
            },
            MapRepresentation::Value { identifier, entries } => MapRepresentation::Value {
                entries,
                identifier: FieldIdentifier {
                    name: identifier.name,
                    description: Some(description.into()),
                },
            },
        }
    }

    /// Returns an iterator over all of the storage entries' placeholder keys, alongside their
    /// expected type.
    pub fn template_requirements(&self) -> TemplateRequirementsIter<'_> {
        match self {
            MapRepresentation::Template { identifier } => Box::new(iter::once((
                identifier.name.clone(),
                PlaceholderTypeRequirement {
                    description: identifier.description.clone(),
                    r#type: TemplateType::storage_map(),
                },
            ))),
            MapRepresentation::Value { identifier, entries } => Box::new(
                entries
                    .iter()
                    .flat_map(move |entry| entry.template_requirements(identifier.name.clone())),
            ),
        }
    }

    /// Returns a reference to map entries.
    pub fn entries(&self) -> &[MapEntry] {
        match self {
            MapRepresentation::Value { entries, .. } => entries,
            MapRepresentation::Template { .. } => &[],
        }
    }

    /// Returns a reference to the map's name within the storage metadata.
    pub fn name(&self) -> &StorageValueName {
        match self {
            MapRepresentation::Template { identifier }
            | MapRepresentation::Value { identifier, .. } => &identifier.name,
        }
    }

    /// Returns a reference to the field's description.
    pub fn description(&self) -> Option<&String> {
        match self {
            MapRepresentation::Template { identifier }
            | MapRepresentation::Value { identifier, .. } => identifier.description.as_ref(),
        }
    }

    /// Returns the number of statically defined key-value pairs in the map.
    pub fn len(&self) -> usize {
        match self {
            MapRepresentation::Value { entries, .. } => entries.len(),
            MapRepresentation::Template { .. } => 0,
        }
    }

    /// Returns `true` if there are no statically defined entries in the map.
    pub fn is_empty(&self) -> bool {
        match self {
            MapRepresentation::Value { entries, .. } => entries.is_empty(),
            MapRepresentation::Template { .. } => true,
        }
    }

    /// Attempts to convert the [MapRepresentation] into a [StorageMap].
    ///
    /// If any of the inner elements are templates, their values are retrieved from
    /// `init_storage_data`, identified by their key.
    pub fn try_build_map(
        &self,
        init_storage_data: &InitStorageData,
    ) -> Result<StorageMap, AccountComponentTemplateError> {
        match self {
            MapRepresentation::Value { identifier, entries } => {
                let entries = entries
                    .iter()
                    .map(|map_entry| {
                        let key = map_entry
                            .key()
                            .try_build_word(init_storage_data, identifier.name.clone())?;
                        let value = map_entry
                            .value()
                            .try_build_word(init_storage_data, identifier.name.clone())?;
                        Ok((key, value))
                    })
                    .collect::<Result<Vec<(Word, Word)>, _>>()?;

                StorageMap::with_entries(entries).map_err(|err| {
                    AccountComponentTemplateError::StorageMapHasDuplicateKeys(Box::new(err))
                })
            },
            MapRepresentation::Template { identifier } => {
                if let Some(entries) = init_storage_data.map_entries(&identifier.name) {
                    return StorageMap::with_entries(entries.clone()).map_err(|err| {
                        AccountComponentTemplateError::StorageMapHasDuplicateKeys(Box::new(err))
                    });
                }

                Err(AccountComponentTemplateError::PlaceholderValueNotProvided(
                    identifier.name.clone(),
                ))
            },
        }
    }

    /// Validates the map representation by checking for duplicate keys and placeholder validity.
    pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
        match self {
            MapRepresentation::Template { .. } => Ok(()),
            MapRepresentation::Value { entries, .. } => {
                let mut seen_keys = BTreeSet::new();
                for entry in entries.iter() {
                    entry.key().validate()?;
                    entry.value().validate()?;
                    if let Ok(key) = entry
                        .key()
                        .try_build_word(&InitStorageData::default(), StorageValueName::empty())
                        && !seen_keys.insert(key)
                    {
                        return Err(AccountComponentTemplateError::StorageMapHasDuplicateKeys(
                            Box::from(format!("key `{key}` is duplicated")),
                        ));
                    }
                }

                Ok(())
            },
        }
    }
}

impl Serializable for MapRepresentation {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        match self {
            MapRepresentation::Value { identifier, entries } => {
                target.write_u8(0u8);
                target.write(identifier);
                target.write(entries);
            },
            MapRepresentation::Template { identifier } => {
                target.write_u8(1u8);
                target.write(identifier);
            },
        }
    }
}

impl Deserializable for MapRepresentation {
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
        let tag = source.read_u8()?;
        match tag {
            0 => {
                let identifier = FieldIdentifier::read_from(source)?;
                let entries = Vec::<MapEntry>::read_from(source)?;
                Ok(MapRepresentation::Value { entries, identifier })
            },
            1 => {
                let identifier = FieldIdentifier::read_from(source)?;
                Ok(MapRepresentation::Template { identifier })
            },
            other => Err(DeserializationError::InvalidValue(format!(
                "unknown tag '{other}' for MapRepresentation"
            ))),
        }
    }
}

// MULTI-WORD VALUE
// ================================================================================================

/// Defines how multi-slot values are represented within the component's storage description.
///
/// Each multi-word value representation can be:
/// - A predefined value that may contain a hardcoded word or a mix of fixed and templated felts.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MultiWordRepresentation {
    // TODO: Once there are multi-slot template types, add a MultiWordRepresentation::Template
    // here
    Value {
        /// The human-readable name of this multi-slot entry.
        identifier: FieldIdentifier,
        /// A list of values to fill the logical slot, with a length equal to the number of slots.
        values: Vec<[FeltRepresentation; 4]>,
    },
}

impl MultiWordRepresentation {
    /// Returns the number of words in this representation.
    pub fn num_words(&self) -> usize {
        match self {
            MultiWordRepresentation::Value { values, .. } => values.len(),
        }
    }

    /// Validates the multi-slot value.
    pub fn validate(&self) -> Result<(), AccountComponentTemplateError> {
        match self {
            MultiWordRepresentation::Value { values, .. } => {
                for slot_word in values {
                    for felt_in_slot in slot_word {
                        felt_in_slot.validate()?;
                    }
                }
            },
        }
        Ok(())
    }
}

impl Serializable for MultiWordRepresentation {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        match self {
            MultiWordRepresentation::Value { identifier, values } => {
                target.write_u8(0u8);
                target.write(identifier);
                target.write(values);
            },
        }
    }
}
impl Deserializable for MultiWordRepresentation {
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
        let variant_tag = source.read_u8()?;
        match variant_tag {
            0 => {
                let identifier: FieldIdentifier = source.read()?;
                let values: Vec<[FeltRepresentation; 4]> = source.read()?;
                Ok(MultiWordRepresentation::Value { identifier, values })
            },
            _ => Err(DeserializationError::InvalidValue(format!(
                "unknown variant tag '{variant_tag}' for MultiWordRepresentation"
            ))),
        }
    }
}