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
105impl core::fmt::Display for Event {
106    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107        match self {
108            Self::FrameStart => f.write_str(FRAME_START_EVENT.as_str()),
109            Self::FrameEnd => f.write_str(FRAME_END_EVENT.as_str()),
110            Self::PrintLn => f.write_str(PRINTLN_EVENT.as_str()),
111            Self::UserDefined(name) => f.write_str(name.as_str()),
112            Self::Unknown(id) => write!(f, "{id}"),
113        }
114    }
115}
116
117impl From<EventId> for Event {
118    fn from(raw: EventId) -> Self {
119        if raw == *FRAME_START_EVENT_ID {
120            Self::FrameStart
121        } else if raw == *FRAME_END_EVENT_ID {
122            Self::FrameEnd
123        } else if raw == *PRINTLN_EVENT_ID {
124            Self::PrintLn
125        } else {
126            Self::Unknown(raw)
127        }
128    }
129}
130
131impl From<Event> for EventId {
132    fn from(event: Event) -> Self {
133        event.as_event_id()
134    }
135}
136
137impl From<EventName> for Event {
138    fn from(value: EventName) -> Self {
139        if value == FRAME_START_EVENT {
140            Self::FrameStart
141        } else if value == FRAME_END_EVENT {
142            Self::FrameEnd
143        } else if value == PRINTLN_EVENT {
144            Self::PrintLn
145        } else {
146            Self::UserDefined(value)
147        }
148    }
149}
150
151#[cfg(test)]
152mod tests {
153    use super::*;
154
155    #[test]
156    fn print_ln_event_roundtrips() {
157        assert_eq!(Event::from(PRINTLN_EVENT.to_event_id()), Event::PrintLn);
158        assert_eq!(Event::PrintLn.as_event_id(), *PRINTLN_EVENT_ID);
159        assert_eq!(Event::from(PRINTLN_EVENT), Event::PrintLn);
160    }
161}