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