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, MastNodeContext, 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
156#[cfg(any(test, feature = "arbitrary"))]
157impl ExternalNodeBuilder {
158 pub fn add_to_forest(self, forest: &mut MastForest) -> Result<MastNodeId, MastForestError> {
160 let node_id = forest
161 .nodes
162 .push(self.build().into())
163 .map_err(|_| MastForestError::TooManyNodes)?;
164 forest.commitment = forest.compute_mast_forest_commitment();
165 Ok(node_id)
166 }
167}
168
169impl MastForestContributor for ExternalNodeBuilder {
170 fn fingerprint_for_node(
171 &self,
172 _context: &impl MastNodeContext,
173 _hash_by_node_id: &impl LookupByIdx<MastNodeId, Word>,
174 ) -> Result<Word, MastForestError> {
175 Ok(self.digest)
176 }
177
178 fn remap_children(self, _remapping: &impl LookupByIdx<MastNodeId, MastNodeId>) -> Self {
179 self
181 }
182
183 fn with_digest(mut self, digest: Word) -> Self {
184 self.digest = digest;
185 self
186 }
187}
188
189#[cfg(any(test, feature = "arbitrary"))]
190impl proptest::prelude::Arbitrary for ExternalNodeBuilder {
191 type Parameters = ();
192 type Strategy = proptest::strategy::BoxedStrategy<Self>;
193
194 fn arbitrary_with(_params: Self::Parameters) -> Self::Strategy {
195 use proptest::prelude::*;
196
197 any::<[u64; 4]>()
198 .prop_map(|[a, b, c, d]| {
199 Word::new([
200 Felt::new_unchecked(a),
201 Felt::new_unchecked(b),
202 Felt::new_unchecked(c),
203 Felt::new_unchecked(d),
204 ])
205 })
206 .prop_map(Self::new)
207 .boxed()
208 }
209}