Skip to main content

miden_debug_engine/exec/
trace_event.rs

1//! This module contains the set of compiler-emitted event codes, and their explanations
2use core::num::NonZeroU32;
3
4/// This event is emitted via `trace`, and indicates that a procedure call frame is entered
5///
6/// The mnemonic here is F = frame, 0 = open
7pub const TRACE_FRAME_START: u32 = 0xf0;
8
9/// This event is emitted via `trace`, and indicates that a procedure call frame is exited
10///
11/// The mnemonic here is F = frame, C = close
12pub const TRACE_FRAME_END: u32 = 0xfc;
13
14/// This event is emitted via `trace`, and 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.
21///
22/// The mnemonic here is ASCII `PRNT`.
23pub const TRACE_PRINT_LN: u32 = 0x50_52_4e_54;
24
25/// A typed wrapper around the raw trace events known to the compiler
26#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
27#[repr(u32)]
28pub enum TraceEvent {
29    FrameStart,
30    FrameEnd,
31    PrintLn,
32    AssertionFailed(Option<NonZeroU32>),
33    Unknown(u32),
34}
35
36impl TraceEvent {
37    #[inline(always)]
38    pub fn is_frame_start(&self) -> bool {
39        matches!(self, Self::FrameStart)
40    }
41
42    #[inline(always)]
43    pub fn is_frame_end(&self) -> bool {
44        matches!(self, Self::FrameEnd)
45    }
46
47    pub fn as_u32(self) -> u32 {
48        match self {
49            Self::FrameStart => TRACE_FRAME_START,
50            Self::FrameEnd => TRACE_FRAME_END,
51            Self::PrintLn => TRACE_PRINT_LN,
52            Self::AssertionFailed(None) => 0,
53            Self::AssertionFailed(Some(code)) => code.get(),
54            Self::Unknown(event) => event,
55        }
56    }
57}
58
59impl core::fmt::Display for TraceEvent {
60    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
61        match self {
62            Self::FrameStart => f.write_str("FRAME_START"),
63            Self::FrameEnd => f.write_str("FRAME_END"),
64            Self::PrintLn => f.write_str("PRNT"),
65            Self::AssertionFailed(None) => write!(f, "ASSERT_FAILED"),
66            Self::AssertionFailed(Some(id)) => write!(f, "ASSERT_FAILED({id})"),
67            Self::Unknown(id) => write!(f, "{id}"),
68        }
69    }
70}
71
72impl From<u32> for TraceEvent {
73    fn from(raw: u32) -> Self {
74        match raw {
75            TRACE_FRAME_START => Self::FrameStart,
76            TRACE_FRAME_END => Self::FrameEnd,
77            TRACE_PRINT_LN => Self::PrintLn,
78            _ => Self::Unknown(raw),
79        }
80    }
81}
82
83impl From<TraceEvent> for u32 {
84    fn from(event: TraceEvent) -> Self {
85        match event {
86            TraceEvent::FrameStart => TRACE_FRAME_START,
87            TraceEvent::FrameEnd => TRACE_FRAME_END,
88            TraceEvent::PrintLn => TRACE_PRINT_LN,
89            TraceEvent::AssertionFailed(None) => 0,
90            TraceEvent::AssertionFailed(Some(code)) => code.get(),
91            TraceEvent::Unknown(code) => code,
92        }
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::{TRACE_PRINT_LN, TraceEvent};
99
100    #[test]
101    fn trace_print_ln_roundtrips_through_trace_event() {
102        assert_eq!(TraceEvent::from(TRACE_PRINT_LN), TraceEvent::PrintLn);
103        assert_eq!(TraceEvent::PrintLn.as_u32(), TRACE_PRINT_LN);
104        assert_eq!(u32::from(TraceEvent::PrintLn), TRACE_PRINT_LN);
105    }
106}