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// 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, (EventName, 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 event name.
113 ///
114 /// The [`EventId`] is computed from the event name during registration.
115 ///
116 /// # Errors
117 /// Returns an error if:
118 /// - The event is a reserved system event
119 /// - A handler with the same event ID is already registered
120 pub fn register(
121 &mut self,
122 event: EventName,
123 handler: Arc<dyn EventHandler>,
124 ) -> Result<(), ExecutionError> {
125 // Check if the event is a reserved system event
126 if SystemEvent::from_name(event.as_str()).is_some() {
127 return Err(ExecutionError::ReservedEventNamespace { event });
128 }
129
130 // Compute EventId from the event name
131 let id = event.to_event_id();
132 match self.handlers.entry(id) {
133 Entry::Vacant(e) => e.insert((event, handler)),
134 Entry::Occupied(_) => return Err(ExecutionError::DuplicateEventHandler { event }),
135 };
136 Ok(())
137 }
138
139 /// Unregisters a handler with the given identifier, returning a flag whether a handler with
140 /// that identifier was previously registered.
141 pub fn unregister(&mut self, id: EventId) -> bool {
142 self.handlers.remove(&id).is_some()
143 }
144
145 /// Returns the [`EventName`] registered for `id`, if any.
146 pub fn resolve_event(&self, id: EventId) -> Option<&EventName> {
147 self.handlers.get(&id).map(|(event, _)| event)
148 }
149
150 /// Handles the event if the registry contains a handler with the same identifier.
151 ///
152 /// Returns an `Option<_>` indicating whether the event was handled. Returns `None` if the
153 /// event was not handled, `Some(mutations)` if it was handled successfully, and propagates
154 /// handler errors to the caller.
155 pub fn handle_event(
156 &self,
157 id: EventId,
158 process: &ProcessState,
159 ) -> Result<Option<Vec<AdviceMutation>>, EventError> {
160 if let Some((_event_name, handler)) = self.handlers.get(&id) {
161 let mutations = handler.on_event(process)?;
162 return Ok(Some(mutations));
163 }
164
165 Ok(None)
166 }
167}
168
169impl Debug for EventHandlerRegistry {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 let events: Vec<_> = self.handlers.values().map(|(event, _)| event).collect();
172 f.debug_struct("EventHandlerRegistry").field("handlers", &events).finish()
173 }
174}
175
176// DEBUG HANDLER
177// ================================================================================================
178
179/// Handler for debug and trace operations
180pub trait DebugHandler: Sync {
181 /// This function is invoked when the `Debug` decorator is executed.
182 fn on_debug(
183 &mut self,
184 process: &ProcessState,
185 options: &DebugOptions,
186 ) -> Result<(), ExecutionError> {
187 let mut handler = crate::host::debug::DefaultDebugHandler::default();
188 handler.on_debug(process, options)
189 }
190
191 /// This function is invoked when the `Trace` decorator is executed.
192 fn on_trace(&mut self, process: &ProcessState, trace_id: u32) -> Result<(), ExecutionError> {
193 let _ = (&process, trace_id);
194 #[cfg(feature = "std")]
195 std::println!(
196 "Trace with id {} emitted at step {} in context {}",
197 trace_id,
198 process.clk(),
199 process.ctx()
200 );
201 Ok(())
202 }
203}