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, MastNodeContext};
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(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
75pub(in crate::mast) enum MastNodeOrderClass {
76    External,
77    BasicBlock,
78    Internal,
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, From, MastNodeExt)]
82#[mast_node_ext(builder = "MastNodeBuilder")]
83pub enum MastNode {
84    Block(BasicBlockNode),
85    Join(JoinNode),
86    Split(SplitNode),
87    Loop(LoopNode),
88    Call(CallNode),
89    Dyn(DynNode),
90    External(ExternalNode),
91}
92
93// ------------------------------------------------------------------------------------------------
94/// Public accessors
95impl MastNode {
96    /// Returns the ordering class used by finalized dense MAST forests.
97    pub(in crate::mast) fn order_class(&self) -> MastNodeOrderClass {
98        if self.is_external() {
99            MastNodeOrderClass::External
100        } else if self.is_basic_block() {
101            MastNodeOrderClass::BasicBlock
102        } else {
103            MastNodeOrderClass::Internal
104        }
105    }
106
107    /// Returns true if this node is an external node.
108    pub fn is_external(&self) -> bool {
109        matches!(self, MastNode::External(_))
110    }
111
112    /// Returns true if this node is a Dyn node.
113    pub fn is_dyn(&self) -> bool {
114        matches!(self, MastNode::Dyn(_))
115    }
116
117    /// Returns true if this node is a basic block.
118    pub fn is_basic_block(&self) -> bool {
119        matches!(self, Self::Block(_))
120    }
121
122    /// Returns the inner basic block node if the [`MastNode`] wraps a [`BasicBlockNode`]; `None`
123    /// otherwise.
124    pub fn get_basic_block(&self) -> Option<&BasicBlockNode> {
125        match self {
126            MastNode::Block(basic_block_node) => Some(basic_block_node),
127            _ => None,
128        }
129    }
130
131    /// Unwraps the inner basic block node if the [`MastNode`] wraps a [`BasicBlockNode`]; panics
132    /// otherwise.
133    ///
134    /// # Panics
135    /// Panics if the [`MastNode`] does not wrap a [`BasicBlockNode`].
136    pub fn unwrap_basic_block(&self) -> &BasicBlockNode {
137        match self {
138            Self::Block(basic_block_node) => basic_block_node,
139            other => unwrap_failed(other, "basic block"),
140        }
141    }
142
143    /// Unwraps the inner join node if the [`MastNode`] wraps a [`JoinNode`]; panics otherwise.
144    ///
145    /// # Panics
146    /// - if the [`MastNode`] does not wrap a [`JoinNode`].
147    pub fn unwrap_join(&self) -> &JoinNode {
148        match self {
149            Self::Join(join_node) => join_node,
150            other => unwrap_failed(other, "join"),
151        }
152    }
153
154    /// Unwraps the inner split node if the [`MastNode`] wraps a [`SplitNode`]; panics otherwise.
155    ///
156    /// # Panics
157    /// - if the [`MastNode`] does not wrap a [`SplitNode`].
158    pub fn unwrap_split(&self) -> &SplitNode {
159        match self {
160            Self::Split(split_node) => split_node,
161            other => unwrap_failed(other, "split"),
162        }
163    }
164
165    /// Unwraps the inner loop node if the [`MastNode`] wraps a [`LoopNode`]; panics otherwise.
166    ///
167    /// # Panics
168    /// - if the [`MastNode`] does not wrap a [`LoopNode`].
169    pub fn unwrap_loop(&self) -> &LoopNode {
170        match self {
171            Self::Loop(loop_node) => loop_node,
172            other => unwrap_failed(other, "loop"),
173        }
174    }
175
176    /// Unwraps the inner call node if the [`MastNode`] wraps a [`CallNode`]; panics otherwise.
177    ///
178    /// # Panics
179    /// - if the [`MastNode`] does not wrap a [`CallNode`].
180    pub fn unwrap_call(&self) -> &CallNode {
181        match self {
182            Self::Call(call_node) => call_node,
183            other => unwrap_failed(other, "call"),
184        }
185    }
186
187    /// Unwraps the inner dynamic node if the [`MastNode`] wraps a [`DynNode`]; panics otherwise.
188    ///
189    /// # Panics
190    /// - if the [`MastNode`] does not wrap a [`DynNode`].
191    pub fn unwrap_dyn(&self) -> &DynNode {
192        match self {
193            Self::Dyn(dyn_node) => dyn_node,
194            other => unwrap_failed(other, "dyn"),
195        }
196    }
197
198    /// Unwraps the inner external node if the [`MastNode`] wraps a [`ExternalNode`]; panics
199    /// otherwise.
200    ///
201    /// # Panics
202    /// - if the [`MastNode`] does not wrap a [`ExternalNode`].
203    pub fn unwrap_external(&self) -> &ExternalNode {
204        match self {
205            Self::External(external_node) => external_node,
206            other => unwrap_failed(other, "external"),
207        }
208    }
209}
210
211// HELPERS
212// ===============================================================================================
213
214/// This function is analogous to the `unwrap_failed()` function used in the implementation of
215/// `core::result::Result` `unwrap_*()` methods.
216#[cold]
217#[inline(never)]
218#[track_caller]
219fn unwrap_failed(node: &MastNode, expected: &str) -> ! {
220    let actual = match node {
221        MastNode::Block(_) => "basic block",
222        MastNode::Join(_) => "join",
223        MastNode::Split(_) => "split",
224        MastNode::Loop(_) => "loop",
225        MastNode::Call(_) => "call",
226        MastNode::Dyn(_) => "dynamic",
227        MastNode::External(_) => "external",
228    };
229    panic!("tried to unwrap {expected} node, but got {actual}");
230}