miden_core/mast/
mod.rs

1use alloc::{
2    collections::{BTreeMap, BTreeSet},
3    sync::Arc,
4    vec::Vec,
5};
6use core::{
7    fmt, mem,
8    ops::{Index, IndexMut},
9};
10
11use miden_crypto::hash::rpo::RpoDigest;
12
13use crate::crypto::hash::{Blake3_256, Blake3Digest, Digest};
14
15mod node;
16pub use node::{
17    BasicBlockNode, CallNode, DynNode, ExternalNode, JoinNode, LoopNode, MastNode, MastNodeExt,
18    OP_BATCH_SIZE, OP_GROUP_SIZE, OpBatch, OperationOrDecorator, SplitNode,
19};
20use winter_utils::{ByteWriter, DeserializationError, Serializable};
21
22use crate::{AdviceMap, Decorator, DecoratorList, Felt, Operation};
23
24mod serialization;
25
26mod merger;
27pub(crate) use merger::MastForestMerger;
28pub use merger::MastForestRootMap;
29
30mod multi_forest_node_iterator;
31pub(crate) use multi_forest_node_iterator::*;
32
33mod node_fingerprint;
34pub use node_fingerprint::{DecoratorFingerprint, MastNodeFingerprint};
35
36#[cfg(test)]
37mod tests;
38
39// MAST FOREST
40// ================================================================================================
41
42/// Represents one or more procedures, represented as a collection of [`MastNode`]s.
43///
44/// A [`MastForest`] does not have an entrypoint, and hence is not executable. A [`crate::Program`]
45/// can be built from a [`MastForest`] to specify an entrypoint.
46#[derive(Clone, Debug, Default, PartialEq, Eq)]
47pub struct MastForest {
48    /// All of the nodes local to the trees comprising the MAST forest.
49    nodes: Vec<MastNode>,
50
51    /// Roots of procedures defined within this MAST forest.
52    roots: Vec<MastNodeId>,
53
54    /// All the decorators included in the MAST forest.
55    decorators: Vec<Decorator>,
56
57    /// Advice map to be loaded into the VM prior to executing procedures from this MAST forest.
58    advice_map: AdviceMap,
59
60    /// A map from error codes to error messages. Error messages cannot be
61    /// recovered from error codes, so they are stored in order to provide a
62    /// useful message to the user in case a error code is triggered.
63    error_codes: BTreeMap<u64, Arc<str>>,
64}
65
66// ------------------------------------------------------------------------------------------------
67/// Constructors
68impl MastForest {
69    /// Creates a new empty [`MastForest`].
70    pub fn new() -> Self {
71        Self::default()
72    }
73}
74
75// ------------------------------------------------------------------------------------------------
76/// State mutators
77impl MastForest {
78    /// The maximum number of nodes that can be stored in a single MAST forest.
79    const MAX_NODES: usize = (1 << 30) - 1;
80
81    /// Adds a decorator to the forest, and returns the associated [`DecoratorId`].
82    pub fn add_decorator(&mut self, decorator: Decorator) -> Result<DecoratorId, MastForestError> {
83        if self.decorators.len() >= u32::MAX as usize {
84            return Err(MastForestError::TooManyDecorators);
85        }
86
87        let new_decorator_id = DecoratorId(self.decorators.len() as u32);
88        self.decorators.push(decorator);
89
90        Ok(new_decorator_id)
91    }
92
93    /// Adds a node to the forest, and returns the associated [`MastNodeId`].
94    ///
95    /// Adding two duplicate nodes will result in two distinct returned [`MastNodeId`]s.
96    pub fn add_node(&mut self, node: MastNode) -> Result<MastNodeId, MastForestError> {
97        if self.nodes.len() == Self::MAX_NODES {
98            return Err(MastForestError::TooManyNodes);
99        }
100
101        let new_node_id = MastNodeId(self.nodes.len() as u32);
102        self.nodes.push(node);
103
104        Ok(new_node_id)
105    }
106
107    /// Adds a basic block node to the forest, and returns the [`MastNodeId`] associated with it.
108    pub fn add_block(
109        &mut self,
110        operations: Vec<Operation>,
111        decorators: Option<DecoratorList>,
112    ) -> Result<MastNodeId, MastForestError> {
113        let block = MastNode::new_basic_block(operations, decorators)?;
114        self.add_node(block)
115    }
116
117    /// Adds a join node to the forest, and returns the [`MastNodeId`] associated with it.
118    pub fn add_join(
119        &mut self,
120        left_child: MastNodeId,
121        right_child: MastNodeId,
122    ) -> Result<MastNodeId, MastForestError> {
123        let join = MastNode::new_join(left_child, right_child, self)?;
124        self.add_node(join)
125    }
126
127    /// Adds a split node to the forest, and returns the [`MastNodeId`] associated with it.
128    pub fn add_split(
129        &mut self,
130        if_branch: MastNodeId,
131        else_branch: MastNodeId,
132    ) -> Result<MastNodeId, MastForestError> {
133        let split = MastNode::new_split(if_branch, else_branch, self)?;
134        self.add_node(split)
135    }
136
137    /// Adds a loop node to the forest, and returns the [`MastNodeId`] associated with it.
138    pub fn add_loop(&mut self, body: MastNodeId) -> Result<MastNodeId, MastForestError> {
139        let loop_node = MastNode::new_loop(body, self)?;
140        self.add_node(loop_node)
141    }
142
143    /// Adds a call node to the forest, and returns the [`MastNodeId`] associated with it.
144    pub fn add_call(&mut self, callee: MastNodeId) -> Result<MastNodeId, MastForestError> {
145        let call = MastNode::new_call(callee, self)?;
146        self.add_node(call)
147    }
148
149    /// Adds a syscall node to the forest, and returns the [`MastNodeId`] associated with it.
150    pub fn add_syscall(&mut self, callee: MastNodeId) -> Result<MastNodeId, MastForestError> {
151        let syscall = MastNode::new_syscall(callee, self)?;
152        self.add_node(syscall)
153    }
154
155    /// Adds a dyn node to the forest, and returns the [`MastNodeId`] associated with it.
156    pub fn add_dyn(&mut self) -> Result<MastNodeId, MastForestError> {
157        self.add_node(MastNode::new_dyn())
158    }
159
160    /// Adds a dyncall node to the forest, and returns the [`MastNodeId`] associated with it.
161    pub fn add_dyncall(&mut self) -> Result<MastNodeId, MastForestError> {
162        self.add_node(MastNode::new_dyncall())
163    }
164
165    /// Adds an external node to the forest, and returns the [`MastNodeId`] associated with it.
166    pub fn add_external(&mut self, mast_root: RpoDigest) -> Result<MastNodeId, MastForestError> {
167        self.add_node(MastNode::new_external(mast_root))
168    }
169
170    /// Marks the given [`MastNodeId`] as being the root of a procedure.
171    ///
172    /// If the specified node is already marked as a root, this will have no effect.
173    ///
174    /// # Panics
175    /// - if `new_root_id`'s internal index is larger than the number of nodes in this forest (i.e.
176    ///   clearly doesn't belong to this MAST forest).
177    pub fn make_root(&mut self, new_root_id: MastNodeId) {
178        assert!((new_root_id.0 as usize) < self.nodes.len());
179
180        if !self.roots.contains(&new_root_id) {
181            self.roots.push(new_root_id);
182        }
183    }
184
185    /// Removes all nodes in the provided set from the MAST forest. The nodes MUST be orphaned (i.e.
186    /// have no parent). Otherwise, this parent's reference is considered "dangling" after the
187    /// removal (i.e. will point to an incorrect node after the removal), and this removal operation
188    /// would result in an invalid [`MastForest`].
189    ///
190    /// It also returns the map from old node IDs to new node IDs. Any [`MastNodeId`] used in
191    /// reference to the old [`MastForest`] should be remapped using this map.
192    pub fn remove_nodes(
193        &mut self,
194        nodes_to_remove: &BTreeSet<MastNodeId>,
195    ) -> BTreeMap<MastNodeId, MastNodeId> {
196        if nodes_to_remove.is_empty() {
197            return BTreeMap::new();
198        }
199
200        let old_nodes = mem::take(&mut self.nodes);
201        let old_root_ids = mem::take(&mut self.roots);
202        let (retained_nodes, id_remappings) = remove_nodes(old_nodes, nodes_to_remove);
203
204        self.remap_and_add_nodes(retained_nodes, &id_remappings);
205        self.remap_and_add_roots(old_root_ids, &id_remappings);
206        id_remappings
207    }
208
209    pub fn append_before_enter(&mut self, node_id: MastNodeId, decorator_ids: &[DecoratorId]) {
210        self[node_id].append_before_enter(decorator_ids)
211    }
212
213    pub fn append_after_exit(&mut self, node_id: MastNodeId, decorator_ids: &[DecoratorId]) {
214        self[node_id].append_after_exit(decorator_ids)
215    }
216
217    /// Merges all `forests` into a new [`MastForest`].
218    ///
219    /// Merging two forests means combining all their constituent parts, i.e. [`MastNode`]s,
220    /// [`Decorator`]s and roots. During this process, any duplicate or
221    /// unreachable nodes are removed. Additionally, [`MastNodeId`]s of nodes as well as
222    /// [`DecoratorId`]s of decorators may change and references to them are remapped to their new
223    /// location.
224    ///
225    /// For example, consider this representation of a forest's nodes with all of these nodes being
226    /// roots:
227    ///
228    /// ```text
229    /// [Block(foo), Block(bar)]
230    /// ```
231    ///
232    /// If we merge another forest into it:
233    ///
234    /// ```text
235    /// [Block(bar), Call(0)]
236    /// ```
237    ///
238    /// then we would expect this forest:
239    ///
240    /// ```text
241    /// [Block(foo), Block(bar), Call(1)]
242    /// ```
243    ///
244    /// - The `Call` to the `bar` block was remapped to its new index (now 1, previously 0).
245    /// - The `Block(bar)` was deduplicated any only exists once in the merged forest.
246    ///
247    /// The function also returns a vector of [`MastForestRootMap`]s, whose length equals the number
248    /// of passed `forests`. The indices in the vector correspond to the ones in `forests`. The map
249    /// of a given forest contains the new locations of its roots in the merged forest. To
250    /// illustrate, the above example would return a vector of two maps:
251    ///
252    /// ```text
253    /// vec![{0 -> 0, 1 -> 1}
254    ///      {0 -> 1, 1 -> 2}]
255    /// ```
256    ///
257    /// - The root locations of the original forest are unchanged.
258    /// - For the second forest, the `bar` block has moved from index 0 to index 1 in the merged
259    ///   forest, and the `Call` has moved from index 1 to 2.
260    ///
261    /// If any forest being merged contains an `External(qux)` node and another forest contains a
262    /// node whose digest is `qux`, then the external node will be replaced with the `qux` node,
263    /// which is effectively deduplication. Decorators are ignored when it comes to merging
264    /// External nodes. This means that an External node with decorators may be replaced by a node
265    /// without decorators or vice versa.
266    pub fn merge<'forest>(
267        forests: impl IntoIterator<Item = &'forest MastForest>,
268    ) -> Result<(MastForest, MastForestRootMap), MastForestError> {
269        MastForestMerger::merge(forests)
270    }
271
272    /// Adds a basic block node to the forest, and returns the [`MastNodeId`] associated with it.
273    ///
274    /// It is assumed that the decorators have not already been added to the MAST forest. If they
275    /// were, they will be added again (and result in a different set of [`DecoratorId`]s).
276    #[cfg(test)]
277    pub fn add_block_with_raw_decorators(
278        &mut self,
279        operations: Vec<Operation>,
280        decorators: Vec<(usize, Decorator)>,
281    ) -> Result<MastNodeId, MastForestError> {
282        let block = MastNode::new_basic_block_with_raw_decorators(operations, decorators, self)?;
283        self.add_node(block)
284    }
285}
286
287/// Helpers
288impl MastForest {
289    /// Adds all provided nodes to the internal set of nodes, remapping all [`MastNodeId`]
290    /// references in those nodes.
291    ///
292    /// # Panics
293    /// - Panics if the internal set of nodes is not empty.
294    fn remap_and_add_nodes(
295        &mut self,
296        nodes_to_add: Vec<MastNode>,
297        id_remappings: &BTreeMap<MastNodeId, MastNodeId>,
298    ) {
299        assert!(self.nodes.is_empty());
300
301        // Add each node to the new MAST forest, making sure to rewrite any outdated internal
302        // `MastNodeId`s
303        for live_node in nodes_to_add {
304            match &live_node {
305                MastNode::Join(join_node) => {
306                    let first_child =
307                        id_remappings.get(&join_node.first()).copied().unwrap_or(join_node.first());
308                    let second_child = id_remappings
309                        .get(&join_node.second())
310                        .copied()
311                        .unwrap_or(join_node.second());
312
313                    self.add_join(first_child, second_child).unwrap();
314                },
315                MastNode::Split(split_node) => {
316                    let on_true_child = id_remappings
317                        .get(&split_node.on_true())
318                        .copied()
319                        .unwrap_or(split_node.on_true());
320                    let on_false_child = id_remappings
321                        .get(&split_node.on_false())
322                        .copied()
323                        .unwrap_or(split_node.on_false());
324
325                    self.add_split(on_true_child, on_false_child).unwrap();
326                },
327                MastNode::Loop(loop_node) => {
328                    let body_id =
329                        id_remappings.get(&loop_node.body()).copied().unwrap_or(loop_node.body());
330
331                    self.add_loop(body_id).unwrap();
332                },
333                MastNode::Call(call_node) => {
334                    let callee_id = id_remappings
335                        .get(&call_node.callee())
336                        .copied()
337                        .unwrap_or(call_node.callee());
338
339                    if call_node.is_syscall() {
340                        self.add_syscall(callee_id).unwrap();
341                    } else {
342                        self.add_call(callee_id).unwrap();
343                    }
344                },
345                MastNode::Block(_) | MastNode::Dyn(_) | MastNode::External(_) => {
346                    self.add_node(live_node).unwrap();
347                },
348            }
349        }
350    }
351
352    /// Remaps and adds all old root ids to the internal set of roots.
353    ///
354    /// # Panics
355    /// - Panics if the internal set of roots is not empty.
356    fn remap_and_add_roots(
357        &mut self,
358        old_root_ids: Vec<MastNodeId>,
359        id_remappings: &BTreeMap<MastNodeId, MastNodeId>,
360    ) {
361        assert!(self.roots.is_empty());
362
363        for old_root_id in old_root_ids {
364            let new_root_id = id_remappings.get(&old_root_id).copied().unwrap_or(old_root_id);
365            self.make_root(new_root_id);
366        }
367    }
368}
369
370/// Returns the set of nodes that are live, as well as the mapping from "old ID" to "new ID" for all
371/// live nodes.
372fn remove_nodes(
373    mast_nodes: Vec<MastNode>,
374    nodes_to_remove: &BTreeSet<MastNodeId>,
375) -> (Vec<MastNode>, BTreeMap<MastNodeId, MastNodeId>) {
376    // Note: this allows us to safely use `usize as u32`, guaranteeing that it won't wrap around.
377    assert!(mast_nodes.len() < u32::MAX as usize);
378
379    let mut retained_nodes = Vec::with_capacity(mast_nodes.len());
380    let mut id_remappings = BTreeMap::new();
381
382    for (old_node_index, old_node) in mast_nodes.into_iter().enumerate() {
383        let old_node_id: MastNodeId = MastNodeId(old_node_index as u32);
384
385        if !nodes_to_remove.contains(&old_node_id) {
386            let new_node_id: MastNodeId = MastNodeId(retained_nodes.len() as u32);
387            id_remappings.insert(old_node_id, new_node_id);
388
389            retained_nodes.push(old_node);
390        }
391    }
392
393    (retained_nodes, id_remappings)
394}
395
396// ------------------------------------------------------------------------------------------------
397
398/// Public accessors
399impl MastForest {
400    /// Returns the [`Decorator`] associated with the provided [`DecoratorId`] if valid, or else
401    /// `None`.
402    ///
403    /// This is the fallible version of indexing (e.g. `mast_forest[decorator_id]`).
404    #[inline(always)]
405    pub fn get_decorator_by_id(&self, decorator_id: DecoratorId) -> Option<&Decorator> {
406        let idx = decorator_id.0 as usize;
407
408        self.decorators.get(idx)
409    }
410
411    /// Returns the [`MastNode`] associated with the provided [`MastNodeId`] if valid, or else
412    /// `None`.
413    ///
414    /// This is the fallible version of indexing (e.g. `mast_forest[node_id]`).
415    #[inline(always)]
416    pub fn get_node_by_id(&self, node_id: MastNodeId) -> Option<&MastNode> {
417        let idx = node_id.0 as usize;
418
419        self.nodes.get(idx)
420    }
421
422    /// Returns the [`MastNodeId`] of the procedure associated with a given digest, if any.
423    #[inline(always)]
424    pub fn find_procedure_root(&self, digest: RpoDigest) -> Option<MastNodeId> {
425        self.roots.iter().find(|&&root_id| self[root_id].digest() == digest).copied()
426    }
427
428    /// Returns true if a node with the specified ID is a root of a procedure in this MAST forest.
429    pub fn is_procedure_root(&self, node_id: MastNodeId) -> bool {
430        self.roots.contains(&node_id)
431    }
432
433    /// Returns an iterator over the digests of all procedures in this MAST forest.
434    pub fn procedure_digests(&self) -> impl Iterator<Item = RpoDigest> + '_ {
435        self.roots.iter().map(|&root_id| self[root_id].digest())
436    }
437
438    /// Returns an iterator over the digests of local procedures in this MAST forest.
439    ///
440    /// A local procedure is defined as a procedure which is not a single external node.
441    pub fn local_procedure_digests(&self) -> impl Iterator<Item = RpoDigest> + '_ {
442        self.roots.iter().filter_map(|&root_id| {
443            let node = &self[root_id];
444            if node.is_external() { None } else { Some(node.digest()) }
445        })
446    }
447
448    /// Returns an iterator over the IDs of the procedures in this MAST forest.
449    pub fn procedure_roots(&self) -> &[MastNodeId] {
450        &self.roots
451    }
452
453    /// Returns the number of procedures in this MAST forest.
454    pub fn num_procedures(&self) -> u32 {
455        self.roots
456            .len()
457            .try_into()
458            .expect("MAST forest contains more than 2^32 procedures.")
459    }
460
461    /// Returns the number of nodes in this MAST forest.
462    pub fn num_nodes(&self) -> u32 {
463        self.nodes.len() as u32
464    }
465
466    /// Returns the underlying nodes in this MAST forest.
467    pub fn nodes(&self) -> &[MastNode] {
468        &self.nodes
469    }
470
471    pub fn decorators(&self) -> &[Decorator] {
472        &self.decorators
473    }
474
475    pub fn advice_map(&self) -> &AdviceMap {
476        &self.advice_map
477    }
478
479    pub fn advice_map_mut(&mut self) -> &mut AdviceMap {
480        &mut self.advice_map
481    }
482
483    /// Registers an error message in the MAST Forest and returns the
484    /// corresponding error code as a Felt.
485    pub fn register_error(&mut self, msg: Arc<str>) -> Felt {
486        let code: Felt = error_code_from_msg(&msg);
487        let code_key = u64::from(code);
488        // we use u64 as keys for the map
489        self.error_codes.insert(code_key, msg);
490        code
491    }
492
493    /// Given an error code as a Felt, resolves it to its corresponding
494    /// error message.
495    pub fn resolve_error_message(&self, code: Felt) -> Option<Arc<str>> {
496        let key = u64::from(code);
497        self.error_codes.get(&key).cloned()
498    }
499}
500
501impl Index<MastNodeId> for MastForest {
502    type Output = MastNode;
503
504    #[inline(always)]
505    fn index(&self, node_id: MastNodeId) -> &Self::Output {
506        let idx = node_id.0 as usize;
507
508        &self.nodes[idx]
509    }
510}
511
512impl IndexMut<MastNodeId> for MastForest {
513    #[inline(always)]
514    fn index_mut(&mut self, node_id: MastNodeId) -> &mut Self::Output {
515        let idx = node_id.0 as usize;
516
517        &mut self.nodes[idx]
518    }
519}
520
521impl Index<DecoratorId> for MastForest {
522    type Output = Decorator;
523
524    #[inline(always)]
525    fn index(&self, decorator_id: DecoratorId) -> &Self::Output {
526        let idx = decorator_id.0 as usize;
527
528        &self.decorators[idx]
529    }
530}
531
532impl IndexMut<DecoratorId> for MastForest {
533    #[inline(always)]
534    fn index_mut(&mut self, decorator_id: DecoratorId) -> &mut Self::Output {
535        let idx = decorator_id.0 as usize;
536        &mut self.decorators[idx]
537    }
538}
539
540// MAST NODE ID
541// ================================================================================================
542
543/// An opaque handle to a [`MastNode`] in some [`MastForest`]. It is the responsibility of the user
544/// to use a given [`MastNodeId`] with the corresponding [`MastForest`].
545///
546/// Note that the [`MastForest`] does *not* ensure that equal [`MastNode`]s have equal
547/// [`MastNodeId`] handles. Hence, [`MastNodeId`] equality must not be used to test for equality of
548/// the underlying [`MastNode`].
549#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
550pub struct MastNodeId(u32);
551
552/// Operations that mutate a MAST often produce this mapping between old and new NodeIds.
553pub type Remapping = BTreeMap<MastNodeId, MastNodeId>;
554
555impl MastNodeId {
556    /// Returns a new `MastNodeId` with the provided inner value, or an error if the provided
557    /// `value` is greater than the number of nodes in the forest.
558    ///
559    /// For use in deserialization.
560    pub fn from_u32_safe(
561        value: u32,
562        mast_forest: &MastForest,
563    ) -> Result<Self, DeserializationError> {
564        Self::from_u32_with_node_count(value, mast_forest.nodes.len())
565    }
566
567    /// Returns a new [`MastNodeId`] with the provided `node_id`, or an error if `node_id` is
568    /// greater than the number of nodes in the [`MastForest`] for which this ID is being
569    /// constructed.
570    pub fn from_usize_safe(
571        node_id: usize,
572        mast_forest: &MastForest,
573    ) -> Result<Self, DeserializationError> {
574        let node_id: u32 = node_id.try_into().map_err(|_| {
575            DeserializationError::InvalidValue(format!(
576                "node id '{node_id}' does not fit into a u32"
577            ))
578        })?;
579        MastNodeId::from_u32_safe(node_id, mast_forest)
580    }
581
582    /// Returns a new [`MastNodeId`] from the given `value` without checking its validity.
583    pub(crate) fn new_unchecked(value: u32) -> Self {
584        Self(value)
585    }
586
587    /// Returns a new [`MastNodeId`] with the provided `id`, or an error if `id` is greater or equal
588    /// to `node_count`. The `node_count` is the total number of nodes in the [`MastForest`] for
589    /// which this ID is being constructed.
590    ///
591    /// This function can be used when deserializing an id whose corresponding node is not yet in
592    /// the forest and [`Self::from_u32_safe`] would fail. For instance, when deserializing the ids
593    /// referenced by the Join node in this forest:
594    ///
595    /// ```text
596    /// [Join(1, 2), Block(foo), Block(bar)]
597    /// ```
598    ///
599    /// Since it is less safe than [`Self::from_u32_safe`] and usually not needed it is not public.
600    pub(super) fn from_u32_with_node_count(
601        id: u32,
602        node_count: usize,
603    ) -> Result<Self, DeserializationError> {
604        if (id as usize) < node_count {
605            Ok(Self(id))
606        } else {
607            Err(DeserializationError::InvalidValue(format!(
608                "Invalid deserialized MAST node ID '{id}', but {node_count} is the number of nodes in the forest",
609            )))
610        }
611    }
612
613    pub fn as_usize(&self) -> usize {
614        self.0 as usize
615    }
616
617    pub fn as_u32(&self) -> u32 {
618        self.0
619    }
620
621    /// Remap the NodeId to its new position using the given [`Remapping`].
622    pub fn remap(&self, remapping: &Remapping) -> Self {
623        *remapping.get(self).unwrap_or(self)
624    }
625}
626
627impl From<MastNodeId> for usize {
628    fn from(value: MastNodeId) -> Self {
629        value.0 as usize
630    }
631}
632
633impl From<MastNodeId> for u32 {
634    fn from(value: MastNodeId) -> Self {
635        value.0
636    }
637}
638
639impl From<&MastNodeId> for u32 {
640    fn from(value: &MastNodeId) -> Self {
641        value.0
642    }
643}
644
645impl fmt::Display for MastNodeId {
646    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
647        write!(f, "MastNodeId({})", self.0)
648    }
649}
650
651// ITERATOR
652
653/// Iterates over all the nodes a root depends on, in pre-order.
654/// The iteration can include other roots in the same forest.
655pub struct SubtreeIterator<'a> {
656    forest: &'a MastForest,
657    discovered: Vec<MastNodeId>,
658    unvisited: Vec<MastNodeId>,
659}
660impl<'a> SubtreeIterator<'a> {
661    pub fn new(root: &MastNodeId, forest: &'a MastForest) -> Self {
662        let discovered = vec![];
663        let unvisited = vec![*root];
664        SubtreeIterator { forest, discovered, unvisited }
665    }
666}
667impl Iterator for SubtreeIterator<'_> {
668    type Item = MastNodeId;
669    fn next(&mut self) -> Option<MastNodeId> {
670        while let Some(id) = self.unvisited.pop() {
671            let node = &self.forest[id];
672            if !node.has_children() {
673                return Some(id);
674            } else {
675                self.discovered.push(id);
676                node.append_children_to(&mut self.unvisited);
677            }
678        }
679        self.discovered.pop()
680    }
681}
682
683// DECORATOR ID
684// ================================================================================================
685
686/// An opaque handle to a [`Decorator`] in some [`MastForest`]. It is the responsibility of the user
687/// to use a given [`DecoratorId`] with the corresponding [`MastForest`].
688#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
689pub struct DecoratorId(u32);
690
691impl DecoratorId {
692    /// Returns a new `DecoratorId` with the provided inner value, or an error if the provided
693    /// `value` is greater than the number of nodes in the forest.
694    ///
695    /// For use in deserialization.
696    pub fn from_u32_safe(
697        value: u32,
698        mast_forest: &MastForest,
699    ) -> Result<Self, DeserializationError> {
700        if (value as usize) < mast_forest.decorators.len() {
701            Ok(Self(value))
702        } else {
703            Err(DeserializationError::InvalidValue(format!(
704                "Invalid deserialized MAST decorator id '{}', but only {} decorators in the forest",
705                value,
706                mast_forest.nodes.len(),
707            )))
708        }
709    }
710
711    /// Creates a new [`DecoratorId`] without checking its validity.
712    pub(crate) fn new_unchecked(value: u32) -> Self {
713        Self(value)
714    }
715
716    pub fn as_usize(&self) -> usize {
717        self.0 as usize
718    }
719
720    pub fn as_u32(&self) -> u32 {
721        self.0
722    }
723}
724
725impl From<DecoratorId> for usize {
726    fn from(value: DecoratorId) -> Self {
727        value.0 as usize
728    }
729}
730
731impl From<DecoratorId> for u32 {
732    fn from(value: DecoratorId) -> Self {
733        value.0
734    }
735}
736
737impl From<&DecoratorId> for u32 {
738    fn from(value: &DecoratorId) -> Self {
739        value.0
740    }
741}
742
743impl fmt::Display for DecoratorId {
744    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
745        write!(f, "DecoratorId({})", self.0)
746    }
747}
748
749impl Serializable for DecoratorId {
750    fn write_into<W: ByteWriter>(&self, target: &mut W) {
751        self.0.write_into(target)
752    }
753}
754
755/// Derives an error code from an error message by hashing the message and
756/// interpreting the first 64 bits as a Felt.
757pub fn error_code_from_msg(msg: impl AsRef<str>) -> Felt {
758    let digest: Blake3Digest<32> = Blake3_256::hash(msg.as_ref().as_bytes());
759    let mut digest_bytes: [u8; 8] = [0; 8];
760    digest_bytes.copy_from_slice(&digest.as_bytes()[0..8]);
761    let code = u64::from_le_bytes(digest_bytes);
762    Felt::new(code)
763}
764
765// MAST FOREST ERROR
766// ================================================================================================
767
768/// Represents the types of errors that can occur when dealing with MAST forest.
769#[derive(Debug, thiserror::Error, PartialEq)]
770pub enum MastForestError {
771    #[error("MAST forest decorator count exceeds the maximum of {} decorators", u32::MAX)]
772    TooManyDecorators,
773    #[error("MAST forest node count exceeds the maximum of {} nodes", MastForest::MAX_NODES)]
774    TooManyNodes,
775    #[error("node id {0} is greater than or equal to forest length {1}")]
776    NodeIdOverflow(MastNodeId, usize),
777    #[error("decorator id {0} is greater than or equal to decorator count {1}")]
778    DecoratorIdOverflow(DecoratorId, usize),
779    #[error("basic block cannot be created from an empty list of operations")]
780    EmptyBasicBlock,
781    #[error(
782        "decorator root of child with node id {0} is missing but is required for fingerprint computation"
783    )]
784    ChildFingerprintMissing(MastNodeId),
785    #[error("advice map key {0} already exists when merging forests")]
786    AdviceMapKeyCollisionOnMerge(RpoDigest),
787}