miden_processor/host/
handlers.rs

1use alloc::{
2    boxed::Box,
3    collections::{BTreeMap, btree_map::Entry},
4    sync::Arc,
5    vec::Vec,
6};
7use core::{error::Error, fmt, fmt::Debug};
8
9use miden_core::{DebugOptions, EventId};
10
11use crate::{AdviceMutation, ExecutionError, ProcessState};
12
13// EVENT HANDLER TRAIT
14// ================================================================================================
15
16/// An [`EventHandler`] defines a function that that can be called from the processor which can
17/// read the VM state and modify the state of the advice provider.
18///
19/// A struct implementing this trait can access its own state, but any output it produces must
20/// be stored in the process's advice provider.
21pub trait EventHandler: Send + Sync + 'static {
22    /// Handles the event when triggered.
23    fn on_event(&self, process: &ProcessState) -> Result<Vec<AdviceMutation>, EventError>;
24}
25
26/// Default implementation for both free functions and closures with signature
27/// `fn(&ProcessState) -> Result<(), HandlerError>`
28impl<F> EventHandler for F
29where
30    F: for<'a> Fn(&'a ProcessState) -> Result<Vec<AdviceMutation>, EventError>
31        + Send
32        + Sync
33        + 'static,
34{
35    fn on_event(&self, process: &ProcessState) -> Result<Vec<AdviceMutation>, EventError> {
36        self(process)
37    }
38}
39
40/// A handler which ignores the process state and leaves the `AdviceProvider` unchanged.
41pub struct NoopEventHandler;
42
43impl EventHandler for NoopEventHandler {
44    fn on_event(&self, _process: &ProcessState) -> Result<Vec<AdviceMutation>, EventError> {
45        Ok(Vec::new())
46    }
47}
48
49// EVENT ERROR
50// ================================================================================================
51
52/// A generic [`Error`] wrapper allowing handlers to return errors to the Host caller.
53///
54/// Error handlers can define their own [`Error`] type which can be seamlessly converted
55/// into this type since it is a [`Box`].
56///
57/// # Example
58///
59/// ```rust, ignore
60/// pub struct MyError{ /* ... */ };
61///
62/// fn try_something() -> Result<(), MyError> { /* ... */ }
63///
64/// fn my_handler(process: &mut ProcessState) -> Result<(), HandlerError> {
65///     // ...
66///     try_something()?;
67///     // ...
68///     Ok(())
69/// }
70/// ```
71pub type EventError = Box<dyn Error + Send + Sync + 'static>;
72
73// EVENT HANDLER REGISTRY
74// ================================================================================================
75
76/// Registry for maintaining event handlers.
77///
78/// # Example
79///
80/// ```rust, ignore
81/// impl Host for MyHost {
82///     fn on_event(
83///         &mut self,
84///         process: &mut ProcessState,
85///         event_id: u32,
86///     ) -> Result<(), EventError> {
87///         if self
88///             .event_handlers
89///             .handle_event(event_id, process)
90///             .map_err(|err| EventError::HandlerError { id: event_id, err })?
91///         {
92///             // the event was handled by the registered event handlers; just return
93///             return Ok(());
94///         }
95///
96///         // implement custom event handling
97///
98///         Err(EventError::UnhandledEvent { id: event_id })
99///     }
100/// }
101/// ```
102#[derive(Default)]
103pub struct EventHandlerRegistry {
104    handlers: BTreeMap<EventId, Arc<dyn EventHandler>>,
105}
106
107impl EventHandlerRegistry {
108    pub fn new() -> Self {
109        Self { handlers: BTreeMap::new() }
110    }
111
112    /// Registers an [`EventHandler`] with a given identifier.
113    pub fn register(
114        &mut self,
115        id: EventId,
116        handler: Arc<dyn EventHandler>,
117    ) -> Result<(), ExecutionError> {
118        if id.is_reserved() {
119            return Err(ExecutionError::ReservedEventId { id });
120        }
121        match self.handlers.entry(id) {
122            Entry::Vacant(e) => e.insert(handler),
123            Entry::Occupied(_) => return Err(ExecutionError::DuplicateEventHandler { id }),
124        };
125        Ok(())
126    }
127
128    /// Unregisters a handler with the given identifier, returning a flag whether a handler with
129    /// that identifier was previously registered.
130    pub fn unregister(&mut self, id: EventId) -> bool {
131        self.handlers.remove(&id).is_some()
132    }
133
134    /// Handles the event if the registry contains a handler with the same identifier.
135    ///
136    /// Returns an `Option<_>` indicating whether the event was handled, wrapping resulting
137    /// mutations if any. Returns `None` if the event was not handled, if the event was handled
138    /// successfully `Some(mutations)` is returned, and if the handler returns an error, it is
139    /// propagated to the caller.
140    pub fn handle_event(
141        &self,
142        id: EventId,
143        process: &ProcessState,
144    ) -> Result<Option<Vec<AdviceMutation>>, EventError> {
145        if let Some(handler) = self.handlers.get(&id) {
146            return handler.on_event(process).map(Some);
147        }
148
149        Ok(None)
150    }
151}
152
153impl Debug for EventHandlerRegistry {
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        let keys: Vec<_> = self.handlers.keys().collect();
156        f.debug_struct("EventHandlerRegistry").field("handlers", &keys).finish()
157    }
158}
159
160// DEBUG HANDLER
161// ================================================================================================
162
163/// Handler for debug and trace operations
164pub trait DebugHandler: Sync {
165    /// This function is invoked when the `Debug` decorator is executed.
166    fn on_debug(
167        &mut self,
168        process: &ProcessState,
169        options: &DebugOptions,
170    ) -> Result<(), ExecutionError> {
171        let _ = (&process, options);
172        #[cfg(feature = "std")]
173        crate::host::debug::print_debug_info(process, options);
174        Ok(())
175    }
176
177    /// This function is invoked when the `Trace` decorator is executed.
178    fn on_trace(&mut self, process: &ProcessState, trace_id: u32) -> Result<(), ExecutionError> {
179        let _ = (&process, trace_id);
180        #[cfg(feature = "std")]
181        std::println!(
182            "Trace with id {} emitted at step {} in context {}",
183            trace_id,
184            process.clk(),
185            process.ctx()
186        );
187        Ok(())
188    }
189}