miden_processor/host/
handlers.rs

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