miden_processor/host/
default.rs

1use alloc::{boxed::Box, sync::Arc, vec::Vec};
2
3use miden_core::{DebugOptions, Felt, Word, mast::MastForest};
4use miden_debug_types::{
5    DefaultSourceManager, Location, SourceFile, SourceManager, SourceManagerSync, SourceSpan,
6};
7
8use crate::{
9    AdviceMutation, AsyncHost, BaseHost, DebugHandler, EventHandler, EventHandlerRegistry,
10    ExecutionError, MastForestStore, MemMastForestStore, ProcessState, SyncHost,
11    host::{EventError, FutureMaybeSend},
12};
13
14// DEFAULT HOST IMPLEMENTATION
15// ================================================================================================
16
17/// A default Host implementation that provides the essential functionality required by the VM.
18#[derive(Debug)]
19pub struct DefaultHost<
20    D: DebugHandler = DefaultDebugHandler,
21    S: SourceManager = DefaultSourceManager,
22> {
23    store: MemMastForestStore,
24    event_handlers: EventHandlerRegistry,
25    debug_handler: D,
26    source_manager: Arc<S>,
27}
28
29impl Default for DefaultHost {
30    fn default() -> Self {
31        Self {
32            store: MemMastForestStore::default(),
33            event_handlers: EventHandlerRegistry::default(),
34            debug_handler: DefaultDebugHandler,
35            source_manager: Arc::new(DefaultSourceManager::default()),
36        }
37    }
38}
39
40impl<D, S> DefaultHost<D, S>
41where
42    D: DebugHandler,
43    S: SourceManager,
44{
45    /// Use the given source manager implementation instead of the default one
46    /// [`DefaultSourceManager`].
47    pub fn with_source_manager<O>(self, source_manager: Arc<O>) -> DefaultHost<D, O>
48    where
49        O: SourceManager,
50    {
51        DefaultHost::<D, O> {
52            store: self.store,
53            event_handlers: self.event_handlers,
54            debug_handler: self.debug_handler,
55            source_manager,
56        }
57    }
58
59    /// Loads a [`HostLibrary`] containing a [`MastForest`] with its list of event handlers.
60    pub fn load_library(&mut self, library: impl Into<HostLibrary>) -> Result<(), ExecutionError> {
61        let library = library.into();
62        self.store.insert(library.mast_forest);
63
64        for (id, handler) in library.handlers {
65            self.event_handlers.register(id, handler)?;
66        }
67        Ok(())
68    }
69
70    /// Adds a [`HostLibrary`] containing a [`MastForest`] with its list of event handlers.
71    /// to the host.
72    pub fn with_library(mut self, library: impl Into<HostLibrary>) -> Result<Self, ExecutionError> {
73        self.load_library(library)?;
74        Ok(self)
75    }
76
77    /// Loads a single [`EventHandler`] into this host.
78    ///
79    /// The handler can be either a closure or a free function with signature
80    /// `fn(&mut ProcessState) -> Result<(), EventHandler>`
81    pub fn load_handler(
82        &mut self,
83        id: u32,
84        handler: impl EventHandler,
85    ) -> Result<(), ExecutionError> {
86        self.event_handlers.register(id, Box::new(handler))
87    }
88
89    /// Unload a handler with the given id, returning a flag indicating whether a handler
90    /// was previously registered with this id.
91    pub fn unload_handler(&mut self, id: u32) -> bool {
92        self.event_handlers.unregister(id)
93    }
94
95    /// Replaces a handler with the given id, returning a flag indicating whether a handler
96    /// was previously registered with this id.
97    pub fn replace_handler(&mut self, id: u32, handler: impl EventHandler) -> bool {
98        let existed = self.event_handlers.unregister(id);
99        self.load_handler(id, handler).unwrap();
100        existed
101    }
102
103    /// Replace the current [`DebugHandler`] with a custom one.
104    pub fn with_debug_handler<H: DebugHandler>(self, handler: H) -> DefaultHost<H, S> {
105        DefaultHost::<H, S> {
106            store: self.store,
107            event_handlers: self.event_handlers,
108            debug_handler: handler,
109            source_manager: self.source_manager,
110        }
111    }
112}
113
114impl<D, S> BaseHost for DefaultHost<D, S>
115where
116    D: DebugHandler,
117    S: SourceManager,
118{
119    fn get_mast_forest(&self, node_digest: &Word) -> Option<Arc<MastForest>> {
120        self.store.get(node_digest)
121    }
122
123    fn get_label_and_source_file(
124        &self,
125        location: &Location,
126    ) -> (SourceSpan, Option<Arc<SourceFile>>) {
127        let maybe_file = self.source_manager.get_by_uri(location.uri());
128        let span = self.source_manager.location_to_span(location.clone()).unwrap_or_default();
129        (span, maybe_file)
130    }
131
132    fn on_debug(
133        &mut self,
134        process: &mut ProcessState,
135        options: &DebugOptions,
136    ) -> Result<(), ExecutionError> {
137        self.debug_handler.on_debug(process, options)
138    }
139
140    fn on_trace(
141        &mut self,
142        process: &mut ProcessState,
143        trace_id: u32,
144    ) -> Result<(), ExecutionError> {
145        self.debug_handler.on_trace(process, trace_id)
146    }
147
148    /// Handles the failure of the assertion instruction.
149    fn on_assert_failed(&mut self, _process: &ProcessState, _err_code: Felt) {}
150}
151
152impl<D, S> SyncHost for DefaultHost<D, S>
153where
154    D: DebugHandler,
155    S: SourceManager,
156{
157    fn on_event(
158        &mut self,
159        process: &ProcessState,
160        event_id: u32,
161    ) -> Result<Vec<AdviceMutation>, EventError> {
162        if let Some(mutations) = self.event_handlers.handle_event(event_id, process)? {
163            // the event was handled by the registered event handlers; just return
164            return Ok(mutations);
165        }
166
167        // EventError is a `Box` so we can define the error anonymously.
168        #[derive(Debug, thiserror::Error)]
169        #[error("no event handler was registered with given id")]
170        struct UnhandledEvent;
171
172        Err(UnhandledEvent.into())
173    }
174}
175
176impl<D, S> AsyncHost for DefaultHost<D, S>
177where
178    D: DebugHandler,
179    S: SourceManagerSync,
180{
181    fn on_event(
182        &mut self,
183        process: &ProcessState<'_>,
184        event_id: u32,
185    ) -> impl FutureMaybeSend<Result<Vec<AdviceMutation>, EventError>> {
186        let result = <Self as SyncHost>::on_event(self, process, event_id);
187        async move { result }
188    }
189}
190
191// HOST LIBRARY
192// ================================================================================================
193
194/// A rich library representing a [`MastForest`] which also exports
195/// a list of handlers for events it may call.
196#[derive(Default)]
197pub struct HostLibrary {
198    /// A `MastForest` with procedures exposed by this library.
199    pub mast_forest: Arc<MastForest>,
200    /// List of handlers along with an event id to call them with `emit`.
201    pub handlers: Vec<(u32, Box<dyn EventHandler>)>,
202}
203
204impl From<Arc<MastForest>> for HostLibrary {
205    fn from(mast_forest: Arc<MastForest>) -> Self {
206        Self { mast_forest, handlers: vec![] }
207    }
208}
209
210impl From<&Arc<MastForest>> for HostLibrary {
211    fn from(mast_forest: &Arc<MastForest>) -> Self {
212        Self {
213            mast_forest: mast_forest.clone(),
214            handlers: vec![],
215        }
216    }
217}
218
219// DEFAULT DEBUG HANDLER IMPLEMENTATION
220// ================================================================================================
221
222/// Concrete [`DebugHandler`] which re-uses the default `on_debug` and `on_trace` implementations.
223#[derive(Clone, Default)]
224pub struct DefaultDebugHandler;
225
226impl DebugHandler for DefaultDebugHandler {}