flowrlib/
debug_command.rs

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use std::fmt;

use serde_derive::{Deserialize, Serialize};

/// Types of `Params` used in communications between the debugger and the debug_client
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
pub enum BreakpointSpec {
    /// All existing breakpoints
    All,
    /// A positive integer was specified - could be a function or a job number
    Numeric(usize),
    /// A descriptor for the `Output` of a `Function` was specified
    Output((usize, String)),
    /// A descriptor for the `Inout` of a `Function` was specified
    Input((usize, usize)),
    /// A description of a "block" (when one function is blocked from running by another) was specified
    Block((Option<usize>, Option<usize>)),
}

/// A Command sent by the debug_client to the debugger
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
pub enum DebugCommand {
    /// Acknowledge event processed correctly
    Ack,
    /// Set a `breakpoint` - with an optional parameter
    Breakpoint(Option<BreakpointSpec>),
    /// `continue` execution of the flow
    Continue,
    /// Debug client is starting
    DebugClientStarting,
    /// `delete` an existing breakpoint - with an optional parameter
    Delete(Option<BreakpointSpec>),
    /// An error on the client side
    Error(String),
    /// `exit` the debugger and runtime
    ExitDebugger,
    /// List of all functions
    FunctionList,
    /// `inspect` a function
    InspectFunction(usize),
    /// Inspect overall state
    Inspect,
    /// Inspect an Input (function_id, input_number)
    InspectInput(usize, usize),
    /// Inspect an Output (function_id, sub-path)
    InspectOutput(usize, String),
    /// Inspect a Block (optional source function_id, optional destination function_id)
    InspectBlock(Option<usize>, Option<usize>),
    /// Invalid - used when deserialization goes wrong
    Invalid,
    /// `list` existing breakpoints
    List,
    /// `modify` a debugger or runtime state value e.g. jobs=1 to set parallel jobs to 1
    Modify(Option<Vec<String>>),
    /// `reset` flow execution back to the initial state, or run the flow from the start
    RunReset,
    /// `step` forward in flow execution by executing one (default) or more `Jobs`
    Step(Option<usize>),
    /// `validate` the current state
    Validate,
}

impl fmt::Display for DebugCommand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "DebugCommand {}", String::from(self))
    }
}

impl From<&DebugCommand> for String {
    fn from(command: &DebugCommand) -> Self {
        match serde_json::to_string(command) {
            Ok(command_string) => command_string,
            _ => String::new(), // Should never occur
        }
    }
}

impl From<DebugCommand> for String {
    fn from(command: DebugCommand) -> Self {
        match serde_json::to_string(&command) {
            Ok(command_string) => command_string,
            _ => String::new(), // Should never occur
        }
    }
}

impl From<String> for DebugCommand {
    fn from(command_string: String) -> Self {
        match serde_json::from_str(&command_string) {
            Ok(command) => command,
            _ => DebugCommand::Invalid,
        }
    }
}

#[cfg(test)]
mod test {
    use crate::debug_command::DebugCommand;

    #[test]
    fn display_debug_command() {
        println!("{}", DebugCommand::Ack);
        println!("{}", DebugCommand::Breakpoint(None));
        println!("{}", DebugCommand::Continue);
        println!("{}", DebugCommand::Delete(None));
        println!("{}", DebugCommand::Error("Hello".into()));
        println!("{}", DebugCommand::ExitDebugger);
        println!("{}", DebugCommand::FunctionList);
        println!("{}", DebugCommand::InspectFunction(0));
        println!("{}", DebugCommand::Inspect);
        println!("{}", DebugCommand::InspectInput(0, 0));
        println!("{}", DebugCommand::InspectOutput(0, "Hello".into()));
        println!("{}", DebugCommand::InspectBlock(None, None));
        println!("{}", DebugCommand::Invalid);
        println!("{}", DebugCommand::List);
        println!("{}", DebugCommand::RunReset);
        println!("{}", DebugCommand::Step(None));
        println!("{}", DebugCommand::Validate);
        println!("{}", DebugCommand::DebugClientStarting);
        println!("{}", DebugCommand::Modify(None));
    }

    #[test]
    fn test_command_to_string() {
        assert_eq!(String::from(DebugCommand::Ack), "\"Ack\"".to_string());
    }

    #[test]
    fn debug_command_from_string() {
        let command: DebugCommand = DebugCommand::from("\"Ack\"".to_string());
        assert_eq!(command, DebugCommand::Ack);
    }

    #[test]
    fn invalid_debug_command_from_string() {
        let command: DebugCommand = DebugCommand::from("\"Foo\"".to_string());
        assert_eq!(command, DebugCommand::Invalid);
    }
}