miden_core/mast/node/
external.rs1use alloc::{boxed::Box, vec::Vec};
2use core::fmt;
3
4use miden_formatting::{
5 hex::ToHex,
6 prettier::{Document, PrettyPrint, const_text, text},
7};
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize};
10
11use super::{MastForestContributor, MastNodeExt};
12use crate::{
13 Felt, Word,
14 mast::{MastForest, MastForestError, MastNodeId},
15 utils::LookupByIdx,
16};
17
18#[derive(Clone, Debug, PartialEq, Eq)]
30#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
31#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
32pub struct ExternalNode {
33 digest: Word,
34}
35
36impl ExternalNode {
40 pub(super) fn to_display<'a>(&'a self, _mast_forest: &'a MastForest) -> impl fmt::Display + 'a {
41 self.clone()
42 }
43
44 pub(super) fn to_pretty_print<'a>(
45 &'a self,
46 _mast_forest: &'a MastForest,
47 ) -> impl PrettyPrint + 'a {
48 self.clone()
49 }
50}
51
52impl PrettyPrint for ExternalNode {
53 fn render(&self) -> Document {
54 const_text("external") + const_text(".") + text(self.digest.as_bytes().to_hex_with_prefix())
55 }
56}
57
58impl fmt::Display for ExternalNode {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 use crate::prettier::PrettyPrint;
61 self.pretty_print(f)
62 }
63}
64
65impl MastNodeExt for ExternalNode {
69 fn digest(&self) -> Word {
75 self.digest
76 }
77
78 fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> Box<dyn fmt::Display + 'a> {
79 Box::new(ExternalNode::to_display(self, mast_forest))
80 }
81
82 fn to_pretty_print<'a>(&'a self, mast_forest: &'a MastForest) -> Box<dyn PrettyPrint + 'a> {
83 Box::new(ExternalNode::to_pretty_print(self, mast_forest))
84 }
85
86 fn has_children(&self) -> bool {
87 false
88 }
89
90 fn append_children_to(&self, _target: &mut Vec<MastNodeId>) {
91 }
93
94 fn for_each_child<F>(&self, _f: F)
95 where
96 F: FnMut(MastNodeId),
97 {
98 }
100
101 fn domain(&self) -> Felt {
102 panic!("Can't fetch domain for an `External` node.")
103 }
104
105 type Builder = ExternalNodeBuilder;
106
107 fn to_builder(self, _forest: &MastForest) -> Self::Builder {
108 ExternalNodeBuilder::new(self.digest)
109 }
110}
111
112#[cfg(all(feature = "arbitrary", test))]
116impl proptest::prelude::Arbitrary for ExternalNode {
117 type Parameters = ();
118
119 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
120 use proptest::prelude::*;
121
122 use crate::Felt;
123
124 any::<[u64; 4]>()
126 .prop_map(|[a, b, c, d]| {
127 let word = Word::from([Felt::new_unchecked(a), Felt::new_unchecked(b), Felt::new_unchecked(c), Felt::new_unchecked(d)]);
128 ExternalNodeBuilder::new(word).build()
129 })
130 .no_shrink() .boxed()
132 }
133
134 type Strategy = proptest::prelude::BoxedStrategy<Self>;
135}
136
137#[derive(Debug)]
140pub struct ExternalNodeBuilder {
141 digest: Word,
142}
143
144impl ExternalNodeBuilder {
145 pub fn new(digest: Word) -> Self {
147 Self { digest }
148 }
149
150 pub fn build(self) -> ExternalNode {
152 ExternalNode { digest: self.digest }
153 }
154}
155
156impl MastForestContributor for ExternalNodeBuilder {
157 fn add_to_forest(self, forest: &mut MastForest) -> Result<MastNodeId, MastForestError> {
158 let node_id = forest
161 .nodes
162 .push(ExternalNode { digest: self.digest }.into())
163 .map_err(|_| MastForestError::TooManyNodes)?;
164
165 Ok(node_id)
166 }
167
168 fn fingerprint_for_node(
169 &self,
170 _forest: &MastForest,
171 _hash_by_node_id: &impl LookupByIdx<MastNodeId, Word>,
172 ) -> Result<Word, MastForestError> {
173 Ok(self.digest)
174 }
175
176 fn remap_children(self, _remapping: &impl LookupByIdx<MastNodeId, MastNodeId>) -> Self {
177 self
179 }
180
181 fn with_digest(mut self, digest: Word) -> Self {
182 self.digest = digest;
183 self
184 }
185}
186
187impl ExternalNodeBuilder {
188 pub(in crate::mast) fn add_to_forest_relaxed(
198 self,
199 forest: &mut MastForest,
200 ) -> Result<MastNodeId, MastForestError> {
201 let node_id = forest
204 .nodes
205 .push(ExternalNode { digest: self.digest }.into())
206 .map_err(|_| MastForestError::TooManyNodes)?;
207
208 Ok(node_id)
209 }
210}
211
212#[cfg(any(test, feature = "arbitrary"))]
213impl proptest::prelude::Arbitrary for ExternalNodeBuilder {
214 type Parameters = ExternalNodeBuilderParams;
215 type Strategy = proptest::strategy::BoxedStrategy<Self>;
216
217 fn arbitrary_with(params: Self::Parameters) -> Self::Strategy {
218 use proptest::prelude::*;
219
220 let _ = params;
221 any::<[u64; 4]>()
222 .prop_map(|[a, b, c, d]| {
223 Word::new([
224 Felt::new_unchecked(a),
225 Felt::new_unchecked(b),
226 Felt::new_unchecked(c),
227 Felt::new_unchecked(d),
228 ])
229 })
230 .prop_map(Self::new)
231 .boxed()
232 }
233}
234
235#[cfg(any(test, feature = "arbitrary"))]
237#[derive(Clone, Debug, Default)]
238pub struct ExternalNodeBuilderParams {}