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    operations::DebugOptions,
8};
9use miden_debug_types::{DefaultSourceManager, Location, SourceFile, SourceManager, SourceSpan};
10
11use super::{
12    debug::DefaultDebugHandler,
13    handlers::{EventError, EventHandler, EventHandlerRegistry},
14};
15use crate::{
16    BaseHost, DebugError, DebugHandler, ExecutionError, MastForestStore, MemMastForestStore,
17    ProcessorState, SyncHost, TraceError, advice::AdviceMutation,
18};
19
20// DEFAULT HOST IMPLEMENTATION
21// ================================================================================================
22
23/// A default SyncHost implementation that provides the essential functionality required by the VM.
24#[derive(Debug)]
25pub struct DefaultHost<
26    D: DebugHandler = DefaultDebugHandler,
27    S: SourceManager = DefaultSourceManager,
28> {
29    store: MemMastForestStore,
30    event_handlers: EventHandlerRegistry,
31    debug_handler: D,
32    source_manager: Arc<S>,
33}
34
35impl Default for DefaultHost {
36    fn default() -> Self {
37        Self {
38            store: MemMastForestStore::default(),
39            event_handlers: EventHandlerRegistry::default(),
40            debug_handler: DefaultDebugHandler::default(),
41            source_manager: Arc::new(DefaultSourceManager::default()),
42        }
43    }
44}
45
46impl<D, S> DefaultHost<D, S>
47where
48    D: DebugHandler,
49    S: SourceManager,
50{
51    /// Use the given source manager implementation instead of the default one
52    /// [`DefaultSourceManager`].
53    pub fn with_source_manager<O>(self, source_manager: Arc<O>) -> DefaultHost<D, O>
54    where
55        O: SourceManager,
56    {
57        DefaultHost::<D, O> {
58            store: self.store,
59            event_handlers: self.event_handlers,
60            debug_handler: self.debug_handler,
61            source_manager,
62        }
63    }
64
65    /// Loads a [`HostLibrary`] containing a [`MastForest`] with its list of event handlers.
66    pub fn load_library(&mut self, library: impl Into<HostLibrary>) -> Result<(), ExecutionError> {
67        let library = library.into();
68        self.store.insert(library.mast_forest);
69
70        for (event, handler) in library.handlers {
71            self.event_handlers.register(event, handler)?;
72        }
73        Ok(())
74    }
75
76    /// Adds a [`HostLibrary`] containing a [`MastForest`] with its list of event handlers.
77    /// to the host.
78    pub fn with_library(mut self, library: impl Into<HostLibrary>) -> Result<Self, ExecutionError> {
79        self.load_library(library)?;
80        Ok(self)
81    }
82
83    /// Registers a single [`EventHandler`] into this host.
84    ///
85    /// The handler can be either a closure or a free function with signature
86    /// `fn(&mut ProcessorState) -> Result<(), EventHandler>`
87    pub fn register_handler(
88        &mut self,
89        event: EventName,
90        handler: Arc<dyn EventHandler>,
91    ) -> Result<(), ExecutionError> {
92        self.event_handlers.register(event, handler)
93    }
94
95    /// Un-registers a handler with the given id, returning a flag indicating whether a handler
96    /// was previously registered with this id.
97    pub fn unregister_handler(&mut self, id: EventId) -> bool {
98        self.event_handlers.unregister(id)
99    }
100
101    /// Replaces a handler with the given event, returning a flag indicating whether a handler
102    /// was previously registered with this event ID.
103    pub fn replace_handler(&mut self, event: EventName, handler: Arc<dyn EventHandler>) -> bool {
104        let event_id = event.to_event_id();
105        let existed = self.event_handlers.unregister(event_id);
106        self.register_handler(event, handler).unwrap();
107        existed
108    }
109
110    /// Replace the current [`DebugHandler`] with a custom one.
111    pub fn with_debug_handler<H: DebugHandler>(self, handler: H) -> DefaultHost<H, S> {
112        DefaultHost::<H, S> {
113            store: self.store,
114            event_handlers: self.event_handlers,
115            debug_handler: handler,
116            source_manager: self.source_manager,
117        }
118    }
119
120    /// Returns a reference to the [`DebugHandler`], useful for recovering debug information
121    /// emitted during a program execution.
122    pub fn debug_handler(&self) -> &D {
123        &self.debug_handler
124    }
125}
126
127impl<D, S> BaseHost for DefaultHost<D, S>
128where
129    D: DebugHandler,
130    S: SourceManager,
131{
132    fn get_label_and_source_file(
133        &self,
134        location: &Location,
135    ) -> (SourceSpan, Option<Arc<SourceFile>>) {
136        let maybe_file = self.source_manager.get_by_uri(location.uri());
137        let span = self.source_manager.location_to_span(location.clone()).unwrap_or_default();
138        (span, maybe_file)
139    }
140
141    fn on_debug(
142        &mut self,
143        process: &ProcessorState,
144        options: &DebugOptions,
145    ) -> Result<(), DebugError> {
146        self.debug_handler.on_debug(process, options)
147    }
148
149    fn on_trace(&mut self, process: &ProcessorState, trace_id: u32) -> Result<(), TraceError> {
150        self.debug_handler.on_trace(process, trace_id)
151    }
152
153    fn resolve_event(&self, event_id: EventId) -> Option<&EventName> {
154        self.event_handlers.resolve_event(event_id)
155    }
156}
157
158impl<D, S> SyncHost for DefaultHost<D, S>
159where
160    D: DebugHandler,
161    S: SourceManager,
162{
163    fn get_mast_forest(&self, node_digest: &Word) -> Option<Arc<MastForest>> {
164        self.store.get(node_digest)
165    }
166
167    fn on_event(
168        &mut self,
169        process: &ProcessorState<'_>,
170    ) -> Result<Vec<AdviceMutation>, EventError> {
171        let event_id = EventId::from_felt(process.get_stack_item(0));
172        match self.event_handlers.handle_event(event_id, process) {
173            Ok(Some(mutations)) => Ok(mutations),
174            Ok(None) => {
175                #[derive(Debug, thiserror::Error)]
176                #[error("no event handler registered")]
177                struct UnhandledEvent;
178
179                Err(UnhandledEvent.into())
180            },
181            Err(e) => Err(e),
182        }
183    }
184}
185
186// NOOPHOST
187// ================================================================================================
188
189/// A SyncHost which does nothing.
190pub struct NoopHost;
191
192impl BaseHost for NoopHost {
193    #[inline(always)]
194    fn get_label_and_source_file(
195        &self,
196        _location: &Location,
197    ) -> (SourceSpan, Option<Arc<SourceFile>>) {
198        (SourceSpan::UNKNOWN, None)
199    }
200}
201
202impl SyncHost for NoopHost {
203    #[inline(always)]
204    fn get_mast_forest(&self, _node_digest: &Word) -> Option<Arc<MastForest>> {
205        None
206    }
207
208    #[inline(always)]
209    fn on_event(
210        &mut self,
211        _process: &ProcessorState<'_>,
212    ) -> Result<Vec<AdviceMutation>, EventError> {
213        Ok(Vec::new())
214    }
215}
216
217// HOST LIBRARY
218// ================================================================================================
219
220/// A rich library representing a [`MastForest`] which also exports
221/// a list of handlers for events it may call.
222#[derive(Default)]
223pub struct HostLibrary {
224    /// A `MastForest` with procedures exposed by this library.
225    pub mast_forest: Arc<MastForest>,
226    /// List of handlers along with their event names to call them with `emit`.
227    pub handlers: Vec<(EventName, Arc<dyn EventHandler>)>,
228}
229
230impl From<Arc<MastForest>> for HostLibrary {
231    fn from(mast_forest: Arc<MastForest>) -> Self {
232        Self { mast_forest, handlers: vec![] }
233    }
234}
235
236impl From<&Arc<MastForest>> for HostLibrary {
237    fn from(mast_forest: &Arc<MastForest>) -> Self {
238        Self {
239            mast_forest: mast_forest.clone(),
240            handlers: vec![],
241        }
242    }
243}