rs_teststand/station/run_time_error.rs
1//! What the engine does when a step reports a run-time error.
2
3/// The station's response to a run-time error (`RTEOption_*`).
4///
5/// [`ShowDialog`](Self::ShowDialog) is the one to watch on an unattended host:
6/// it suspends the execution until an operator answers, which on an
7/// unattended station is an outage rather than a prompt.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9#[repr(i32)]
10pub enum RunTimeErrorOption {
11 /// Prompt the operator (`RTEOption_ShowDialog`). Blocks until answered.
12 ShowDialog = 0,
13 /// Pass the error to the calling sequence (`RTEOption_Continue`).
14 Continue = 1,
15 /// Carry on as though nothing happened (`RTEOption_Ignore`).
16 Ignore = 2,
17 /// Abort the execution (`RTEOption_Abort`).
18 Abort = 3,
19 /// Re-run the step that failed (`RTEOption_Retry`).
20 Retry = 4,
21}
22
23impl RunTimeErrorOption {
24 /// Every response the engine defines.
25 pub const ALL: [Self; 5] = [
26 Self::ShowDialog,
27 Self::Continue,
28 Self::Ignore,
29 Self::Abort,
30 Self::Retry,
31 ];
32
33 /// The value the COM boundary expects.
34 #[must_use]
35 pub const fn bits(self) -> i32 {
36 self as i32
37 }
38
39 /// Reads a raw value, returning it unchanged when it is one this build does
40 /// not name.
41 ///
42 /// # Errors
43 /// The raw value, when it matches no known option.
44 pub const fn from_bits(raw: i32) -> Result<Self, i32> {
45 Ok(match raw {
46 0 => Self::ShowDialog,
47 1 => Self::Continue,
48 2 => Self::Ignore,
49 3 => Self::Abort,
50 4 => Self::Retry,
51 other => return Err(other),
52 })
53 }
54
55 /// Whether this response is interactive.
56 ///
57 /// The single question an unattended host needs answered.
58 #[must_use]
59 pub const fn is_interactive(self) -> bool {
60 matches!(self, Self::ShowDialog)
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::RunTimeErrorOption;
67
68 #[test]
69 fn only_the_dialog_response_blocks() {
70 assert!(RunTimeErrorOption::ShowDialog.is_interactive());
71 for option in [
72 RunTimeErrorOption::Continue,
73 RunTimeErrorOption::Ignore,
74 RunTimeErrorOption::Abort,
75 RunTimeErrorOption::Retry,
76 ] {
77 assert!(!option.is_interactive(), "{option:?}");
78 }
79 }
80
81 #[test]
82 fn every_option_round_trips_through_its_raw_value() {
83 for option in RunTimeErrorOption::ALL {
84 assert_eq!(RunTimeErrorOption::from_bits(option.bits()), Ok(option));
85 }
86 }
87
88 #[test]
89 fn an_unknown_value_is_returned_rather_than_guessed() {
90 // A newer engine may add a response; reporting the number beats
91 // silently mapping it onto an existing one.
92 assert_eq!(RunTimeErrorOption::from_bits(99), Err(99));
93 }
94}