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: the union this crate clears so that a host
46 /// with no one at the keyboard cannot wedge at exit.
47 const MODAL_ON_SHUTDOWN =
48 Self::REPORT_OBJECT_LEAKS.bits() | Self::REPORT_KNOWN_OS_AND_COMPONENT_PROBLEMS.bits();
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::DebugOptions;
55
56 #[test]
57 fn modal_bits_are_exactly_the_two_shutdown_dialogs() {
58 assert_eq!(DebugOptions::MODAL_ON_SHUTDOWN.bits(), 4 | 16);
59 }
60
61 #[test]
62 fn clearing_modal_bits_preserves_unrelated_options() {
63 // The engine hands back one mask for every debug setting, so the
64 // hardening step must subtract bits rather than overwrite the value.
65 let current = DebugOptions::STACK_CHECKING
66 | DebugOptions::BUFFER_CHECKING
67 | DebugOptions::SEND_OUTPUT_MESSAGES_TO_DEBUGGER
68 | DebugOptions::MODAL_ON_SHUTDOWN;
69
70 let quiet = current.difference(DebugOptions::MODAL_ON_SHUTDOWN);
71
72 assert!(quiet.contains(DebugOptions::STACK_CHECKING));
73 assert!(quiet.contains(DebugOptions::BUFFER_CHECKING));
74 assert!(quiet.contains(DebugOptions::SEND_OUTPUT_MESSAGES_TO_DEBUGGER));
75 assert!(!quiet.contains(DebugOptions::REPORT_OBJECT_LEAKS));
76 assert!(!quiet.contains(DebugOptions::REPORT_KNOWN_OS_AND_COMPONENT_PROBLEMS));
77 }
78
79 #[test]
80 fn unknown_bits_from_a_newer_engine_survive_a_round_trip() {
81 // A future engine may define debug bits this build does not name;
82 // clearing the modal ones must not discard them.
83 let unknown = DebugOptions::from_bits_retain(1 << 20);
84 let current = unknown | DebugOptions::MODAL_ON_SHUTDOWN;
85 let quiet = current.difference(DebugOptions::MODAL_ON_SHUTDOWN);
86 assert_eq!(quiet.bits(), 1 << 20);
87 }
88}