rs_teststand/sequence/options.rs
1//! Options controlling how a sequence file is opened.
2
3bitflags::bitflags! {
4 /// Flags for opening a sequence file (`GetSeqFile_*`).
5 ///
6 /// ```
7 /// use rs_teststand::GetSeqFileOptions as Options;
8 ///
9 /// let opened = Options::PRELOAD_MODULES | Options::FIND_FILE;
10 /// assert!(opened.contains(Options::FIND_FILE));
11 /// ```
12 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
13 pub struct GetSeqFileOptions: i32 {
14 /// Default behavior (`GetSeqFile_NoOptions`).
15 const NONE = 0;
16 /// Preload the file's code modules (`GetSeqFile_PreloadModules`).
17 const PRELOAD_MODULES = 1;
18 /// Reload from disk even if cached (`GetSeqFile_UpdateFromDisk`).
19 const UPDATE_FROM_DISK = 2;
20 /// Tolerate type conflicts (`GetSeqFile_AllowTypeConflicts`).
21 const ALLOW_TYPE_CONFLICTS = 4;
22 /// Skip the file's load callback (`GetSeqFile_DoNotRunLoadCallback`).
23 ///
24 /// A load callback can display a dialog, which blocks an unattended
25 /// host, set this when opening untrusted files headlessly.
26 const DO_NOT_RUN_LOAD_CALLBACK = 16;
27 /// Search the configured directories for the file (`GetSeqFile_FindFile`).
28 const FIND_FILE = 32;
29 /// The combination an operator interface uses
30 /// (`GetSeqFile_OperatorInterfaceFlags`).
31 const OPERATOR_INTERFACE = 107;
32 /// Return the file only if already cached
33 /// (`GetSeqFile_GetFileOnlyIfInCache`).
34 const ONLY_IF_IN_CACHE = 512;
35 }
36}
37
38/// How the engine resolves a type conflict while loading
39/// (`ConflictHandler_*`).
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
41#[repr(i32)]
42pub enum ConflictHandler {
43 /// Fail the load (`ConflictHandler_Error`). The only non-interactive
44 /// choice that never blocks, so it is the sensible default for a service.
45 Error = 1,
46 /// Ask the user (`ConflictHandler_Prompt`). Raises a dialog, unsuitable
47 /// for an unattended host.
48 Prompt = 3,
49 /// Keep the already-loaded type (`ConflictHandler_UseGlobalType`).
50 UseGlobalType = 4,
51}
52
53impl ConflictHandler {
54 /// The value the COM boundary expects.
55 #[must_use]
56 pub const fn bits(self) -> i32 {
57 self as i32
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::{ConflictHandler, GetSeqFileOptions};
64
65 #[test]
66 fn flags_combine() {
67 let options = GetSeqFileOptions::PRELOAD_MODULES | GetSeqFileOptions::FIND_FILE;
68 assert_eq!(options.bits(), 1 | 32);
69 assert!(options.contains(GetSeqFileOptions::FIND_FILE));
70 assert!(!options.contains(GetSeqFileOptions::ONLY_IF_IN_CACHE));
71 }
72
73 #[test]
74 fn operator_interface_is_a_composite_of_named_flags() {
75 // 107 = 1 | 2 | 8 | 32 | 64: it already implies preload and find-file,
76 // which is why an operator interface does not set them separately.
77 let operator = GetSeqFileOptions::OPERATOR_INTERFACE;
78 assert!(operator.contains(GetSeqFileOptions::PRELOAD_MODULES));
79 assert!(operator.contains(GetSeqFileOptions::UPDATE_FROM_DISK));
80 assert!(operator.contains(GetSeqFileOptions::FIND_FILE));
81 }
82
83 #[test]
84 fn conflict_handler_maps_to_documented_values() {
85 assert_eq!(ConflictHandler::Error.bits(), 1);
86 assert_eq!(ConflictHandler::Prompt.bits(), 3);
87 assert_eq!(ConflictHandler::UseGlobalType.bits(), 4);
88 }
89}