Skip to main content

miden_processor/host/
default.rs

1use alloc::{sync::Arc, vec::Vec};
2
3use miden_core::{
4    Word,
5    events::{EventId, EventName},
6    mast::MastForest,
7};
8use miden_debug_types::{DefaultSourceManager, Location, SourceFile, SourceManager, SourceSpan};
9use miden_mast_package::{PackageDebugInfoError, debug_info::PackageDebugInfo};
10
11use super::handlers::{
12    EventError, EventHandler, EventHandlerRegistry, TraceError, TraceHandler, TraceHandlerRegistry,
13};
14use crate::{
15    BaseHost, ExecutionError, LoadedMastForest, MastForestStore, MemMastForestStore,
16    ProcessorState, SyncHost, advice::AdviceMutation,
17};
18
19// DEFAULT HOST IMPLEMENTATION
20// ================================================================================================
21
22/// A default SyncHost implementation that provides the essential functionality required by the VM.
23#[derive(Debug)]
24pub struct DefaultHost<S: SourceManager = DefaultSourceManager> {
25    store: MemMastForestStore,
26    event_handlers: EventHandlerRegistry,
27    trace_handlers: TraceHandlerRegistry,
28    source_manager: Arc<S>,
29}
30
31impl Default for DefaultHost {
32    fn default() -> Self {
33        Self {
34            store: MemMastForestStore::default(),
35            event_handlers: EventHandlerRegistry::default(),
36            trace_handlers: TraceHandlerRegistry::default(),
37            source_manager: Arc::new(DefaultSourceManager::default()),
38        }
39    }
40}
41
42impl<S> DefaultHost<S>
43where
44    S: SourceManager,
45{
46    /// Use the given source manager implementation instead of the default one
47    /// [`DefaultSourceManager`].
48    pub fn with_source_manager<O>(self, source_manager: Arc<O>) -> DefaultHost<O>
49    where
50        O: SourceManager,
51    {
52        DefaultHost::<O> {
53            store: self.store,
54            event_handlers: self.event_handlers,
55            trace_handlers: self.trace_handlers,
56            source_manager,
57        }
58    }
59
60    /// Loads a [`HostLibrary`] containing a [`MastForest`] with its list of event handlers.
61    pub fn load_library(&mut self, library: impl Into<HostLibrary>) -> Result<(), ExecutionError> {
62        let library = library.into();
63        self.store.insert_loaded(LoadedMastForest::with_package_debug_info(
64            library.mast_forest,
65            library.package_debug_info,
66        ));
67
68        for (event, handler) in library.handlers {
69            self.event_handlers.register(event, handler)?;
70        }
71        Ok(())
72    }
73
74    /// Adds a [`HostLibrary`] containing a [`MastForest`] with its list of event handlers.
75    /// to the host.
76    pub fn with_library(mut self, library: impl Into<HostLibrary>) -> Result<Self, ExecutionError> {
77        self.load_library(library)?;
78        Ok(self)
79    }
80
81    /// Registers a single [`EventHandler`] into this host.
82    ///
83    /// The handler can be either a closure or a free function with signature
84    /// `fn(&mut ProcessorState) -> Result<(), EventHandler>`
85    pub fn register_handler(
86        &mut self,
87        event: EventName,
88        handler: Arc<dyn EventHandler>,
89    ) -> Result<(), ExecutionError> {
90        self.event_handlers.register(event, handler)
91    }
92
93    /// Un-registers a handler with the given id, returning a flag indicating whether a handler
94    /// was previously registered with this id.
95    pub fn unregister_handler(&mut self, id: EventId) -> bool {
96        self.event_handlers.unregister(id)
97    }
98
99    /// Replaces a handler with the given event, returning a flag indicating whether a handler
100    /// was previously registered with this event ID.
101    pub fn replace_handler(&mut self, event: EventName, handler: Arc<dyn EventHandler>) -> bool {
102        let event_id = event.to_event_id();
103        let existed = self.event_handlers.unregister(event_id);
104        self.register_handler(event, handler).unwrap();
105        existed
106    }
107
108    /// Registers a single [`TraceHandler`] into this host.
109    ///
110    /// Trace handlers observe VM state for optional, read-only trace events; they cannot mutate the
111    /// advice provider. Unhandled trace event IDs are ignored. The handler can be either a closure
112    /// or a free function.
113    pub fn register_trace_handler(
114        &mut self,
115        event: EventName,
116        handler: Arc<dyn TraceHandler>,
117    ) -> Result<(), ExecutionError> {
118        self.trace_handlers.register(event, handler)
119    }
120
121    /// Un-registers a trace handler with the given id, returning a flag indicating whether a
122    /// handler was previously registered with this id.
123    pub fn unregister_trace_handler(&mut self, id: EventId) -> bool {
124        self.trace_handlers.unregister(id)
125    }
126
127    /// Replaces a trace handler with the given event, returning a flag indicating whether a
128    /// handler was previously registered with this event ID.
129    pub fn replace_trace_handler(
130        &mut self,
131        event: EventName,
132        handler: Arc<dyn TraceHandler>,
133    ) -> bool {
134        let event_id = event.to_event_id();
135        let existed = self.trace_handlers.unregister(event_id);
136        self.register_trace_handler(event, handler).unwrap();
137        existed
138    }
139}
140
141impl<S> BaseHost for DefaultHost<S>
142where
143    S: SourceManager,
144{
145    fn get_label_and_source_file(
146        &self,
147        location: &Location,
148    ) -> (SourceSpan, Option<Arc<SourceFile>>) {
149        let maybe_file = self.source_manager.get_by_uri(location.uri());
150        let span = self.source_manager.location_to_span(location.clone()).unwrap_or_default();
151        (span, maybe_file)
152    }
153
154    fn resolve_event(&self, event_id: EventId) -> Option<&EventName> {
155        self.event_handlers.resolve_event(event_id)
156    }
157
158    fn resolve_trace(&self, trace_id: EventId) -> Option<&EventName> {
159        self.trace_handlers.resolve_trace(trace_id)
160    }
161}
162
163impl<S> SyncHost for DefaultHost<S>
164where
165    S: SourceManager,
166{
167    fn get_mast_forest(&self, node_digest: &Word) -> Option<LoadedMastForest> {
168        self.store.get(node_digest)
169    }
170
171    fn on_event(
172        &mut self,
173        process: &ProcessorState<'_>,
174    ) -> Result<Vec<AdviceMutation>, EventError> {
175        let event_id = EventId::from_felt(process.get_stack_item(0));
176        match self.event_handlers.handle_event(event_id, process) {
177            Ok(Some(mutations)) => Ok(mutations),
178            Ok(None) => {
179                #[derive(Debug, thiserror::Error)]
180                #[error("no event handler registered")]
181                struct UnhandledEvent;
182
183                Err(UnhandledEvent.into())
184            },
185            Err(e) => Err(e),
186        }
187    }
188
189    fn on_trace(&mut self, process: &ProcessorState<'_>) -> Result<(), TraceError> {
190        // The trace id sits one below the `SystemEvent::TraceEvent` id.
191        let trace_id = EventId::from_felt(process.get_stack_item(1));
192        match self.trace_handlers.handle_trace(trace_id, process) {
193            Ok(Some(())) => Ok(()),
194            // Traces are optional/readonly, so an unhandled trace is not an error.
195            Ok(None) => Ok(()),
196            Err(e) => Err(e),
197        }
198    }
199}
200
201// NOOPHOST
202// ================================================================================================
203
204/// A SyncHost which does nothing.
205pub struct NoopHost;
206
207impl BaseHost for NoopHost {
208    #[inline(always)]
209    fn get_label_and_source_file(
210        &self,
211        _location: &Location,
212    ) -> (SourceSpan, Option<Arc<SourceFile>>) {
213        (SourceSpan::UNKNOWN, None)
214    }
215}
216
217impl SyncHost for NoopHost {
218    #[inline(always)]
219    fn get_mast_forest(&self, _node_digest: &Word) -> Option<LoadedMastForest> {
220        None
221    }
222
223    #[inline(always)]
224    fn on_event(
225        &mut self,
226        _process: &ProcessorState<'_>,
227    ) -> Result<Vec<AdviceMutation>, EventError> {
228        Ok(Vec::new())
229    }
230}
231
232// HOST LIBRARY
233// ================================================================================================
234
235/// A rich library representing a [`MastForest`] which also exports
236/// a list of handlers for events it may call.
237pub struct HostLibrary {
238    /// A `MastForest` with procedures exposed by this library.
239    pub mast_forest: Arc<MastForest>,
240    /// Package-owned debug info that belongs to `mast_forest`.
241    pub package_debug_info: Result<Option<PackageDebugInfo>, PackageDebugInfoError>,
242    /// List of handlers along with their event names to call them with `emit`.
243    pub handlers: Vec<(EventName, Arc<dyn EventHandler>)>,
244}
245
246impl Default for HostLibrary {
247    fn default() -> Self {
248        Self {
249            mast_forest: Arc::new(MastForest::new()),
250            package_debug_info: Ok(None),
251            handlers: Vec::new(),
252        }
253    }
254}
255
256impl From<Arc<miden_mast_package::Package>> for HostLibrary {
257    fn from(package: Arc<miden_mast_package::Package>) -> Self {
258        let package_debug_info = match package.debug_info() {
259            Ok(debug_info) => Ok(debug_info),
260            Err(PackageDebugInfoError::UntrustedSections) => Ok(None),
261            Err(err) => Err(err),
262        };
263        Self {
264            mast_forest: package.mast_forest().clone(),
265            package_debug_info,
266            handlers: vec![],
267        }
268    }
269}
270
271impl From<Arc<MastForest>> for HostLibrary {
272    fn from(mast_forest: Arc<MastForest>) -> Self {
273        Self {
274            mast_forest,
275            package_debug_info: Ok(None),
276            handlers: vec![],
277        }
278    }
279}
280
281impl From<&Arc<MastForest>> for HostLibrary {
282    fn from(mast_forest: &Arc<MastForest>) -> Self {
283        Self {
284            mast_forest: mast_forest.clone(),
285            package_debug_info: Ok(None),
286            handlers: vec![],
287        }
288    }
289}