Skip to main content

rs_teststand/sequence/
breakpoint.rs

1//! Breakpoints, and the two scopes they can live in.
2//!
3//! A breakpoint belongs to a step, not to a run. Setting one through
4//! [`Step::set_break_on_step`](crate::Step::set_break_on_step) writes it into
5//! the step, so every execution of that sequence stops there and the setting
6//! outlives the run that set it.
7//!
8//! Passing an execution instead scopes the breakpoint to that one run. The
9//! step on disk is untouched, and the breakpoint goes away with the execution.
10//! That is what a host debugging on behalf of a remote panel wants: a
11//! debugging session should not quietly edit the station's sequence files.
12//!
13//! Nothing here stops a run on its own. The engine only honors breakpoints
14//! while they are switched on, which is a separate decision made at two levels.
15//! [`Engine::breakpoints_enabled`](crate::Engine::breakpoints_enabled) is the
16//! live switch for the session, and the station option of the same name is the
17//! setting written to disk. With either off, a set breakpoint stays set and is
18//! ignored.
19
20use rs_teststand_sys::Value;
21
22/// Which run a breakpoint applies to.
23///
24/// The engine takes this as an optional argument on every breakpoint member.
25/// Leaving it out edits the step itself; supplying an execution scopes the
26/// change to that run.
27#[derive(Debug, Clone, Copy)]
28pub enum BreakpointScope<'execution> {
29    /// Write the breakpoint into the step, where it outlives every run and is
30    /// saved with the sequence file.
31    Step,
32    /// Apply it to one execution only, leaving the step on disk alone.
33    Execution(&'execution crate::Execution),
34}
35
36impl BreakpointScope<'_> {
37    /// The optional execution argument the engine expects.
38    ///
39    /// [`Step`](Self::Step) becomes an absent argument rather than a null one,
40    /// which is how the engine is told to edit the step itself.
41    pub(crate) fn argument(self) -> Value {
42        match self {
43            Self::Step => Value::Empty,
44            Self::Execution(execution) => execution.as_argument(),
45        }
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use rs_teststand_sys::Value;
52
53    use super::BreakpointScope;
54
55    #[test]
56    fn step_scope_sends_an_absent_argument() {
57        // Absent, not null. The engine reads a missing execution as "edit the
58        // step itself"; a null object would be a different request.
59        assert!(matches!(BreakpointScope::Step.argument(), Value::Empty));
60    }
61}