Skip to main content

rs_teststand/messaging/
ui_message_code.rs

1//! Codes identifying what a user-interface message reports.
2
3/// A user-interface message code (`UIMsg_*`).
4///
5/// The engine posts these to tell a host what an execution is doing. A
6/// sequence can also post its own, numbered from
7/// [`USER_MESSAGE_BASE`](Self::USER_MESSAGE_BASE) upward, which is how a test
8/// reports progress to whatever is driving it.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10#[repr(i32)]
11pub enum UIMessageCode {
12    /// `UIMsg_BreakOnUserRequest`.
13    BreakOnUserRequest = 1,
14    /// `UIMsg_BreakOnBreakpoint`.
15    BreakOnBreakpoint = 2,
16    /// `UIMsg_BreakOnRunTimeError`.
17    BreakOnRunTimeError = 3,
18    /// `UIMsg_Trace`.
19    Trace = 4,
20    /// `UIMsg_TerminatingExecution`.
21    TerminatingExecution = 5,
22    /// `UIMsg_AbortingExecution`.
23    AbortingExecution = 6,
24    /// `UIMsg_KillingExecutionThreads`.
25    KillingExecutionThreads = 7,
26    /// `UIMsg_EndExecution`.
27    EndExecution = 8,
28    /// `UIMsg_ShutDownComplete`.
29    ShutDownComplete = 9,
30    /// `UIMsg_StartExecution`.
31    StartExecution = 10,
32    /// `UIMsg_ProgressPercent`.
33    ProgressPercent = 11,
34    /// `UIMsg_ProgressText`.
35    ProgressText = 12,
36    /// `UIMsg_StartInteractiveExecution`.
37    StartInteractiveExecution = 13,
38    /// `UIMsg_EndInteractiveExecution`.
39    EndInteractiveExecution = 14,
40    /// `UIMsg_TerminatingInteractiveExecution`.
41    TerminatingInteractiveExecution = 15,
42    /// `UIMsg_TerminationCanceled`.
43    TerminationCanceled = 16,
44    /// `UIMsg_ResumeFromBreak`.
45    ResumeFromBreak = 17,
46    /// `UIMsg_StartFileExecution`.
47    StartFileExecution = 18,
48    /// `UIMsg_EndFileExecution`.
49    EndFileExecution = 19,
50    /// `UIMsg_ShutDownCanceled`.
51    ShutDownCanceled = 20,
52    /// `UIMsg_LocalizationSettingChanged`.
53    LocalizationSettingChanged = 21,
54    /// `UIMsg_OpenWindows`.
55    OpenWindows = 22,
56    /// `UIMsg_TileWindows`.
57    TileWindows = 23,
58    /// `UIMsg_CascadeWindows`.
59    CascadeWindows = 24,
60    /// `UIMsg_ReportChanged`.
61    ReportChanged = 25,
62    /// `UIMsg_CloseWindows`.
63    CloseWindows = 26,
64    /// `UIMsg_RefreshWindows`.
65    RefreshWindows = 27,
66    /// `UIMsg_ClientFileChanged`.
67    ClientFileChanged = 28,
68    /// `UIMsg_DisplayReport`.
69    DisplayReport = 29,
70    /// `UIMsg_ModelStateInitializing`.
71    ModelStateInitializing = 30,
72    /// `UIMsg_ModelStateWaiting`.
73    ModelStateWaiting = 31,
74    /// `UIMsg_ModelStateIdentified`.
75    ModelStateIdentified = 32,
76    /// `UIMsg_ModelStateBeginTesting`.
77    ModelStateBeginTesting = 33,
78    /// `UIMsg_ModelStateTestingComplete`.
79    ModelStateTestingComplete = 34,
80    /// `UIMsg_ModelStatePostProcessingComplete`.
81    ModelStatePostProcessingComplete = 35,
82    /// `UIMsg_ModelStateEnabledStateSet`.
83    ModelStateEnabledStateSet = 36,
84    /// `UIMsg_ReportLocationChanged`.
85    ReportLocationChanged = 37,
86    /// `UIMsg_GotoLocation`.
87    GotoLocation = 38,
88    /// `UIMsg_PushUndoItem`.
89    PushUndoItem = 39,
90    /// `UIMsg_OutputMessages`.
91    OutputMessages = 40,
92    /// `UIMsg_TypePaletteFileListChanged`.
93    TypePaletteFileListChanged = 41,
94    /// `UIMsg_NonTerminatableThreadsArePreventingTermination`.
95    NonTerminatableThreadsArePreventingTermination = 42,
96    /// `UIMsg_ModelStatePostProcessing`.
97    ModelStatePostProcessing = 43,
98    /// `UIMsg_ReportCollectionChanged`.
99    ReportCollectionChanged = 44,
100    /// `UIMsg_RuntimeError`.
101    RuntimeError = 45,
102}
103
104impl UIMessageCode {
105    /// Every code the engine defines.
106    pub const ALL: [Self; 45] = [
107        Self::BreakOnUserRequest,
108        Self::BreakOnBreakpoint,
109        Self::BreakOnRunTimeError,
110        Self::Trace,
111        Self::TerminatingExecution,
112        Self::AbortingExecution,
113        Self::KillingExecutionThreads,
114        Self::EndExecution,
115        Self::ShutDownComplete,
116        Self::StartExecution,
117        Self::ProgressPercent,
118        Self::ProgressText,
119        Self::StartInteractiveExecution,
120        Self::EndInteractiveExecution,
121        Self::TerminatingInteractiveExecution,
122        Self::TerminationCanceled,
123        Self::ResumeFromBreak,
124        Self::StartFileExecution,
125        Self::EndFileExecution,
126        Self::ShutDownCanceled,
127        Self::LocalizationSettingChanged,
128        Self::OpenWindows,
129        Self::TileWindows,
130        Self::CascadeWindows,
131        Self::ReportChanged,
132        Self::CloseWindows,
133        Self::RefreshWindows,
134        Self::ClientFileChanged,
135        Self::DisplayReport,
136        Self::ModelStateInitializing,
137        Self::ModelStateWaiting,
138        Self::ModelStateIdentified,
139        Self::ModelStateBeginTesting,
140        Self::ModelStateTestingComplete,
141        Self::ModelStatePostProcessingComplete,
142        Self::ModelStateEnabledStateSet,
143        Self::ReportLocationChanged,
144        Self::GotoLocation,
145        Self::PushUndoItem,
146        Self::OutputMessages,
147        Self::TypePaletteFileListChanged,
148        Self::NonTerminatableThreadsArePreventingTermination,
149        Self::ModelStatePostProcessing,
150        Self::ReportCollectionChanged,
151        Self::RuntimeError,
152    ];
153
154    /// The first code available to a sequence (`UIMsg_UserMessageBase`).
155    ///
156    /// Engine codes sit below this; anything at or above it was posted by a
157    /// sequence, so a host can tell the two apart without a lookup.
158    pub const USER_MESSAGE_BASE: i32 = 10000;
159
160    /// The value the COM boundary expects.
161    #[must_use]
162    pub const fn bits(self) -> i32 {
163        self as i32
164    }
165
166    /// Whether a raw code was posted by a sequence rather than the engine.
167    #[must_use]
168    pub const fn is_user_message(raw: i32) -> bool {
169        raw >= Self::USER_MESSAGE_BASE
170    }
171
172    /// Reads a raw code, returning it unchanged when it is not an engine one.
173    ///
174    /// # Errors
175    /// The raw value, for a user message or a code this build does not name.
176    pub const fn from_bits(raw: i32) -> Result<Self, i32> {
177        Ok(match raw {
178            1 => Self::BreakOnUserRequest,
179            2 => Self::BreakOnBreakpoint,
180            3 => Self::BreakOnRunTimeError,
181            4 => Self::Trace,
182            5 => Self::TerminatingExecution,
183            6 => Self::AbortingExecution,
184            7 => Self::KillingExecutionThreads,
185            8 => Self::EndExecution,
186            9 => Self::ShutDownComplete,
187            10 => Self::StartExecution,
188            11 => Self::ProgressPercent,
189            12 => Self::ProgressText,
190            13 => Self::StartInteractiveExecution,
191            14 => Self::EndInteractiveExecution,
192            15 => Self::TerminatingInteractiveExecution,
193            16 => Self::TerminationCanceled,
194            17 => Self::ResumeFromBreak,
195            18 => Self::StartFileExecution,
196            19 => Self::EndFileExecution,
197            20 => Self::ShutDownCanceled,
198            21 => Self::LocalizationSettingChanged,
199            22 => Self::OpenWindows,
200            23 => Self::TileWindows,
201            24 => Self::CascadeWindows,
202            25 => Self::ReportChanged,
203            26 => Self::CloseWindows,
204            27 => Self::RefreshWindows,
205            28 => Self::ClientFileChanged,
206            29 => Self::DisplayReport,
207            30 => Self::ModelStateInitializing,
208            31 => Self::ModelStateWaiting,
209            32 => Self::ModelStateIdentified,
210            33 => Self::ModelStateBeginTesting,
211            34 => Self::ModelStateTestingComplete,
212            35 => Self::ModelStatePostProcessingComplete,
213            36 => Self::ModelStateEnabledStateSet,
214            37 => Self::ReportLocationChanged,
215            38 => Self::GotoLocation,
216            39 => Self::PushUndoItem,
217            40 => Self::OutputMessages,
218            41 => Self::TypePaletteFileListChanged,
219            42 => Self::NonTerminatableThreadsArePreventingTermination,
220            43 => Self::ModelStatePostProcessing,
221            44 => Self::ReportCollectionChanged,
222            45 => Self::RuntimeError,
223            other => return Err(other),
224        })
225    }
226}
227
228#[cfg(test)]
229mod tests {
230    use super::UIMessageCode;
231
232    #[test]
233    fn every_code_round_trips() {
234        for code in UIMessageCode::ALL {
235            assert_eq!(UIMessageCode::from_bits(code.bits()), Ok(code));
236        }
237    }
238
239    #[test]
240    fn engine_codes_sit_below_the_user_range() {
241        // A host distinguishes its own messages from the engine's by value
242        // alone, so no engine code may stray into the user range.
243        for code in UIMessageCode::ALL {
244            assert!(
245                !UIMessageCode::is_user_message(code.bits()),
246                "{code:?} collides with the user range"
247            );
248        }
249    }
250
251    #[test]
252    fn a_sequence_posted_code_is_recognized() {
253        assert!(UIMessageCode::is_user_message(
254            UIMessageCode::USER_MESSAGE_BASE
255        ));
256        assert!(UIMessageCode::is_user_message(
257            UIMessageCode::USER_MESSAGE_BASE + 1
258        ));
259        assert_eq!(
260            UIMessageCode::from_bits(UIMessageCode::USER_MESSAGE_BASE + 1),
261            Err(10001)
262        );
263    }
264
265    #[test]
266    fn shutdown_complete_keeps_the_value_the_watchdog_relies_on() {
267        // Engine shutdown is signaled by this code; the graceful-shutdown
268        // path waits for it, so the number is load-bearing.
269        assert_eq!(UIMessageCode::ShutDownComplete.bits(), 9);
270    }
271}