rs_teststand/station/execution_mask.rs
1//! Execution and tracing option flags.
2
3bitflags::bitflags! {
4 /// Execution options (`ExecMask_*`), the mask behind the Execution page of
5 /// the Station Options dialog.
6 ///
7 /// Each checkbox on that page is one bit here, so the mask is how a headless
8 /// host configures debugging and tracing without a sequence editor.
9 ///
10 /// Tracing has two independent controls, and confusing them is the usual
11 /// mistake:
12 ///
13 /// * **Whether** tracing happens, [`Self::TRACING_ENABLED`] plus the
14 /// `TRACE_INTO_*` bits that widen its reach.
15 /// * **How fast** it runs, not in this mask at all. That is the Speed
16 /// slider, which is
17 /// [`StationOptions::ui_message_delay`](crate::StationOptions::ui_message_delay):
18 /// milliseconds between trace postings. See that method for the scale.
19 ///
20 /// ```
21 /// use rs_teststand::ExecutionMask;
22 ///
23 /// // Headless: keep tracing, drop everything that can stop an execution.
24 /// let unattended = ExecutionMask::DEFAULT.difference(
25 /// ExecutionMask::BREAKPOINTS_ENABLED
26 /// | ExecutionMask::BREAK_ON_RUN_TIME_ERROR
27 /// | ExecutionMask::BREAK_WHILE_TERMINATING
28 /// | ExecutionMask::ALLOW_BREAK_WHILE_IN_CODE_MODULES,
29 /// );
30 /// assert!(!unattended.contains(ExecutionMask::BREAKPOINTS_ENABLED));
31 /// ```
32 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
33 pub struct ExecutionMask: i32 {
34 /// Breakpoints are honoured (`ExecMask_BreakpointsEnabled`).
35 ///
36 /// A breakpoint suspends the execution until an operator resumes it, so
37 /// this bit is the first to clear on an unattended station.
38 const BREAKPOINTS_ENABLED = 1;
39 /// Breakpoints are still honoured while terminating
40 /// (`ExecMask_BreakWhileTerminating`).
41 const BREAK_WHILE_TERMINATING = 2;
42 /// A run-time error breaks into the debugger
43 /// (`ExecMask_BreakOnRunTimeError`).
44 ///
45 /// Clear this on an unattended station and let
46 /// [`StationOptions::set_rte_option`](crate::StationOptions::set_rte_option)
47 /// decide what happens instead.
48 const BREAK_ON_RUN_TIME_ERROR = 4;
49 /// Tracing is on (`ExecMask_TracingEnabled`).
50 const TRACING_ENABLED = 8;
51 /// Trace into Setup and Cleanup step groups
52 /// (`ExecMask_TraceIntoSetupCleanup`).
53 const TRACE_INTO_SETUP_CLEANUP = 16;
54 /// Trace into pre- and post-step callbacks
55 /// (`ExecMask_TraceIntoPrePostCallbacks`).
56 const TRACE_INTO_PRE_POST_CALLBACKS = 32;
57 /// Trace into post-action callbacks
58 /// (`ExecMask_TraceIntoPostActionCallbacks`).
59 const TRACE_INTO_POST_ACTION_CALLBACKS = 64;
60 /// Trace into separate-execution callbacks
61 /// (`ExecMask_TraceIntoSeparateExecutionCallbacks`).
62 const TRACE_INTO_SEPARATE_EXECUTION_CALLBACKS = 128;
63 /// Trace into entry points (`ExecMask_TraceIntoEntryPoints`).
64 const TRACE_INTO_ENTRY_POINTS = 256;
65 /// Trace into sequence calls whose tracing is switched off
66 /// (`ExecMask_TraceIntoSequenceCallsMarkedAsTraceOff`).
67 const TRACE_INTO_SEQUENCE_CALLS_MARKED_AS_TRACE_OFF = 512;
68 /// Keep tracing while an execution terminates
69 /// (`ExecMask_TraceWhileTerminating`).
70 const TRACE_WHILE_TERMINATING = 1024;
71 /// Trace every thread (`ExecMask_TraceAllThreads`).
72 ///
73 /// The most expensive tracing bit on a parallel station: every thread
74 /// posts trace messages, and each posting is paced by the Speed setting.
75 const TRACE_ALL_THREADS = 2048;
76 /// Interactive executions record results
77 /// (`ExecMask_InteractiveRecordResults`).
78 const INTERACTIVE_RECORD_RESULTS = 4096;
79 /// Interactive executions run Setup and Cleanup
80 /// (`ExecMask_InteractiveRunSetupCleanup`).
81 const INTERACTIVE_RUN_SETUP_CLEANUP = 8192;
82 /// Interactive executions evaluate preconditions
83 /// (`ExecMask_InteractiveEvaluatePreconditions`).
84 const INTERACTIVE_EVALUATE_PRECONDITIONS = 16384;
85 /// Allow breaking while inside a code module
86 /// (`ExecMask_AllowBreakWhileInCodeModules`).
87 const ALLOW_BREAK_WHILE_IN_CODE_MODULES = 32768;
88
89 /// The engine's default combination (`ExecMask_DefaultExecutionMask`).
90 ///
91 /// 32797 = breakpoints + run-time-error break + tracing + trace into
92 /// setup/cleanup + break inside code modules.
93 const DEFAULT = 32797;
94
95 /// Every bit that breaks into the debugger.
96 ///
97 /// Not an engine constant: the union this crate treats as unsafe for an
98 /// unattended host: each one suspends the execution until an operator acts.
99 const BREAKS = Self::BREAKPOINTS_ENABLED.bits()
100 | Self::BREAK_WHILE_TERMINATING.bits()
101 | Self::BREAK_ON_RUN_TIME_ERROR.bits()
102 | Self::ALLOW_BREAK_WHILE_IN_CODE_MODULES.bits();
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::ExecutionMask;
109
110 #[test]
111 fn the_engine_default_decomposes_into_named_bits() {
112 // 32797 is a composite; proving it equals the sum of named bits is what
113 // stops a typo in any one constant going unnoticed.
114 let expected = ExecutionMask::BREAKPOINTS_ENABLED
115 | ExecutionMask::BREAK_ON_RUN_TIME_ERROR
116 | ExecutionMask::TRACING_ENABLED
117 | ExecutionMask::TRACE_INTO_SETUP_CLEANUP
118 | ExecutionMask::ALLOW_BREAK_WHILE_IN_CODE_MODULES;
119 assert_eq!(ExecutionMask::DEFAULT, expected);
120 assert_eq!(ExecutionMask::DEFAULT.bits(), 32797);
121 }
122
123 #[test]
124 fn the_default_mask_would_halt_an_unattended_station() {
125 // The out-of-the-box configuration contains breakpoint and break-on-error
126 // bits, which is precisely why a headless host must clear them.
127 assert!(ExecutionMask::DEFAULT.intersects(ExecutionMask::BREAKS));
128 }
129
130 #[test]
131 fn clearing_the_halting_bits_keeps_tracing_intact() {
132 let unattended = ExecutionMask::DEFAULT.difference(ExecutionMask::BREAKS);
133 assert!(unattended.contains(ExecutionMask::TRACING_ENABLED));
134 assert!(unattended.contains(ExecutionMask::TRACE_INTO_SETUP_CLEANUP));
135 assert!(!unattended.intersects(ExecutionMask::BREAKS));
136 }
137
138 #[test]
139 fn unknown_bits_from_a_newer_engine_survive() {
140 let unknown = ExecutionMask::from_bits_retain(1 << 24);
141 let cleared = (unknown | ExecutionMask::BREAKS).difference(ExecutionMask::BREAKS);
142 assert_eq!(cleared.bits(), 1 << 24);
143 }
144}