Skip to main content

miden_core/mast/node/
mod.rs

1mod basic_block_node;
2use alloc::{boxed::Box, vec::Vec};
3use core::fmt;
4
5pub use basic_block_node::{
6    BATCH_SIZE as OP_BATCH_SIZE, BasicBlockNode, BasicBlockNodeBuilder, DecoratorOpLinkIterator,
7    GROUP_SIZE as OP_GROUP_SIZE, OpBatch, OperationOrDecorator,
8};
9use derive_more::From;
10use miden_utils_core_derive::MastNodeExt;
11
12mod call_node;
13pub use call_node::{CallNode, CallNodeBuilder};
14
15mod dyn_node;
16pub use dyn_node::{DynNode, DynNodeBuilder};
17
18mod external;
19pub use external::{ExternalNode, ExternalNodeBuilder};
20
21mod join_node;
22pub use join_node::{JoinNode, JoinNodeBuilder};
23
24mod split_node;
25use miden_crypto::{Felt, Word};
26use miden_formatting::prettier::PrettyPrint;
27pub use split_node::{SplitNode, SplitNodeBuilder};
28
29mod loop_node;
30#[cfg(any(test, feature = "arbitrary"))]
31pub use basic_block_node::arbitrary;
32pub use loop_node::{LoopNode, LoopNodeBuilder};
33
34mod mast_forest_contributor;
35pub use mast_forest_contributor::{MastForestContributor, MastNodeBuilder};
36
37mod decorator_store;
38pub use decorator_store::DecoratorStore;
39
40use super::DecoratorId;
41use crate::mast::{MastForest, MastNodeId};
42
43pub trait MastNodeExt {
44    /// Returns a commitment/hash of the node.
45    fn digest(&self) -> Word;
46
47    /// Returns the decorators to be executed before this node is executed.
48    fn before_enter<'a>(&'a self, forest: &'a MastForest) -> &'a [DecoratorId];
49
50    /// Returns the decorators to be executed after this node is executed.
51    fn after_exit<'a>(&'a self, forest: &'a MastForest) -> &'a [DecoratorId];
52
53    /// Returns a display formatter for this node.
54    fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> Box<dyn fmt::Display + 'a>;
55
56    /// Returns a pretty printer for this node.
57    fn to_pretty_print<'a>(&'a self, mast_forest: &'a MastForest) -> Box<dyn PrettyPrint + 'a>;
58
59    /// Returns true if the this node has children.
60    fn has_children(&self) -> bool;
61
62    /// Appends the NodeIds of the children of this node, if any, to the vector.
63    fn append_children_to(&self, target: &mut Vec<MastNodeId>);
64
65    /// Executes the given closure for each child of this node.
66    fn for_each_child<F>(&self, f: F)
67    where
68        F: FnMut(MastNodeId);
69
70    /// Returns the domain of this node.
71    fn domain(&self) -> Felt;
72
73    /// Verifies that this node is stored at the ID in its decorators field in the forest.
74    #[cfg(debug_assertions)]
75    fn verify_node_in_forest(&self, forest: &MastForest);
76
77    /// Converts this node into its corresponding builder, reusing allocated data where possible.
78    type Builder: MastForestContributor;
79
80    fn to_builder(self, forest: &MastForest) -> Self::Builder;
81}
82
83// MAST NODE
84// ================================================================================================
85
86#[derive(Debug, Clone, PartialEq, Eq, From, MastNodeExt)]
87#[mast_node_ext(builder = "MastNodeBuilder")]
88pub enum MastNode {
89    Block(BasicBlockNode),
90    Join(JoinNode),
91    Split(SplitNode),
92    Loop(LoopNode),
93    Call(CallNode),
94    Dyn(DynNode),
95    External(ExternalNode),
96}
97
98// ------------------------------------------------------------------------------------------------
99/// Public accessors
100impl MastNode {
101    /// Returns true if this node is an external node.
102    pub fn is_external(&self) -> bool {
103        matches!(self, MastNode::External(_))
104    }
105
106    /// Returns true if this node is a Dyn node.
107    pub fn is_dyn(&self) -> bool {
108        matches!(self, MastNode::Dyn(_))
109    }
110
111    /// Returns true if this node is a basic block.
112    pub fn is_basic_block(&self) -> bool {
113        matches!(self, Self::Block(_))
114    }
115
116    /// Returns the inner basic block node if the [`MastNode`] wraps a [`BasicBlockNode`]; `None`
117    /// otherwise.
118    pub fn get_basic_block(&self) -> Option<&BasicBlockNode> {
119        match self {
120            MastNode::Block(basic_block_node) => Some(basic_block_node),
121            _ => None,
122        }
123    }
124
125    /// Unwraps the inner basic block node if the [`MastNode`] wraps a [`BasicBlockNode`]; panics
126    /// otherwise.
127    ///
128    /// # Panics
129    /// Panics if the [`MastNode`] does not wrap a [`BasicBlockNode`].
130    pub fn unwrap_basic_block(&self) -> &BasicBlockNode {
131        match self {
132            Self::Block(basic_block_node) => basic_block_node,
133            other => unwrap_failed(other, "basic block"),
134        }
135    }
136
137    /// Unwraps the inner join node if the [`MastNode`] wraps a [`JoinNode`]; panics otherwise.
138    ///
139    /// # Panics
140    /// - if the [`MastNode`] does not wrap a [`JoinNode`].
141    pub fn unwrap_join(&self) -> &JoinNode {
142        match self {
143            Self::Join(join_node) => join_node,
144            other => unwrap_failed(other, "join"),
145        }
146    }
147
148    /// Unwraps the inner split node if the [`MastNode`] wraps a [`SplitNode`]; panics otherwise.
149    ///
150    /// # Panics
151    /// - if the [`MastNode`] does not wrap a [`SplitNode`].
152    pub fn unwrap_split(&self) -> &SplitNode {
153        match self {
154            Self::Split(split_node) => split_node,
155            other => unwrap_failed(other, "split"),
156        }
157    }
158
159    /// Unwraps the inner loop node if the [`MastNode`] wraps a [`LoopNode`]; panics otherwise.
160    ///
161    /// # Panics
162    /// - if the [`MastNode`] does not wrap a [`LoopNode`].
163    pub fn unwrap_loop(&self) -> &LoopNode {
164        match self {
165            Self::Loop(loop_node) => loop_node,
166            other => unwrap_failed(other, "loop"),
167        }
168    }
169
170    /// Unwraps the inner call node if the [`MastNode`] wraps a [`CallNode`]; panics otherwise.
171    ///
172    /// # Panics
173    /// - if the [`MastNode`] does not wrap a [`CallNode`].
174    pub fn unwrap_call(&self) -> &CallNode {
175        match self {
176            Self::Call(call_node) => call_node,
177            other => unwrap_failed(other, "call"),
178        }
179    }
180
181    /// Unwraps the inner dynamic node if the [`MastNode`] wraps a [`DynNode`]; panics otherwise.
182    ///
183    /// # Panics
184    /// - if the [`MastNode`] does not wrap a [`DynNode`].
185    pub fn unwrap_dyn(&self) -> &DynNode {
186        match self {
187            Self::Dyn(dyn_node) => dyn_node,
188            other => unwrap_failed(other, "dyn"),
189        }
190    }
191
192    /// Unwraps the inner external node if the [`MastNode`] wraps a [`ExternalNode`]; panics
193    /// otherwise.
194    ///
195    /// # Panics
196    /// - if the [`MastNode`] does not wrap a [`ExternalNode`].
197    pub fn unwrap_external(&self) -> &ExternalNode {
198        match self {
199            Self::External(external_node) => external_node,
200            other => unwrap_failed(other, "external"),
201        }
202    }
203}
204
205// MAST INNER NODE EXT
206// ===============================================================================================
207
208// Links an operation index in a block to a decoratorid, to be executed right before this
209// operation's position
210pub type DecoratedOpLink = (usize, DecoratorId);
211
212// HELPERS
213// ===============================================================================================
214
215/// This function is analogous to the `unwrap_failed()` function used in the implementation of
216/// `core::result::Result` `unwrap_*()` methods.
217#[cold]
218#[inline(never)]
219#[track_caller]
220fn unwrap_failed(node: &MastNode, expected: &str) -> ! {
221    let actual = match node {
222        MastNode::Block(_) => "basic block",
223        MastNode::Join(_) => "join",
224        MastNode::Split(_) => "split",
225        MastNode::Loop(_) => "loop",
226        MastNode::Call(_) => "call",
227        MastNode::Dyn(_) => "dynamic",
228        MastNode::External(_) => "external",
229    };
230    panic!("tried to unwrap {expected} node, but got {actual}");
231}