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,
8    GROUP_SIZE as OP_GROUP_SIZE, OpBatch,
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(super) use mast_forest_contributor::fingerprint_with_child_fingerprints;
37pub use mast_forest_contributor::{MastForestContributor, MastNodeBuilder};
38
39use crate::mast::{MastForest, MastNodeId};
40
41pub trait MastNodeExt {
42    /// Returns a commitment/hash of the node.
43    fn digest(&self) -> Word;
44
45    /// Returns a display formatter for this node.
46    fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> Box<dyn fmt::Display + 'a>;
47
48    /// Returns a pretty printer for this node.
49    fn to_pretty_print<'a>(&'a self, mast_forest: &'a MastForest) -> Box<dyn PrettyPrint + 'a>;
50
51    /// Returns true if the this node has children.
52    fn has_children(&self) -> bool;
53
54    /// Appends the NodeIds of the children of this node, if any, to the vector.
55    fn append_children_to(&self, target: &mut Vec<MastNodeId>);
56
57    /// Executes the given closure for each child of this node.
58    fn for_each_child<F>(&self, f: F)
59    where
60        F: FnMut(MastNodeId);
61
62    /// Returns the domain of this node.
63    fn domain(&self) -> Felt;
64
65    /// Converts this node into its corresponding builder, reusing allocated data where possible.
66    type Builder: MastForestContributor;
67
68    fn to_builder(self, forest: &MastForest) -> Self::Builder;
69}
70
71// MAST NODE
72// ================================================================================================
73
74#[derive(Debug, Clone, PartialEq, Eq, From, MastNodeExt)]
75#[mast_node_ext(builder = "MastNodeBuilder")]
76pub enum MastNode {
77    Block(BasicBlockNode),
78    Join(JoinNode),
79    Split(SplitNode),
80    Loop(LoopNode),
81    Call(CallNode),
82    Dyn(DynNode),
83    External(ExternalNode),
84}
85
86// ------------------------------------------------------------------------------------------------
87/// Public accessors
88impl MastNode {
89    /// Returns true if this node is an external node.
90    pub fn is_external(&self) -> bool {
91        matches!(self, MastNode::External(_))
92    }
93
94    /// Returns true if this node is a Dyn node.
95    pub fn is_dyn(&self) -> bool {
96        matches!(self, MastNode::Dyn(_))
97    }
98
99    /// Returns true if this node is a basic block.
100    pub fn is_basic_block(&self) -> bool {
101        matches!(self, Self::Block(_))
102    }
103
104    /// Returns the inner basic block node if the [`MastNode`] wraps a [`BasicBlockNode`]; `None`
105    /// otherwise.
106    pub fn get_basic_block(&self) -> Option<&BasicBlockNode> {
107        match self {
108            MastNode::Block(basic_block_node) => Some(basic_block_node),
109            _ => None,
110        }
111    }
112
113    /// Unwraps the inner basic block node if the [`MastNode`] wraps a [`BasicBlockNode`]; panics
114    /// otherwise.
115    ///
116    /// # Panics
117    /// Panics if the [`MastNode`] does not wrap a [`BasicBlockNode`].
118    pub fn unwrap_basic_block(&self) -> &BasicBlockNode {
119        match self {
120            Self::Block(basic_block_node) => basic_block_node,
121            other => unwrap_failed(other, "basic block"),
122        }
123    }
124
125    /// Unwraps the inner join node if the [`MastNode`] wraps a [`JoinNode`]; panics otherwise.
126    ///
127    /// # Panics
128    /// - if the [`MastNode`] does not wrap a [`JoinNode`].
129    pub fn unwrap_join(&self) -> &JoinNode {
130        match self {
131            Self::Join(join_node) => join_node,
132            other => unwrap_failed(other, "join"),
133        }
134    }
135
136    /// Unwraps the inner split node if the [`MastNode`] wraps a [`SplitNode`]; panics otherwise.
137    ///
138    /// # Panics
139    /// - if the [`MastNode`] does not wrap a [`SplitNode`].
140    pub fn unwrap_split(&self) -> &SplitNode {
141        match self {
142            Self::Split(split_node) => split_node,
143            other => unwrap_failed(other, "split"),
144        }
145    }
146
147    /// Unwraps the inner loop node if the [`MastNode`] wraps a [`LoopNode`]; panics otherwise.
148    ///
149    /// # Panics
150    /// - if the [`MastNode`] does not wrap a [`LoopNode`].
151    pub fn unwrap_loop(&self) -> &LoopNode {
152        match self {
153            Self::Loop(loop_node) => loop_node,
154            other => unwrap_failed(other, "loop"),
155        }
156    }
157
158    /// Unwraps the inner call node if the [`MastNode`] wraps a [`CallNode`]; panics otherwise.
159    ///
160    /// # Panics
161    /// - if the [`MastNode`] does not wrap a [`CallNode`].
162    pub fn unwrap_call(&self) -> &CallNode {
163        match self {
164            Self::Call(call_node) => call_node,
165            other => unwrap_failed(other, "call"),
166        }
167    }
168
169    /// Unwraps the inner dynamic node if the [`MastNode`] wraps a [`DynNode`]; panics otherwise.
170    ///
171    /// # Panics
172    /// - if the [`MastNode`] does not wrap a [`DynNode`].
173    pub fn unwrap_dyn(&self) -> &DynNode {
174        match self {
175            Self::Dyn(dyn_node) => dyn_node,
176            other => unwrap_failed(other, "dyn"),
177        }
178    }
179
180    /// Unwraps the inner external node if the [`MastNode`] wraps a [`ExternalNode`]; panics
181    /// otherwise.
182    ///
183    /// # Panics
184    /// - if the [`MastNode`] does not wrap a [`ExternalNode`].
185    pub fn unwrap_external(&self) -> &ExternalNode {
186        match self {
187            Self::External(external_node) => external_node,
188            other => unwrap_failed(other, "external"),
189        }
190    }
191}
192
193// HELPERS
194// ===============================================================================================
195
196/// This function is analogous to the `unwrap_failed()` function used in the implementation of
197/// `core::result::Result` `unwrap_*()` methods.
198#[cold]
199#[inline(never)]
200#[track_caller]
201fn unwrap_failed(node: &MastNode, expected: &str) -> ! {
202    let actual = match node {
203        MastNode::Block(_) => "basic block",
204        MastNode::Join(_) => "join",
205        MastNode::Split(_) => "split",
206        MastNode::Loop(_) => "loop",
207        MastNode::Call(_) => "call",
208        MastNode::Dyn(_) => "dynamic",
209        MastNode::External(_) => "external",
210    };
211    panic!("tried to unwrap {expected} node, but got {actual}");
212}