miden_core/mast/node/
dyn_node.rs1use alloc::{boxed::Box, vec::Vec};
2use core::fmt;
3
4use miden_crypto::{Felt, Word};
5use miden_formatting::prettier::{Document, PrettyPrint, const_text, nl};
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use super::{MastNodeErrorContext, MastNodeExt};
10use crate::{
11 OPCODE_DYN, OPCODE_DYNCALL,
12 mast::{DecoratorId, MastForest, MastNodeId, Remapping},
13};
14
15#[derive(Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21pub struct DynNode {
22 is_dyncall: bool,
23 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Vec::is_empty"))]
24 before_enter: Vec<DecoratorId>,
25 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Vec::is_empty"))]
26 after_exit: Vec<DecoratorId>,
27}
28
29impl DynNode {
31 pub const DYN_DOMAIN: Felt = Felt::new(OPCODE_DYN as u64);
33
34 pub const DYNCALL_DOMAIN: Felt = Felt::new(OPCODE_DYNCALL as u64);
36}
37
38impl DynNode {
40 pub fn new_dyn() -> Self {
42 Self {
43 is_dyncall: false,
44 before_enter: Vec::new(),
45 after_exit: Vec::new(),
46 }
47 }
48
49 pub fn new_dyncall() -> Self {
51 Self {
52 is_dyncall: true,
53 before_enter: Vec::new(),
54 after_exit: Vec::new(),
55 }
56 }
57
58 pub fn is_dyncall(&self) -> bool {
60 self.is_dyncall
61 }
62
63 pub fn domain(&self) -> Felt {
65 if self.is_dyncall() {
66 Self::DYNCALL_DOMAIN
67 } else {
68 Self::DYN_DOMAIN
69 }
70 }
71}
72
73impl MastNodeErrorContext for DynNode {
74 fn decorators(&self) -> impl Iterator<Item = (usize, DecoratorId)> {
75 self.before_enter.iter().chain(&self.after_exit).copied().enumerate()
76 }
77}
78
79impl DynNode {
83 pub(super) fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> impl fmt::Display + 'a {
84 DynNodePrettyPrint { node: self, mast_forest }
85 }
86
87 pub(super) fn to_pretty_print<'a>(
88 &'a self,
89 mast_forest: &'a MastForest,
90 ) -> impl PrettyPrint + 'a {
91 DynNodePrettyPrint { node: self, mast_forest }
92 }
93}
94
95struct DynNodePrettyPrint<'a> {
96 node: &'a DynNode,
97 mast_forest: &'a MastForest,
98}
99
100impl DynNodePrettyPrint<'_> {
101 fn concatenate_decorators(
104 &self,
105 decorator_ids: &[DecoratorId],
106 prepend: Document,
107 append: Document,
108 ) -> Document {
109 let decorators = decorator_ids
110 .iter()
111 .map(|&decorator_id| self.mast_forest[decorator_id].render())
112 .reduce(|acc, doc| acc + const_text(" ") + doc)
113 .unwrap_or_default();
114
115 if decorators.is_empty() {
116 decorators
117 } else {
118 prepend + decorators + append
119 }
120 }
121
122 fn single_line_pre_decorators(&self) -> Document {
123 self.concatenate_decorators(self.node.before_enter(), Document::Empty, const_text(" "))
124 }
125
126 fn single_line_post_decorators(&self) -> Document {
127 self.concatenate_decorators(self.node.after_exit(), const_text(" "), Document::Empty)
128 }
129
130 fn multi_line_pre_decorators(&self) -> Document {
131 self.concatenate_decorators(self.node.before_enter(), Document::Empty, nl())
132 }
133
134 fn multi_line_post_decorators(&self) -> Document {
135 self.concatenate_decorators(self.node.after_exit(), nl(), Document::Empty)
136 }
137}
138
139impl crate::prettier::PrettyPrint for DynNodePrettyPrint<'_> {
140 fn render(&self) -> crate::prettier::Document {
141 let dyn_text = if self.node.is_dyncall() {
142 const_text("dyncall")
143 } else {
144 const_text("dyn")
145 };
146
147 let single_line = self.single_line_pre_decorators()
148 + dyn_text.clone()
149 + self.single_line_post_decorators();
150 let multi_line =
151 self.multi_line_pre_decorators() + dyn_text + self.multi_line_post_decorators();
152
153 single_line | multi_line
154 }
155}
156
157impl fmt::Display for DynNodePrettyPrint<'_> {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 self.pretty_print(f)
160 }
161}
162
163impl MastNodeExt for DynNode {
167 fn digest(&self) -> Word {
179 if self.is_dyncall {
180 Word::new([
181 Felt::new(8751004906421739448),
182 Felt::new(13469709002495534233),
183 Felt::new(12584249374630430826),
184 Felt::new(7624899870831503004),
185 ])
186 } else {
187 Word::new([
188 Felt::new(8115106948140260551),
189 Felt::new(13491227816952616836),
190 Felt::new(15015806788322198710),
191 Felt::new(16575543461540527115),
192 ])
193 }
194 }
195
196 fn before_enter(&self) -> &[DecoratorId] {
198 &self.before_enter
199 }
200
201 fn after_exit(&self) -> &[DecoratorId] {
203 &self.after_exit
204 }
205
206 fn append_before_enter(&mut self, decorator_ids: &[DecoratorId]) {
208 self.before_enter.extend_from_slice(decorator_ids);
209 }
210
211 fn append_after_exit(&mut self, decorator_ids: &[DecoratorId]) {
213 self.after_exit.extend_from_slice(decorator_ids);
214 }
215
216 fn remove_decorators(&mut self) {
218 self.before_enter.truncate(0);
219 self.after_exit.truncate(0);
220 }
221
222 fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> Box<dyn fmt::Display + 'a> {
223 Box::new(DynNode::to_display(self, mast_forest))
224 }
225
226 fn to_pretty_print<'a>(&'a self, mast_forest: &'a MastForest) -> Box<dyn PrettyPrint + 'a> {
227 Box::new(DynNode::to_pretty_print(self, mast_forest))
228 }
229
230 fn remap_children(&self, _remapping: &Remapping) -> Self {
231 self.clone()
232 }
233
234 fn has_children(&self) -> bool {
235 false
236 }
237
238 fn append_children_to(&self, _target: &mut Vec<MastNodeId>) {
239 }
241
242 fn domain(&self) -> Felt {
243 self.domain()
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use miden_crypto::hash::rpo::Rpo256;
250
251 use super::*;
252
253 #[test]
256 pub fn test_dyn_node_digest() {
257 assert_eq!(
258 DynNode::new_dyn().digest(),
259 Rpo256::merge_in_domain(&[Word::default(), Word::default()], DynNode::DYN_DOMAIN)
260 );
261
262 assert_eq!(
263 DynNode::new_dyncall().digest(),
264 Rpo256::merge_in_domain(&[Word::default(), Word::default()], DynNode::DYNCALL_DOMAIN)
265 );
266 }
267}