miden_core/operations/decorators/
mod.rs

1use alloc::{string::ToString, vec::Vec};
2use core::fmt;
3
4use miden_crypto::hash::blake::Blake3_256;
5use num_traits::ToBytes;
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9mod assembly_op;
10pub use assembly_op::AssemblyOp;
11
12mod debug;
13pub use debug::DebugOptions;
14
15use crate::mast::{DecoratorFingerprint, DecoratorId};
16
17// DECORATORS
18// ================================================================================================
19
20/// A set of decorators which can be executed by the VM.
21///
22/// Executing a decorator does not affect the state of the main VM components such as operand stack
23/// and memory.
24///
25/// Executing decorators does not advance the VM clock. As such, many decorators can be executed in
26/// a single VM cycle.
27#[derive(Clone, Debug, Eq, PartialEq)]
28#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29pub enum Decorator {
30    /// Adds information about the assembly instruction at a particular index (only applicable in
31    /// debug mode).
32    AsmOp(AssemblyOp),
33    /// Prints out information about the state of the VM based on the specified options. This
34    /// decorator is executed only in debug mode.
35    Debug(DebugOptions),
36    /// Emits a trace to the host.
37    Trace(u32),
38}
39
40impl Decorator {
41    pub fn fingerprint(&self) -> DecoratorFingerprint {
42        match self {
43            Self::AsmOp(asm_op) => {
44                let mut bytes_to_hash = Vec::new();
45                if let Some(location) = asm_op.location() {
46                    bytes_to_hash.extend(location.uri.as_str().as_bytes());
47                    bytes_to_hash.extend(location.start.to_u32().to_le_bytes());
48                    bytes_to_hash.extend(location.end.to_u32().to_le_bytes());
49                }
50                bytes_to_hash.extend(asm_op.context_name().as_bytes());
51                bytes_to_hash.extend(asm_op.op().as_bytes());
52                bytes_to_hash.push(asm_op.num_cycles());
53                bytes_to_hash.push(asm_op.should_break() as u8);
54
55                Blake3_256::hash(&bytes_to_hash)
56            },
57            Self::Debug(debug) => Blake3_256::hash(debug.to_string().as_bytes()),
58            Self::Trace(trace) => Blake3_256::hash(&trace.to_le_bytes()),
59        }
60    }
61}
62
63impl crate::prettier::PrettyPrint for Decorator {
64    fn render(&self) -> crate::prettier::Document {
65        crate::prettier::display(self)
66    }
67}
68
69impl fmt::Display for Decorator {
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        match self {
72            Self::AsmOp(assembly_op) => {
73                write!(f, "asmOp({}, {})", assembly_op.op(), assembly_op.num_cycles())
74            },
75            Self::Debug(options) => write!(f, "debug({options})"),
76            Self::Trace(trace_id) => write!(f, "trace({trace_id})"),
77        }
78    }
79}
80
81/// Vector consisting of a tuple of operation index (within a span block) and decorator at that
82/// index.
83///
84/// Note: for `AssemblyOp` decorators, when an instruction compiles down to multiple operations,
85/// only the first operation is associated with the assembly op.
86pub type DecoratorList = Vec<(usize, DecoratorId)>;
87
88/// Iterator used to iterate through the decorator list of a span block
89/// while executing operation batches of a span block.
90pub struct DecoratorIdIterator<'a> {
91    decorators: &'a DecoratorList,
92    idx: usize,
93}
94
95impl<'a> DecoratorIdIterator<'a> {
96    /// Returns a new instance of decorator iterator instantiated with the provided decorator list.
97    pub fn new(decorators: &'a DecoratorList) -> Self {
98        Self { decorators, idx: 0 }
99    }
100
101    /// Returns the next decorator but only if its position matches the specified position,
102    /// otherwise, None is returned.
103    #[inline(always)]
104    pub fn next_filtered(&mut self, pos: usize) -> Option<&DecoratorId> {
105        if self.idx < self.decorators.len() && self.decorators[self.idx].0 == pos {
106            self.idx += 1;
107            Some(&self.decorators[self.idx - 1].1)
108        } else {
109            None
110        }
111    }
112}
113
114impl<'a> Iterator for DecoratorIdIterator<'a> {
115    type Item = &'a DecoratorId;
116
117    fn next(&mut self) -> Option<Self::Item> {
118        if self.idx < self.decorators.len() {
119            self.idx += 1;
120            Some(&self.decorators[self.idx - 1].1)
121        } else {
122            None
123        }
124    }
125}
126
127impl<'a> ExactSizeIterator for DecoratorIdIterator<'a> {
128    fn len(&self) -> usize {
129        self.decorators.len() - self.idx
130    }
131}