Skip to main content

miden_core/mast/serialization/
view.rs

1use alloc::{borrow::Cow, collections::BTreeMap, vec::Vec};
2use core::mem::size_of;
3
4use super::{
5    MastNodeEntry, MastNodeInfo,
6    layout::{OffsetTrackingReader, TrackingReader},
7};
8use crate::{
9    Felt, Word,
10    advice::AdviceMap,
11    mast::MastNodeId,
12    serde::{ByteReader, Deserializable, DeserializationError, SliceReader},
13};
14
15const FELT_SERIALIZED_SIZE: usize = size_of::<u64>();
16
17/// Read-only view over a value from forest advice.
18#[derive(Debug)]
19pub struct AdviceValueView<'a> {
20    inner: Cow<'a, [Felt]>,
21}
22
23impl<'a> AdviceValueView<'a> {
24    pub(crate) fn borrowed(values: &'a [Felt]) -> Self {
25        Self { inner: Cow::Borrowed(values) }
26    }
27
28    fn owned(values: Vec<Felt>) -> Self {
29        Self { inner: Cow::Owned(values) }
30    }
31
32    /// Returns the advice values as a slice.
33    pub fn as_slice(&self) -> &[Felt] {
34        self.inner.as_ref()
35    }
36
37    /// Returns the number of field elements in this advice value.
38    pub fn len(&self) -> usize {
39        self.as_slice().len()
40    }
41
42    /// Returns true when this advice value contains no field elements.
43    pub fn is_empty(&self) -> bool {
44        self.as_slice().is_empty()
45    }
46}
47
48impl AsRef<[Felt]> for AdviceValueView<'_> {
49    fn as_ref(&self) -> &[Felt] {
50        self.as_slice()
51    }
52}
53
54/// Read-only view over forest advice.
55#[derive(Debug)]
56pub struct AdviceMapView<'a> {
57    inner: AdviceMapViewInner<'a>,
58}
59
60#[derive(Debug)]
61enum AdviceMapViewInner<'a> {
62    Materialized(&'a AdviceMap),
63    Wire(&'a WireAdviceMapView<'a>),
64}
65
66impl<'a> AdviceMapView<'a> {
67    pub(crate) fn materialized(advice_map: &'a AdviceMap) -> Self {
68        Self {
69            inner: AdviceMapViewInner::Materialized(advice_map),
70        }
71    }
72
73    pub(crate) fn wire(advice_map: &'a WireAdviceMapView<'a>) -> Self {
74        Self {
75            inner: AdviceMapViewInner::Wire(advice_map),
76        }
77    }
78
79    /// Returns the number of key-value entries in this advice map.
80    pub fn len(&self) -> usize {
81        match self.inner {
82            AdviceMapViewInner::Materialized(advice_map) => advice_map.len(),
83            AdviceMapViewInner::Wire(advice_map) => advice_map.len(),
84        }
85    }
86
87    /// Returns true when this advice map has no entries.
88    pub fn is_empty(&self) -> bool {
89        self.len() == 0
90    }
91
92    /// Returns true when the key has a corresponding value in the map.
93    pub fn contains_key(&self, key: &Word) -> bool {
94        match self.inner {
95            AdviceMapViewInner::Materialized(advice_map) => advice_map.contains_key(key),
96            AdviceMapViewInner::Wire(advice_map) => advice_map.contains_key(key),
97        }
98    }
99
100    /// Returns the values associated with a key, if present.
101    pub fn get(&self, key: &Word) -> Result<Option<AdviceValueView<'a>>, DeserializationError> {
102        match self.inner {
103            AdviceMapViewInner::Materialized(advice_map) => {
104                Ok(advice_map.get(key).map(|values| AdviceValueView::borrowed(values.as_ref())))
105            },
106            AdviceMapViewInner::Wire(advice_map) => advice_map.get(key),
107        }
108    }
109}
110
111#[derive(Debug)]
112pub(crate) struct WireAdviceMapView<'a> {
113    bytes: &'a [u8],
114    entries: BTreeMap<Word, AdviceValueRange>,
115    end_offset: usize,
116}
117
118#[derive(Debug, Clone, Copy)]
119struct AdviceValueRange {
120    offset: usize,
121    len: usize,
122}
123
124impl<'a> WireAdviceMapView<'a> {
125    pub(crate) fn new(bytes: &'a [u8], offset: usize) -> Result<Self, DeserializationError> {
126        let slice = bytes.get(offset..).ok_or(DeserializationError::UnexpectedEOF)?;
127        let mut reader = SliceReader::new(slice);
128        let mut reader = TrackingReader::new(&mut reader);
129        let entry_count = reader.read_usize()?;
130        let mut entries = BTreeMap::new();
131
132        for _ in 0..entry_count {
133            let key = Word::read_from(&mut reader)?;
134            let len = reader.read_usize()?;
135            let value_offset = offset.checked_add(reader.offset()).ok_or_else(|| {
136                DeserializationError::InvalidValue("advice value offset overflow".into())
137            })?;
138            let value_byte_len = len.checked_mul(FELT_SERIALIZED_SIZE).ok_or_else(|| {
139                DeserializationError::InvalidValue("advice value length overflow".into())
140            })?;
141            reader.read_slice(value_byte_len)?;
142
143            if entries.insert(key, AdviceValueRange { offset: value_offset, len }).is_some() {
144                return Err(DeserializationError::InvalidValue(
145                    "duplicate advice key in wire payload".into(),
146                ));
147            }
148        }
149
150        let end_offset = offset.checked_add(reader.offset()).ok_or_else(|| {
151            DeserializationError::InvalidValue("advice map offset overflow".into())
152        })?;
153
154        Ok(Self { bytes, entries, end_offset })
155    }
156
157    pub(crate) fn end_offset(&self) -> usize {
158        self.end_offset
159    }
160
161    fn len(&self) -> usize {
162        self.entries.len()
163    }
164
165    fn contains_key(&self, key: &Word) -> bool {
166        self.entries.contains_key(key)
167    }
168
169    fn get(&self, key: &Word) -> Result<Option<AdviceValueView<'a>>, DeserializationError> {
170        let Some(range) = self.entries.get(key) else {
171            return Ok(None);
172        };
173
174        let byte_len = range.len.checked_mul(FELT_SERIALIZED_SIZE).ok_or_else(|| {
175            DeserializationError::InvalidValue("advice value length overflow".into())
176        })?;
177        let end = range.offset.checked_add(byte_len).ok_or_else(|| {
178            DeserializationError::InvalidValue("advice value offset overflow".into())
179        })?;
180        let bytes = self.bytes.get(range.offset..end).ok_or(DeserializationError::UnexpectedEOF)?;
181        let mut reader = SliceReader::new(bytes);
182        let mut values = Vec::with_capacity(range.len);
183
184        for _ in 0..range.len {
185            values.push(Felt::read_from(&mut reader)?);
186        }
187
188        Ok(Some(AdviceValueView::owned(values)))
189    }
190}
191
192/// Read-only view over serialization-oriented MAST node metadata.
193///
194/// This trait lives alongside [`super::MastForestWireView`] because its surface is defined in
195/// terms of serialized-equivalent node entries and digests, even though both
196/// [`super::MastForestWireView`] and in-memory [`crate::mast::MastForest`] implement it.
197pub trait MastForestView {
198    /// Returns the number of nodes in the forest.
199    fn node_count(&self) -> usize;
200
201    /// Returns fixed-width structural metadata for a node at the specified index.
202    ///
203    /// Returns an error if `index >= self.node_count()`.
204    fn node_entry_at(&self, index: usize) -> Result<MastNodeEntry, DeserializationError>;
205
206    /// Returns the digest of the node at the specified index.
207    ///
208    /// Returns an error if `index >= self.node_count()`.
209    fn node_digest_at(&self, index: usize) -> Result<Word, DeserializationError>;
210
211    /// Returns serialized-equivalent metadata for a node at the specified index.
212    ///
213    /// Returns an error if `index >= self.node_count()`.
214    fn node_info_at(&self, index: usize) -> Result<MastNodeInfo, DeserializationError> {
215        Ok(MastNodeInfo::from_entry(
216            self.node_entry_at(index)?,
217            self.node_digest_at(index)?,
218        ))
219    }
220
221    /// Returns the number of procedure roots in the forest.
222    fn procedure_root_count(&self) -> usize;
223
224    /// Returns the procedure root id at the specified index.
225    ///
226    /// Returns an error if `index >= self.procedure_root_count()`.
227    fn procedure_root_at(&self, index: usize) -> Result<MastNodeId, DeserializationError>;
228
229    /// Returns a read-only view over the forest advice map.
230    fn advice_map(&self) -> AdviceMapView<'_>;
231
232    /// Returns true when the forest contains no nodes.
233    fn is_empty(&self) -> bool {
234        self.node_count() == 0
235    }
236
237    /// Returns true when `index` is a valid node index.
238    fn has_node(&self, index: usize) -> bool {
239        index < self.node_count()
240    }
241
242    /// Returns all node infos in index order.
243    fn all_node_infos(&self) -> Result<Vec<MastNodeInfo>, DeserializationError> {
244        (0..self.node_count()).map(|index| self.node_info_at(index)).collect()
245    }
246
247    /// Returns all procedure roots in index order.
248    fn procedure_roots(&self) -> Result<Vec<MastNodeId>, DeserializationError> {
249        (0..self.procedure_root_count())
250            .map(|index| self.procedure_root_at(index))
251            .collect()
252    }
253}