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