miden_processor/host/
default.rs

1use alloc::{sync::Arc, vec::Vec};
2
3use miden_core::{DebugOptions, EventId, 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    /// Registers 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 register_handler(
82        &mut self,
83        id: EventId,
84        handler: Arc<dyn EventHandler>,
85    ) -> Result<(), ExecutionError> {
86        self.event_handlers.register(id, handler)
87    }
88
89    /// Un-registers a handler with the given id, returning a flag indicating whether a handler
90    /// was previously registered with this id.
91    pub fn unregister_handler(&mut self, id: EventId) -> 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: EventId, handler: Arc<dyn EventHandler>) -> bool {
98        let existed = self.event_handlers.unregister(id);
99        self.register_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_label_and_source_file(
120        &self,
121        location: &Location,
122    ) -> (SourceSpan, Option<Arc<SourceFile>>) {
123        let maybe_file = self.source_manager.get_by_uri(location.uri());
124        let span = self.source_manager.location_to_span(location.clone()).unwrap_or_default();
125        (span, maybe_file)
126    }
127
128    fn on_debug(
129        &mut self,
130        process: &mut ProcessState,
131        options: &DebugOptions,
132    ) -> Result<(), ExecutionError> {
133        self.debug_handler.on_debug(process, options)
134    }
135
136    fn on_trace(
137        &mut self,
138        process: &mut ProcessState,
139        trace_id: u32,
140    ) -> Result<(), ExecutionError> {
141        self.debug_handler.on_trace(process, trace_id)
142    }
143
144    /// Handles the failure of the assertion instruction.
145    fn on_assert_failed(&mut self, _process: &ProcessState, _err_code: Felt) {}
146}
147
148impl<D, S> SyncHost for DefaultHost<D, S>
149where
150    D: DebugHandler,
151    S: SourceManager,
152{
153    fn get_mast_forest(&self, node_digest: &Word) -> Option<Arc<MastForest>> {
154        self.store.get(node_digest)
155    }
156
157    fn on_event(&mut self, process: &ProcessState) -> Result<Vec<AdviceMutation>, EventError> {
158        let event_id = EventId::from_felt(process.get_stack_item(0));
159        if let Some(mutations) = self.event_handlers.handle_event(event_id, process)? {
160            // the event was handled by the registered event handlers; just return
161            return Ok(mutations);
162        }
163
164        // EventError is a `Box` so we can define the error anonymously.
165        #[derive(Debug, thiserror::Error)]
166        #[error("no event handler was registered with given id")]
167        struct UnhandledEvent;
168
169        Err(UnhandledEvent.into())
170    }
171}
172
173impl<D, S> AsyncHost for DefaultHost<D, S>
174where
175    D: DebugHandler,
176    S: SourceManagerSync,
177{
178    fn get_mast_forest(&self, node_digest: &Word) -> impl FutureMaybeSend<Option<Arc<MastForest>>> {
179        let result = <Self as SyncHost>::get_mast_forest(self, node_digest);
180        async move { result }
181    }
182
183    fn on_event(
184        &mut self,
185        process: &ProcessState<'_>,
186    ) -> impl FutureMaybeSend<Result<Vec<AdviceMutation>, EventError>> {
187        let result = <Self as SyncHost>::on_event(self, process);
188        async move { result }
189    }
190}
191
192// HOST LIBRARY
193// ================================================================================================
194
195/// A rich library representing a [`MastForest`] which also exports
196/// a list of handlers for events it may call.
197#[derive(Default)]
198pub struct HostLibrary {
199    /// A `MastForest` with procedures exposed by this library.
200    pub mast_forest: Arc<MastForest>,
201    /// List of handlers along with an event id to call them with `emit`.
202    pub handlers: Vec<(EventId, Arc<dyn EventHandler>)>,
203}
204
205impl From<Arc<MastForest>> for HostLibrary {
206    fn from(mast_forest: Arc<MastForest>) -> Self {
207        Self { mast_forest, handlers: vec![] }
208    }
209}
210
211impl From<&Arc<MastForest>> for HostLibrary {
212    fn from(mast_forest: &Arc<MastForest>) -> Self {
213        Self {
214            mast_forest: mast_forest.clone(),
215            handlers: vec![],
216        }
217    }
218}
219
220// DEFAULT DEBUG HANDLER IMPLEMENTATION
221// ================================================================================================
222
223/// Concrete [`DebugHandler`] which re-uses the default `on_debug` and `on_trace` implementations.
224#[derive(Clone, Default)]
225pub struct DefaultDebugHandler;
226
227impl DebugHandler for DefaultDebugHandler {}