Skip to main content

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}