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, EventName, sys_events::SystemEvent};
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// DEBUG AND TRACE ERRORS
74// ================================================================================================
75
76/// A generic [`Error`] wrapper for debug handler errors.
77///
78/// Debug handlers can define their own [`Error`] type which can be seamlessly converted
79/// into this type since it is a [`Box`].
80pub type DebugError = Box<dyn Error + Send + Sync + 'static>;
81
82/// A generic [`Error`] wrapper for trace handler errors.
83///
84/// Trace handlers can define their own [`Error`] type which can be seamlessly converted
85/// into this type since it is a [`Box`].
86pub type TraceError = Box<dyn Error + Send + Sync + 'static>;
87
88/// A generic [`Error`] wrapper for assertion handler errors.
89///
90/// Assertion handlers can define their own [`Error`] type which can be seamlessly converted
91/// into this type since it is a [`Box`].
92pub type AssertError = Box<dyn Error + Send + Sync + 'static>;
93
94// EVENT HANDLER REGISTRY
95// ================================================================================================
96
97/// Registry for maintaining event handlers.
98///
99/// # Example
100///
101/// ```rust, ignore
102/// impl Host for MyHost {
103///     fn on_event(
104///         &mut self,
105///         process: &mut ProcessState,
106///         event_id: u32,
107///     ) -> Result<(), EventError> {
108///         if self
109///             .event_handlers
110///             .handle_event(event_id, process)
111///             .map_err(|err| EventError::HandlerError { id: event_id, err })?
112///         {
113///             // the event was handled by the registered event handlers; just return
114///             return Ok(());
115///         }
116///
117///         // implement custom event handling
118///
119///         Err(EventError::UnhandledEvent { id: event_id })
120///     }
121/// }
122/// ```
123#[derive(Default)]
124pub struct EventHandlerRegistry {
125    handlers: BTreeMap<EventId, (EventName, Arc<dyn EventHandler>)>,
126}
127
128impl EventHandlerRegistry {
129    pub fn new() -> Self {
130        Self { handlers: BTreeMap::new() }
131    }
132
133    /// Registers an [`EventHandler`] with a given event name.
134    ///
135    /// The [`EventId`] is computed from the event name during registration.
136    ///
137    /// # Errors
138    /// Returns an error if:
139    /// - The event is a reserved system event
140    /// - A handler with the same event ID is already registered
141    pub fn register(
142        &mut self,
143        event: EventName,
144        handler: Arc<dyn EventHandler>,
145    ) -> Result<(), ExecutionError> {
146        // Check if the event is a reserved system event
147        if SystemEvent::from_name(event.as_str()).is_some() {
148            return Err(ExecutionError::ReservedEventNamespace { event });
149        }
150
151        // Compute EventId from the event name
152        let id = event.to_event_id();
153        match self.handlers.entry(id) {
154            Entry::Vacant(e) => e.insert((event, handler)),
155            Entry::Occupied(_) => return Err(ExecutionError::DuplicateEventHandler { event }),
156        };
157        Ok(())
158    }
159
160    /// Unregisters a handler with the given identifier, returning a flag whether a handler with
161    /// that identifier was previously registered.
162    pub fn unregister(&mut self, id: EventId) -> bool {
163        self.handlers.remove(&id).is_some()
164    }
165
166    /// Returns the [`EventName`] registered for `id`, if any.
167    pub fn resolve_event(&self, id: EventId) -> Option<&EventName> {
168        self.handlers.get(&id).map(|(event, _)| event)
169    }
170
171    /// Handles the event if the registry contains a handler with the same identifier.
172    ///
173    /// Returns an `Option<_>` indicating whether the event was handled. Returns `None` if the
174    /// event was not handled, `Some(mutations)` if it was handled successfully, and propagates
175    /// handler errors to the caller.
176    pub fn handle_event(
177        &self,
178        id: EventId,
179        process: &ProcessState,
180    ) -> Result<Option<Vec<AdviceMutation>>, EventError> {
181        if let Some((_event_name, handler)) = self.handlers.get(&id) {
182            let mutations = handler.on_event(process)?;
183            return Ok(Some(mutations));
184        }
185
186        Ok(None)
187    }
188}
189
190impl Debug for EventHandlerRegistry {
191    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192        let events: Vec<_> = self.handlers.values().map(|(event, _)| event).collect();
193        f.debug_struct("EventHandlerRegistry").field("handlers", &events).finish()
194    }
195}
196
197// DEBUG HANDLER
198// ================================================================================================
199
200/// Handler for debug and trace operations
201pub trait DebugHandler: Sync {
202    /// This function is invoked when the `Debug` decorator is executed.
203    fn on_debug(
204        &mut self,
205        process: &ProcessState,
206        options: &DebugOptions,
207    ) -> Result<(), DebugError> {
208        let mut handler = crate::host::debug::DefaultDebugHandler::default();
209        handler.on_debug(process, options)
210    }
211
212    /// This function is invoked when the `Trace` decorator is executed.
213    fn on_trace(&mut self, process: &ProcessState, trace_id: u32) -> Result<(), TraceError> {
214        let _ = (&process, trace_id);
215        #[cfg(feature = "std")]
216        std::println!(
217            "Trace with id {} emitted at step {} in context {}",
218            trace_id,
219            process.clk(),
220            process.ctx()
221        );
222        Ok(())
223    }
224}