miden_core/mast/
mod.rs

1use alloc::{
2    collections::{BTreeMap, BTreeSet},
3    sync::Arc,
4    vec::Vec,
5};
6use core::{
7    fmt,
8    ops::{Index, IndexMut},
9};
10
11pub use miden_utils_indexing::{IndexVec, IndexedVecError};
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15mod node;
16#[cfg(any(test, feature = "arbitrary"))]
17pub use node::arbitrary;
18pub use node::{
19    BasicBlockNode, BasicBlockNodeBuilder, CallNode, CallNodeBuilder, DecoratedOpLink,
20    DecoratorOpLinkIterator, DecoratorStore, DynNode, DynNodeBuilder, ExternalNode,
21    ExternalNodeBuilder, JoinNode, JoinNodeBuilder, LoopNode, LoopNodeBuilder,
22    MastForestContributor, MastNode, MastNodeBuilder, MastNodeErrorContext, MastNodeExt,
23    OP_BATCH_SIZE, OP_GROUP_SIZE, OpBatch, OperationOrDecorator, SplitNode, SplitNodeBuilder,
24};
25
26use crate::{
27    AdviceMap, Decorator, Felt, Idx, LexicographicWord, Word,
28    crypto::hash::Hasher,
29    utils::{ByteWriter, DeserializationError, Serializable, hash_string_to_word},
30};
31
32mod debuginfo;
33pub use debuginfo::{
34    DebugInfo, DecoratedLinks, DecoratedLinksIter, DecoratorIndexError, NodeToDecoratorIds,
35    OpToDecoratorIds,
36};
37
38mod serialization;
39
40mod merger;
41pub(crate) use merger::MastForestMerger;
42pub use merger::MastForestRootMap;
43
44mod multi_forest_node_iterator;
45pub(crate) use multi_forest_node_iterator::*;
46
47mod node_fingerprint;
48pub use node_fingerprint::{DecoratorFingerprint, MastNodeFingerprint};
49
50#[cfg(test)]
51mod tests;
52
53// MAST FOREST
54// ================================================================================================
55
56/// Represents one or more procedures, represented as a collection of [`MastNode`]s.
57///
58/// A [`MastForest`] does not have an entrypoint, and hence is not executable. A [`crate::Program`]
59/// can be built from a [`MastForest`] to specify an entrypoint.
60#[derive(Clone, Debug, Default, PartialEq, Eq)]
61pub struct MastForest {
62    /// All of the nodes local to the trees comprising the MAST forest.
63    nodes: IndexVec<MastNodeId, MastNode>,
64
65    /// Roots of procedures defined within this MAST forest.
66    roots: Vec<MastNodeId>,
67
68    /// Advice map to be loaded into the VM prior to executing procedures from this MAST forest.
69    advice_map: AdviceMap,
70
71    /// Debug information including decorators and error codes.
72    /// Always present (as per issue #1821), but can be empty for stripped builds.
73    debug_info: DebugInfo,
74}
75
76// ------------------------------------------------------------------------------------------------
77/// Constructors
78impl MastForest {
79    /// Creates a new empty [`MastForest`].
80    pub fn new() -> Self {
81        Self {
82            nodes: IndexVec::new(),
83            roots: Vec::new(),
84            advice_map: AdviceMap::default(),
85            debug_info: DebugInfo::new(),
86        }
87    }
88}
89
90// ------------------------------------------------------------------------------------------------
91/// State mutators
92impl MastForest {
93    /// The maximum number of nodes that can be stored in a single MAST forest.
94    const MAX_NODES: usize = (1 << 30) - 1;
95
96    /// Marks the given [`MastNodeId`] as being the root of a procedure.
97    ///
98    /// If the specified node is already marked as a root, this will have no effect.
99    ///
100    /// # Panics
101    /// - if `new_root_id`'s internal index is larger than the number of nodes in this forest (i.e.
102    ///   clearly doesn't belong to this MAST forest).
103    pub fn make_root(&mut self, new_root_id: MastNodeId) {
104        assert!(new_root_id.to_usize() < self.nodes.len());
105
106        if !self.roots.contains(&new_root_id) {
107            self.roots.push(new_root_id);
108        }
109    }
110
111    /// Removes all nodes in the provided set from the MAST forest. The nodes MUST be orphaned (i.e.
112    /// have no parent). Otherwise, this parent's reference is considered "dangling" after the
113    /// removal (i.e. will point to an incorrect node after the removal), and this removal operation
114    /// would result in an invalid [`MastForest`].
115    ///
116    /// It also returns the map from old node IDs to new node IDs. Any [`MastNodeId`] used in
117    /// reference to the old [`MastForest`] should be remapped using this map.
118    pub fn remove_nodes(
119        &mut self,
120        nodes_to_remove: &BTreeSet<MastNodeId>,
121    ) -> BTreeMap<MastNodeId, MastNodeId> {
122        if nodes_to_remove.is_empty() {
123            return BTreeMap::new();
124        }
125
126        let old_nodes = core::mem::replace(&mut self.nodes, IndexVec::new());
127        let old_root_ids = core::mem::take(&mut self.roots);
128        let (retained_nodes, id_remappings) = remove_nodes(old_nodes.into_inner(), nodes_to_remove);
129
130        self.remap_and_add_nodes(retained_nodes, &id_remappings);
131        self.remap_and_add_roots(old_root_ids, &id_remappings);
132        id_remappings
133    }
134
135    /// Removes all decorators from this MAST forest.
136    ///
137    /// This method modifies the forest in-place, removing all decorator information
138    /// including operation-indexed decorators, before-enter decorators, after-exit
139    /// decorators, and error codes.
140    ///
141    /// # Examples
142    ///
143    /// ```rust
144    /// use miden_core::mast::MastForest;
145    ///
146    /// let mut forest = MastForest::new();
147    /// // Add decorators and nodes to the forest
148    /// forest.strip_decorators(); // forest is now stripped
149    /// ```
150    pub fn strip_decorators(&mut self) {
151        // Clear all debug info (decorators and error codes)
152        self.debug_info.clear();
153    }
154
155    /// Compacts the forest by merging duplicate nodes.
156    ///
157    /// This operation performs node deduplication by merging the forest with itself.
158    /// The method assumes that decorators have already been stripped if that is desired.
159    /// The operation modifies the forest in-place, updating all node references as needed.
160    ///
161    /// The process works by:
162    /// 1. Merging the forest with itself to deduplicate identical nodes
163    /// 2. Updating internal node references and remappings
164    /// 3. Modifying the forest in-place with the compacted result
165    ///
166    /// # Examples
167    ///
168    /// ```rust
169    /// use miden_core::mast::MastForest;
170    ///
171    /// let mut forest = MastForest::new();
172    /// // Add nodes to the forest
173    ///
174    /// // First strip decorators if needed
175    /// forest.strip_decorators();
176    ///
177    /// // Then compact the forest
178    /// let root_map = forest.compact();
179    ///
180    /// // Forest is now compacted with duplicate nodes merged
181    /// ```
182    pub fn compact(&mut self) -> MastForestRootMap {
183        // Merge with itself to deduplicate nodes
184        // Note: This cannot fail for a self-merge under normal conditions.
185        // The only possible failures (TooManyNodes, TooManyDecorators) would require the
186        // original forest to be at capacity limits, at which point compaction wouldn't help.
187        let (compacted_forest, root_map) = MastForest::merge([&*self])
188            .expect("Failed to compact MastForest: this should never happen during self-merge");
189
190        // Replace current forest with compacted version
191        *self = compacted_forest;
192
193        root_map
194    }
195
196    /// Merges all `forests` into a new [`MastForest`].
197    ///
198    /// Merging two forests means combining all their constituent parts, i.e. [`MastNode`]s,
199    /// [`Decorator`]s and roots. During this process, any duplicate or
200    /// unreachable nodes are removed. Additionally, [`MastNodeId`]s of nodes as well as
201    /// [`DecoratorId`]s of decorators may change and references to them are remapped to their new
202    /// location.
203    ///
204    /// For example, consider this representation of a forest's nodes with all of these nodes being
205    /// roots:
206    ///
207    /// ```text
208    /// [Block(foo), Block(bar)]
209    /// ```
210    ///
211    /// If we merge another forest into it:
212    ///
213    /// ```text
214    /// [Block(bar), Call(0)]
215    /// ```
216    ///
217    /// then we would expect this forest:
218    ///
219    /// ```text
220    /// [Block(foo), Block(bar), Call(1)]
221    /// ```
222    ///
223    /// - The `Call` to the `bar` block was remapped to its new index (now 1, previously 0).
224    /// - The `Block(bar)` was deduplicated any only exists once in the merged forest.
225    ///
226    /// The function also returns a vector of [`MastForestRootMap`]s, whose length equals the number
227    /// of passed `forests`. The indices in the vector correspond to the ones in `forests`. The map
228    /// of a given forest contains the new locations of its roots in the merged forest. To
229    /// illustrate, the above example would return a vector of two maps:
230    ///
231    /// ```text
232    /// vec![{0 -> 0, 1 -> 1}
233    ///      {0 -> 1, 1 -> 2}]
234    /// ```
235    ///
236    /// - The root locations of the original forest are unchanged.
237    /// - For the second forest, the `bar` block has moved from index 0 to index 1 in the merged
238    ///   forest, and the `Call` has moved from index 1 to 2.
239    ///
240    /// If any forest being merged contains an `External(qux)` node and another forest contains a
241    /// node whose digest is `qux`, then the external node will be replaced with the `qux` node,
242    /// which is effectively deduplication. Decorators are ignored when it comes to merging
243    /// External nodes. This means that an External node with decorators may be replaced by a node
244    /// without decorators or vice versa.
245    pub fn merge<'forest>(
246        forests: impl IntoIterator<Item = &'forest MastForest>,
247    ) -> Result<(MastForest, MastForestRootMap), MastForestError> {
248        MastForestMerger::merge(forests)
249    }
250}
251
252// ------------------------------------------------------------------------------------------------
253/// Helpers
254impl MastForest {
255    /// Adds all provided nodes to the internal set of nodes, remapping all [`MastNodeId`]
256    /// references in those nodes.
257    ///
258    /// # Panics
259    /// - Panics if the internal set of nodes is not empty.
260    fn remap_and_add_nodes(
261        &mut self,
262        nodes_to_add: Vec<MastNode>,
263        id_remappings: &BTreeMap<MastNodeId, MastNodeId>,
264    ) {
265        assert!(self.nodes.is_empty());
266        // extract decorator information from the nodes by converting them into builders
267        let node_builders =
268            nodes_to_add.into_iter().map(|node| node.to_builder(self)).collect::<Vec<_>>();
269
270        // Clear decorator storage after extracting builders (builders contain decorator data)
271        self.debug_info.clear_mappings();
272
273        // Add each node to the new MAST forest, making sure to rewrite any outdated internal
274        // `MastNodeId`s
275        for live_node_builder in node_builders {
276            live_node_builder.remap_children(id_remappings).add_to_forest(self).unwrap();
277        }
278    }
279
280    /// Remaps and adds all old root ids to the internal set of roots.
281    ///
282    /// # Panics
283    /// - Panics if the internal set of roots is not empty.
284    fn remap_and_add_roots(
285        &mut self,
286        old_root_ids: Vec<MastNodeId>,
287        id_remappings: &BTreeMap<MastNodeId, MastNodeId>,
288    ) {
289        assert!(self.roots.is_empty());
290
291        for old_root_id in old_root_ids {
292            let new_root_id = id_remappings.get(&old_root_id).copied().unwrap_or(old_root_id);
293            self.make_root(new_root_id);
294        }
295    }
296}
297
298/// Returns the set of nodes that are live, as well as the mapping from "old ID" to "new ID" for all
299/// live nodes.
300fn remove_nodes(
301    mast_nodes: Vec<MastNode>,
302    nodes_to_remove: &BTreeSet<MastNodeId>,
303) -> (Vec<MastNode>, BTreeMap<MastNodeId, MastNodeId>) {
304    // Note: this allows us to safely use `usize as u32`, guaranteeing that it won't wrap around.
305    assert!(mast_nodes.len() < u32::MAX as usize);
306
307    let mut retained_nodes = Vec::with_capacity(mast_nodes.len());
308    let mut id_remappings = BTreeMap::new();
309
310    for (old_node_index, old_node) in mast_nodes.into_iter().enumerate() {
311        let old_node_id: MastNodeId = MastNodeId(old_node_index as u32);
312
313        if !nodes_to_remove.contains(&old_node_id) {
314            let new_node_id: MastNodeId = MastNodeId(retained_nodes.len() as u32);
315            id_remappings.insert(old_node_id, new_node_id);
316
317            retained_nodes.push(old_node);
318        }
319    }
320
321    (retained_nodes, id_remappings)
322}
323
324// ------------------------------------------------------------------------------------------------
325/// Public accessors
326impl MastForest {
327    /// Returns the [`MastNode`] associated with the provided [`MastNodeId`] if valid, or else
328    /// `None`.
329    ///
330    /// This is the fallible version of indexing (e.g. `mast_forest[node_id]`).
331    #[inline(always)]
332    pub fn get_node_by_id(&self, node_id: MastNodeId) -> Option<&MastNode> {
333        self.nodes.get(node_id)
334    }
335
336    /// Returns the [`MastNodeId`] of the procedure associated with a given digest, if any.
337    #[inline(always)]
338    pub fn find_procedure_root(&self, digest: Word) -> Option<MastNodeId> {
339        self.roots.iter().find(|&&root_id| self[root_id].digest() == digest).copied()
340    }
341
342    /// Returns true if a node with the specified ID is a root of a procedure in this MAST forest.
343    pub fn is_procedure_root(&self, node_id: MastNodeId) -> bool {
344        self.roots.contains(&node_id)
345    }
346
347    /// Returns an iterator over the digests of all procedures in this MAST forest.
348    pub fn procedure_digests(&self) -> impl Iterator<Item = Word> + '_ {
349        self.roots.iter().map(|&root_id| self[root_id].digest())
350    }
351
352    /// Returns an iterator over the digests of local procedures in this MAST forest.
353    ///
354    /// A local procedure is defined as a procedure which is not a single external node.
355    pub fn local_procedure_digests(&self) -> impl Iterator<Item = Word> + '_ {
356        self.roots.iter().filter_map(|&root_id| {
357            let node = &self[root_id];
358            if node.is_external() { None } else { Some(node.digest()) }
359        })
360    }
361
362    /// Returns an iterator over the IDs of the procedures in this MAST forest.
363    pub fn procedure_roots(&self) -> &[MastNodeId] {
364        &self.roots
365    }
366
367    /// Returns the number of procedures in this MAST forest.
368    pub fn num_procedures(&self) -> u32 {
369        self.roots
370            .len()
371            .try_into()
372            .expect("MAST forest contains more than 2^32 procedures.")
373    }
374
375    /// Returns the [Word] representing the content hash of a subset of [`MastNodeId`]s.
376    ///
377    /// # Panics
378    /// This function panics if any `node_ids` is not a node of this forest.
379    pub fn compute_nodes_commitment<'a>(
380        &self,
381        node_ids: impl IntoIterator<Item = &'a MastNodeId>,
382    ) -> Word {
383        let mut digests: Vec<Word> = node_ids.into_iter().map(|&id| self[id].digest()).collect();
384        digests.sort_unstable_by_key(|word| LexicographicWord::from(*word));
385        miden_crypto::hash::rpo::Rpo256::merge_many(&digests)
386    }
387
388    /// Returns the number of nodes in this MAST forest.
389    pub fn num_nodes(&self) -> u32 {
390        self.nodes.len() as u32
391    }
392
393    /// Returns the underlying nodes in this MAST forest.
394    pub fn nodes(&self) -> &[MastNode] {
395        self.nodes.as_slice()
396    }
397
398    pub fn advice_map(&self) -> &AdviceMap {
399        &self.advice_map
400    }
401
402    pub fn advice_map_mut(&mut self) -> &mut AdviceMap {
403        &mut self.advice_map
404    }
405}
406
407// ------------------------------------------------------------------------------------------------
408/// Decorator methods
409impl MastForest {
410    /// Returns a list of all decorators contained in this [MastForest].
411    pub fn decorators(&self) -> &[Decorator] {
412        self.debug_info.decorators()
413    }
414
415    /// Returns the [`Decorator`] associated with the provided [`DecoratorId`] if valid, or else
416    /// `None`.
417    ///
418    /// This is the fallible version of indexing (e.g. `mast_forest[decorator_id]`).
419    #[inline]
420    pub fn decorator_by_id(&self, decorator_id: DecoratorId) -> Option<&Decorator> {
421        self.debug_info.decorator(decorator_id)
422    }
423
424    /// Returns decorator indices for a specific operation within a node.
425    ///
426    /// This is the primary accessor for reading decorators from the centralized storage.
427    /// Returns a slice of decorator IDs for the given operation.
428    #[inline]
429    pub(crate) fn decorator_indices_for_op(
430        &self,
431        node_id: MastNodeId,
432        local_op_idx: usize,
433    ) -> &[DecoratorId] {
434        self.debug_info.decorators_for_operation(node_id, local_op_idx)
435    }
436
437    /// Returns an iterator over decorator references for a specific operation within a node.
438    ///
439    /// This is the preferred method for accessing decorators, as it provides direct
440    /// references to the decorator objects.
441    #[inline]
442    pub fn decorators_for_op<'a>(
443        &'a self,
444        node_id: MastNodeId,
445        local_op_idx: usize,
446    ) -> impl Iterator<Item = &'a Decorator> + 'a {
447        self.decorator_indices_for_op(node_id, local_op_idx)
448            .iter()
449            .map(move |&decorator_id| &self[decorator_id])
450    }
451
452    /// Returns the decorators to be executed before this node is executed.
453    #[inline]
454    pub fn before_enter_decorators(&self, node_id: MastNodeId) -> &[DecoratorId] {
455        self.debug_info.before_enter_decorators(node_id)
456    }
457
458    /// Returns the decorators to be executed after this node is executed.
459    #[inline]
460    pub fn after_exit_decorators(&self, node_id: MastNodeId) -> &[DecoratorId] {
461        self.debug_info.after_exit_decorators(node_id)
462    }
463
464    /// Returns decorator links for a node, including operation indices.
465    ///
466    /// This provides a flattened view of all decorators for a node with their operation indices.
467    #[inline]
468    pub(crate) fn decorator_links_for_node<'a>(
469        &'a self,
470        node_id: MastNodeId,
471    ) -> Result<DecoratedLinks<'a>, DecoratorIndexError> {
472        self.debug_info.decorator_links_for_node(node_id)
473    }
474
475    /// Adds a decorator to the forest, and returns the associated [`DecoratorId`].
476    pub fn add_decorator(&mut self, decorator: Decorator) -> Result<DecoratorId, MastForestError> {
477        self.debug_info.add_decorator(decorator)
478    }
479
480    /// Adds decorator IDs for a node to the storage.
481    ///
482    /// Used when building nodes for efficient decorator access during execution.
483    ///
484    /// # Note
485    /// This method does not validate decorator IDs immediately. Validation occurs during
486    /// operations that need to access the actual decorator data (e.g., merging, serialization).
487    #[inline]
488    pub(crate) fn register_node_decorators(
489        &mut self,
490        node_id: MastNodeId,
491        before_enter: &[DecoratorId],
492        after_exit: &[DecoratorId],
493    ) {
494        self.debug_info.register_node_decorators(node_id, before_enter, after_exit);
495    }
496}
497
498// ------------------------------------------------------------------------------------------------
499/// Error message methods
500impl MastForest {
501    /// Given an error code as a Felt, resolves it to its corresponding error message.
502    pub fn resolve_error_message(&self, code: Felt) -> Option<Arc<str>> {
503        let key = u64::from(code);
504        self.debug_info.error_message(key)
505    }
506
507    /// Registers an error message in the MAST Forest and returns the corresponding error code as a
508    /// Felt.
509    pub fn register_error(&mut self, msg: Arc<str>) -> Felt {
510        let code: Felt = error_code_from_msg(&msg);
511        // we use u64 as keys for the map
512        self.debug_info.insert_error_code(code.as_int(), msg);
513        code
514    }
515}
516
517// MAST FOREST INDEXING
518// ------------------------------------------------------------------------------------------------
519
520impl Index<MastNodeId> for MastForest {
521    type Output = MastNode;
522
523    #[inline(always)]
524    fn index(&self, node_id: MastNodeId) -> &Self::Output {
525        &self.nodes[node_id]
526    }
527}
528
529impl IndexMut<MastNodeId> for MastForest {
530    #[inline(always)]
531    fn index_mut(&mut self, node_id: MastNodeId) -> &mut Self::Output {
532        &mut self.nodes[node_id]
533    }
534}
535
536impl Index<DecoratorId> for MastForest {
537    type Output = Decorator;
538
539    #[inline(always)]
540    fn index(&self, decorator_id: DecoratorId) -> &Self::Output {
541        self.debug_info.decorator(decorator_id).expect("DecoratorId out of bounds")
542    }
543}
544
545impl IndexMut<DecoratorId> for MastForest {
546    #[inline(always)]
547    fn index_mut(&mut self, decorator_id: DecoratorId) -> &mut Self::Output {
548        self.debug_info.decorator_mut(decorator_id).expect("DecoratorId out of bounds")
549    }
550}
551
552// MAST NODE ID
553// ================================================================================================
554
555/// An opaque handle to a [`MastNode`] in some [`MastForest`]. It is the responsibility of the user
556/// to use a given [`MastNodeId`] with the corresponding [`MastForest`].
557///
558/// Note that the [`MastForest`] does *not* ensure that equal [`MastNode`]s have equal
559/// [`MastNodeId`] handles. Hence, [`MastNodeId`] equality must not be used to test for equality of
560/// the underlying [`MastNode`].
561#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
562#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
563#[cfg_attr(feature = "serde", serde(transparent))]
564#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
565pub struct MastNodeId(u32);
566
567/// Operations that mutate a MAST often produce this mapping between old and new NodeIds.
568pub type Remapping = BTreeMap<MastNodeId, MastNodeId>;
569
570impl MastNodeId {
571    /// Returns a new `MastNodeId` with the provided inner value, or an error if the provided
572    /// `value` is greater than the number of nodes in the forest.
573    ///
574    /// For use in deserialization.
575    pub fn from_u32_safe(
576        value: u32,
577        mast_forest: &MastForest,
578    ) -> Result<Self, DeserializationError> {
579        Self::from_u32_with_node_count(value, mast_forest.nodes.len())
580    }
581
582    /// Returns a new [`MastNodeId`] with the provided `node_id`, or an error if `node_id` is
583    /// greater than the number of nodes in the [`MastForest`] for which this ID is being
584    /// constructed.
585    pub fn from_usize_safe(
586        node_id: usize,
587        mast_forest: &MastForest,
588    ) -> Result<Self, DeserializationError> {
589        let node_id: u32 = node_id.try_into().map_err(|_| {
590            DeserializationError::InvalidValue(format!(
591                "node id '{node_id}' does not fit into a u32"
592            ))
593        })?;
594        MastNodeId::from_u32_safe(node_id, mast_forest)
595    }
596
597    /// Returns a new [`MastNodeId`] from the given `value` without checking its validity.
598    pub(crate) fn new_unchecked(value: u32) -> Self {
599        Self(value)
600    }
601
602    /// Returns a new [`MastNodeId`] with the provided `id`, or an error if `id` is greater or equal
603    /// to `node_count`. The `node_count` is the total number of nodes in the [`MastForest`] for
604    /// which this ID is being constructed.
605    ///
606    /// This function can be used when deserializing an id whose corresponding node is not yet in
607    /// the forest and [`Self::from_u32_safe`] would fail. For instance, when deserializing the ids
608    /// referenced by the Join node in this forest:
609    ///
610    /// ```text
611    /// [Join(1, 2), Block(foo), Block(bar)]
612    /// ```
613    ///
614    /// Since it is less safe than [`Self::from_u32_safe`] and usually not needed it is not public.
615    pub(super) fn from_u32_with_node_count(
616        id: u32,
617        node_count: usize,
618    ) -> Result<Self, DeserializationError> {
619        if (id as usize) < node_count {
620            Ok(Self(id))
621        } else {
622            Err(DeserializationError::InvalidValue(format!(
623                "Invalid deserialized MAST node ID '{id}', but {node_count} is the number of nodes in the forest",
624            )))
625        }
626    }
627
628    /// Remap the NodeId to its new position using the given [`Remapping`].
629    pub fn remap(&self, remapping: &Remapping) -> Self {
630        *remapping.get(self).unwrap_or(self)
631    }
632}
633
634impl From<u32> for MastNodeId {
635    fn from(value: u32) -> Self {
636        MastNodeId::new_unchecked(value)
637    }
638}
639
640impl Idx for MastNodeId {}
641
642impl From<MastNodeId> for u32 {
643    fn from(value: MastNodeId) -> Self {
644        value.0
645    }
646}
647
648impl fmt::Display for MastNodeId {
649    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
650        write!(f, "MastNodeId({})", self.0)
651    }
652}
653
654#[cfg(any(test, feature = "arbitrary"))]
655impl proptest::prelude::Arbitrary for MastNodeId {
656    type Parameters = ();
657
658    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
659        use proptest::prelude::*;
660        any::<u32>().prop_map(MastNodeId).boxed()
661    }
662
663    type Strategy = proptest::prelude::BoxedStrategy<Self>;
664}
665
666// ITERATOR
667
668/// Iterates over all the nodes a root depends on, in pre-order. The iteration can include other
669/// roots in the same forest.
670pub struct SubtreeIterator<'a> {
671    forest: &'a MastForest,
672    discovered: Vec<MastNodeId>,
673    unvisited: Vec<MastNodeId>,
674}
675impl<'a> SubtreeIterator<'a> {
676    pub fn new(root: &MastNodeId, forest: &'a MastForest) -> Self {
677        let discovered = vec![];
678        let unvisited = vec![*root];
679        SubtreeIterator { forest, discovered, unvisited }
680    }
681}
682impl Iterator for SubtreeIterator<'_> {
683    type Item = MastNodeId;
684    fn next(&mut self) -> Option<MastNodeId> {
685        while let Some(id) = self.unvisited.pop() {
686            let node = &self.forest[id];
687            if !node.has_children() {
688                return Some(id);
689            } else {
690                self.discovered.push(id);
691                node.append_children_to(&mut self.unvisited);
692            }
693        }
694        self.discovered.pop()
695    }
696}
697
698// DECORATOR ID
699// ================================================================================================
700
701/// An opaque handle to a [`Decorator`] in some [`MastForest`]. It is the responsibility of the user
702/// to use a given [`DecoratorId`] with the corresponding [`MastForest`].
703#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
704#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
705#[cfg_attr(feature = "serde", serde(transparent))]
706pub struct DecoratorId(u32);
707
708impl DecoratorId {
709    /// Returns a new `DecoratorId` with the provided inner value, or an error if the provided
710    /// `value` is greater than the number of nodes in the forest.
711    ///
712    /// For use in deserialization.
713    pub fn from_u32_safe(
714        value: u32,
715        mast_forest: &MastForest,
716    ) -> Result<Self, DeserializationError> {
717        Self::from_u32_bounded(value, mast_forest.debug_info.num_decorators())
718    }
719
720    /// Returns a new `DecoratorId` with the provided inner value, or an error if the provided
721    /// `value` is greater than or equal to `bound`.
722    ///
723    /// For use in deserialization when the bound is known without needing the full MastForest.
724    pub fn from_u32_bounded(value: u32, bound: usize) -> Result<Self, DeserializationError> {
725        if (value as usize) < bound {
726            Ok(Self(value))
727        } else {
728            Err(DeserializationError::InvalidValue(format!(
729                "Invalid deserialized MAST decorator id '{}', but allows only {} decorators",
730                value, bound,
731            )))
732        }
733    }
734
735    /// Creates a new [`DecoratorId`] without checking its validity.
736    pub(crate) fn new_unchecked(value: u32) -> Self {
737        Self(value)
738    }
739}
740
741impl From<u32> for DecoratorId {
742    fn from(value: u32) -> Self {
743        DecoratorId::new_unchecked(value)
744    }
745}
746
747impl Idx for DecoratorId {}
748
749impl From<DecoratorId> for u32 {
750    fn from(value: DecoratorId) -> Self {
751        value.0
752    }
753}
754
755impl fmt::Display for DecoratorId {
756    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757        write!(f, "DecoratorId({})", self.0)
758    }
759}
760
761impl Serializable for DecoratorId {
762    fn write_into<W: ByteWriter>(&self, target: &mut W) {
763        self.0.write_into(target)
764    }
765}
766
767/// Derives an error code from an error message by hashing the message and returning the 0th element
768/// of the resulting [`Word`].
769pub fn error_code_from_msg(msg: impl AsRef<str>) -> Felt {
770    // hash the message and return 0th felt of the resulting Word
771    hash_string_to_word(msg.as_ref())[0]
772}
773
774// MAST FOREST ERROR
775// ================================================================================================
776
777/// Represents the types of errors that can occur when dealing with MAST forest.
778#[derive(Debug, thiserror::Error, PartialEq)]
779pub enum MastForestError {
780    #[error("MAST forest decorator count exceeds the maximum of {} decorators", u32::MAX)]
781    TooManyDecorators,
782    #[error("MAST forest node count exceeds the maximum of {} nodes", MastForest::MAX_NODES)]
783    TooManyNodes,
784    #[error("node id {0} is greater than or equal to forest length {1}")]
785    NodeIdOverflow(MastNodeId, usize),
786    #[error("decorator id {0} is greater than or equal to decorator count {1}")]
787    DecoratorIdOverflow(DecoratorId, usize),
788    #[error("basic block cannot be created from an empty list of operations")]
789    EmptyBasicBlock,
790    #[error(
791        "decorator root of child with node id {0} is missing but is required for fingerprint computation"
792    )]
793    ChildFingerprintMissing(MastNodeId),
794    #[error("advice map key {0} already exists when merging forests")]
795    AdviceMapKeyCollisionOnMerge(Word),
796    #[error("decorator storage error: {0}")]
797    DecoratorError(DecoratorIndexError),
798    #[error("digest is required for deserialization")]
799    DigestRequiredForDeserialization,
800}
801
802// Custom serde implementations for MastForest that handle linked decorators properly
803// by delegating to the existing winter-utils serialization which already handles
804// the conversion between linked and owned decorator formats.
805#[cfg(feature = "serde")]
806impl serde::Serialize for MastForest {
807    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
808    where
809        S: serde::Serializer,
810    {
811        // Use the existing winter-utils serialization which already handles linked decorators
812        let bytes = crate::utils::Serializable::to_bytes(self);
813        serializer.serialize_bytes(&bytes)
814    }
815}
816
817#[cfg(feature = "serde")]
818impl<'de> serde::Deserialize<'de> for MastForest {
819    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
820    where
821        D: serde::Deserializer<'de>,
822    {
823        // Deserialize bytes, then use winter-utils Deserializable
824        let bytes = Vec::<u8>::deserialize(deserializer)?;
825        let mut slice_reader = winter_utils::SliceReader::new(&bytes);
826        crate::utils::Deserializable::read_from(&mut slice_reader).map_err(serde::de::Error::custom)
827    }
828}