Skip to main content

miden_debug_engine/exec/
event.rs

1//! This module contains the set of compiler-emitted event codes, and their explanations
2use std::sync::LazyLock;
3
4use miden_core::events::{EventId, EventName};
5
6/// This event indicates that a procedure call frame is entered
7pub const FRAME_START_EVENT: EventName = EventName::new("readonly::miden_debug::frame_start");
8static FRAME_START_EVENT_ID: LazyLock<EventId> = LazyLock::new(|| FRAME_START_EVENT.to_event_id());
9
10/// This event indicates that a procedure call frame is exited
11pub const FRAME_END_EVENT: EventName = EventName::new("readonly::miden_debug::frame_end");
12static FRAME_END_EVENT_ID: LazyLock<EventId> = LazyLock::new(|| FRAME_END_EVENT.to_event_id());
13
14/// This event indicates that a line should be printed.
15///
16/// The bytes representing the string are expected in memory. The executor reads the start address
17/// and length from the operand stack.
18///
19/// The decoded string is emitted through the [`log`] infra at `Info` level on the `stdout`
20/// target.
21pub const PRINTLN_EVENT: EventName = EventName::new("readonly::miden_debug::println");
22static PRINTLN_EVENT_ID: LazyLock<EventId> = LazyLock::new(|| PRINTLN_EVENT.to_event_id());
23
24/// A typed wrapper around the raw trace events known to the compiler
25#[derive(Debug, Clone)]
26#[repr(u32)]
27pub enum Event {
28    FrameStart,
29    FrameEnd,
30    PrintLn,
31    UserDefined(EventName),
32    Unknown(EventId),
33}
34
35impl std::hash::Hash for Event {
36    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
37        self.as_event_id().hash(state);
38    }
39}
40
41impl Eq for Event {}
42
43impl PartialEq for Event {
44    fn eq(&self, other: &Self) -> bool {
45        self.as_event_id() == other.as_event_id()
46    }
47}
48
49impl PartialOrd for Event {
50    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
51        Some(self.cmp(other))
52    }
53}
54
55impl Ord for Event {
56    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
57        use std::cmp::Ordering;
58        if self.as_event_id() == other.as_event_id() {
59            return Ordering::Equal;
60        }
61        match (self, other) {
62            (Self::Unknown(a), Self::Unknown(b)) => a.cmp(b),
63            (Self::Unknown(_), _) => Ordering::Greater,
64            (_, Self::Unknown(_)) => Ordering::Less,
65            (a, b) => a.as_event_name().unwrap().as_str().cmp(b.as_event_name().unwrap().as_str()),
66        }
67    }
68}
69
70impl Event {
71    #[inline(always)]
72    pub fn is_frame_start(&self) -> bool {
73        matches!(self, Self::FrameStart)
74    }
75
76    #[inline(always)]
77    pub fn is_frame_end(&self) -> bool {
78        matches!(self, Self::FrameEnd)
79    }
80
81    pub fn as_event_id(&self) -> EventId {
82        match self {
83            Self::FrameStart => *FRAME_START_EVENT_ID,
84            Self::FrameEnd => *FRAME_END_EVENT_ID,
85            Self::PrintLn => *PRINTLN_EVENT_ID,
86            Self::UserDefined(event) => event.to_event_id(),
87            Self::Unknown(event) => *event,
88        }
89    }
90
91    /// Get the [EventName] corresponding to this event
92    ///
93    /// Returns `None` if the name is unknown/requires lookup in the set of registered events
94    pub fn as_event_name(&self) -> Option<EventName> {
95        Some(match self {
96            Self::FrameStart => FRAME_START_EVENT,
97            Self::FrameEnd => FRAME_END_EVENT,
98            Self::PrintLn => PRINTLN_EVENT,
99            Self::UserDefined(name) => name.clone(),
100            Self::Unknown(_) => return None,
101        })
102    }
103
104    /// Returns `true` if `DebuggerHost` has a builtin handler for the event.
105    pub fn has_builtin_handler(&self) -> bool {
106        match self {
107            Self::FrameStart | Self::FrameEnd | Self::PrintLn => true,
108            Self::UserDefined(_) | Self::Unknown(_) => false,
109        }
110    }
111}
112
113impl core::fmt::Display for Event {
114    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115        match self {
116            Self::FrameStart => f.write_str(FRAME_START_EVENT.as_str()),
117            Self::FrameEnd => f.write_str(FRAME_END_EVENT.as_str()),
118            Self::PrintLn => f.write_str(PRINTLN_EVENT.as_str()),
119            Self::UserDefined(name) => f.write_str(name.as_str()),
120            Self::Unknown(id) => write!(f, "{id}"),
121        }
122    }
123}
124
125impl From<EventId> for Event {
126    fn from(raw: EventId) -> Self {
127        if raw == *FRAME_START_EVENT_ID {
128            Self::FrameStart
129        } else if raw == *FRAME_END_EVENT_ID {
130            Self::FrameEnd
131        } else if raw == *PRINTLN_EVENT_ID {
132            Self::PrintLn
133        } else {
134            Self::Unknown(raw)
135        }
136    }
137}
138
139impl From<Event> for EventId {
140    fn from(event: Event) -> Self {
141        event.as_event_id()
142    }
143}
144
145impl From<EventName> for Event {
146    fn from(value: EventName) -> Self {
147        if value == FRAME_START_EVENT {
148            Self::FrameStart
149        } else if value == FRAME_END_EVENT {
150            Self::FrameEnd
151        } else if value == PRINTLN_EVENT {
152            Self::PrintLn
153        } else {
154            Self::UserDefined(value)
155        }
156    }
157}
158
159#[cfg(test)]
160mod tests {
161    use super::*;
162
163    #[test]
164    fn print_ln_event_roundtrips() {
165        assert_eq!(Event::from(PRINTLN_EVENT.to_event_id()), Event::PrintLn);
166        assert_eq!(Event::PrintLn.as_event_id(), *PRINTLN_EVENT_ID);
167        assert_eq!(Event::from(PRINTLN_EVENT), Event::PrintLn);
168    }
169}