rs_teststand/station/debug_options.rs
1//! Engine debugging option flags.
2
3bitflags::bitflags! {
4 /// Station debugging options (`DebugOption_*`).
5 ///
6 /// A bitmask read and written whole via
7 /// [`StationOptions::debug_options`](crate::StationOptions::debug_options)
8 /// and its setter, so changing one option means editing a mask rather than
9 /// assigning a value, always read, modify the bits, write back.
10 ///
11 /// ```
12 /// use rs_teststand::DebugOptions;
13 ///
14 /// // Turn off just the dialog-raising bits, preserving everything else.
15 /// let current = DebugOptions::STACK_CHECKING | DebugOptions::REPORT_OBJECT_LEAKS;
16 /// let quiet = current.difference(DebugOptions::MODAL_ON_SHUTDOWN);
17 /// assert!(quiet.contains(DebugOptions::STACK_CHECKING));
18 /// assert!(!quiet.contains(DebugOptions::REPORT_OBJECT_LEAKS));
19 /// ```
20 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
21 pub struct DebugOptions: i32 {
22 /// No debugging options (`DebugOption_NoOptions`).
23 const NONE = 0;
24 /// Validate the stack around code-module calls (`DebugOption_StackChecking`).
25 const STACK_CHECKING = 1;
26 /// Validate buffers around code-module calls (`DebugOption_BufferChecking`).
27 const BUFFER_CHECKING = 2;
28 /// Report leaked objects at shutdown (`DebugOption_ReportObjectLeaks`).
29 ///
30 /// The report is a modal dialog, so this bit blocks an unattended host
31 /// at exit. Leak *detection* is separate, clearing this suppresses
32 /// only the dialog.
33 const REPORT_OBJECT_LEAKS = 4;
34 /// Send output messages to an attached debugger
35 /// (`DebugOption_SendOutputMessagesToDebugger`).
36 const SEND_OUTPUT_MESSAGES_TO_DEBUGGER = 8;
37 /// Report known OS and component problems
38 /// (`DebugOption_ReportKnownOSandComponentProblems`).
39 ///
40 /// Also a modal dialog raised during shutdown.
41 const REPORT_KNOWN_OS_AND_COMPONENT_PROBLEMS = 16;
42
43 /// The bits that raise a modal dialog while the engine shuts down.
44 ///
45 /// Not an engine constant. This is the union [`Engine::new`] clears on
46 /// the station it connects to, so that a host with no one at the
47 /// keyboard cannot wedge at exit. Every other debug bit is left as the
48 /// operator set it.
49 ///
50 /// [`Engine::new`]: crate::Engine::new
51 const MODAL_ON_SHUTDOWN =
52 Self::REPORT_OBJECT_LEAKS.bits() | Self::REPORT_KNOWN_OS_AND_COMPONENT_PROBLEMS.bits();
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::DebugOptions;
59
60 #[test]
61 fn modal_bits_are_exactly_the_two_shutdown_dialogs() {
62 assert_eq!(DebugOptions::MODAL_ON_SHUTDOWN.bits(), 4 | 16);
63 }
64
65 #[test]
66 fn clearing_modal_bits_preserves_unrelated_options() {
67 // The engine hands back one mask for every debug setting, so the
68 // hardening step must subtract bits rather than overwrite the value.
69 let current = DebugOptions::STACK_CHECKING
70 | DebugOptions::BUFFER_CHECKING
71 | DebugOptions::SEND_OUTPUT_MESSAGES_TO_DEBUGGER
72 | DebugOptions::MODAL_ON_SHUTDOWN;
73
74 let quiet = current.difference(DebugOptions::MODAL_ON_SHUTDOWN);
75
76 assert!(quiet.contains(DebugOptions::STACK_CHECKING));
77 assert!(quiet.contains(DebugOptions::BUFFER_CHECKING));
78 assert!(quiet.contains(DebugOptions::SEND_OUTPUT_MESSAGES_TO_DEBUGGER));
79 assert!(!quiet.contains(DebugOptions::REPORT_OBJECT_LEAKS));
80 assert!(!quiet.contains(DebugOptions::REPORT_KNOWN_OS_AND_COMPONENT_PROBLEMS));
81 }
82
83 #[test]
84 fn unknown_bits_from_a_newer_engine_survive_a_round_trip() {
85 // A future engine may define debug bits this build does not name;
86 // clearing the modal ones must not discard them.
87 let unknown = DebugOptions::from_bits_retain(1 << 20);
88 let current = unknown | DebugOptions::MODAL_ON_SHUTDOWN;
89 let quiet = current.difference(DebugOptions::MODAL_ON_SHUTDOWN);
90 assert_eq!(quiet.bits(), 1 << 20);
91 }
92}