switchbot_api/
command_request.rs

1/// A command request to send to the [SwitchBot API].
2///
3/// For more details of each field, please refer to the [SwitchBot
4/// documentation about device control commands][send-device-control-commands].
5///
6/// # Examples
7/// ```
8/// # use switchbot_api::CommandRequest;
9/// let command = CommandRequest {
10///     command: "turnOn".into(),
11///     ..Default::default()
12/// };
13/// ```
14///
15/// [SwitchBot API]: https://github.com/OpenWonderLabs/SwitchBotAPI
16/// [send-device-control-commands]: https://github.com/OpenWonderLabs/SwitchBotAPI/blob/main/README.md#send-device-control-commands
17#[derive(Debug, Default, PartialEq, serde::Serialize)]
18#[serde(rename_all = "camelCase")]
19pub struct CommandRequest {
20    /// The command.
21    pub command: String,
22
23    /// The command parameters.
24    #[serde(skip_serializing_if = "CommandRequest::can_omit_parameter")]
25    pub parameter: String,
26
27    /// The command type.
28    #[serde(skip_serializing_if = "CommandRequest::can_omit_command_type")]
29    pub command_type: String,
30}
31
32impl CommandRequest {
33    const DEFAULT_PARAMETER: &str = "default";
34    const DEFAULT_COMMAND_TYPE: &str = "command";
35
36    fn can_omit_parameter(str: &str) -> bool {
37        str.is_empty() || str == Self::DEFAULT_PARAMETER
38    }
39
40    fn can_omit_command_type(str: &str) -> bool {
41        str.is_empty() || str == Self::DEFAULT_COMMAND_TYPE
42    }
43}
44
45impl From<&str> for CommandRequest {
46    /// Parse a string into a [`CommandRequest`].
47    /// Please see the [`switchbot-cli` document] for the syntax.
48    ///
49    /// [`switchbot-cli` document]: https://github.com/kojiishi/switchbot-rs/tree/main/cli#command
50    /// ```
51    /// # use switchbot_api::CommandRequest;
52    /// assert_eq!(
53    ///     CommandRequest::from("turnOn"),
54    ///     CommandRequest {
55    ///         command: "turnOn".into(),
56    ///         ..Default::default()
57    ///     }
58    /// );
59    /// assert_eq!(
60    ///     CommandRequest::from("turnOn:parameter:colon/slash"),
61    ///     CommandRequest {
62    ///         command: "turnOn".into(),
63    ///         parameter: "parameter:colon/slash".into(),
64    ///         ..Default::default()
65    ///     }
66    /// );
67    /// assert_eq!(
68    ///     CommandRequest::from("customize/turnOn"),
69    ///     CommandRequest {
70    ///         command: "turnOn".into(),
71    ///         command_type: "customize".into(),
72    ///         ..Default::default()
73    ///     }
74    /// );
75    /// assert_eq!(
76    ///     CommandRequest::from("customize/turnOn:parameter:colon/slash"),
77    ///     CommandRequest {
78    ///         command: "turnOn".into(),
79    ///         command_type: "customize".into(),
80    ///         parameter: "parameter:colon/slash".into(),
81    ///     }
82    /// );
83    /// ```
84    fn from(mut text: &str) -> Self {
85        let mut command = CommandRequest::default();
86        if let Some((name, parameter)) = text.split_once(':') {
87            command.parameter = parameter.into();
88            text = name;
89        }
90        if let Some((command_type, name)) = text.split_once('/') {
91            command.command_type = command_type.into();
92            text = name;
93        }
94        command.command = text.into();
95        command
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn serialize_all() {
105        let all = CommandRequest {
106            command: "test_command".into(),
107            parameter: "param".into(),
108            command_type: "type".into(),
109        };
110        assert_eq!(
111            serde_json::to_string(&all).unwrap(),
112            r#"{"command":"test_command","parameter":"param","commandType":"type"}"#
113        );
114    }
115
116    #[test]
117    fn serialize_default() {
118        let param_type_default = CommandRequest {
119            command: "test_command".into(),
120            ..Default::default()
121        };
122        assert_eq!(
123            serde_json::to_string(&param_type_default).unwrap(),
124            r#"{"command":"test_command"}"#
125        );
126    }
127
128    #[test]
129    fn serialize_default_str() {
130        let param_type_default = CommandRequest {
131            command: "test_command".into(),
132            parameter: CommandRequest::DEFAULT_PARAMETER.into(),
133            command_type: CommandRequest::DEFAULT_COMMAND_TYPE.into(),
134        };
135        assert_eq!(
136            serde_json::to_string(&param_type_default).unwrap(),
137            r#"{"command":"test_command"}"#
138        );
139    }
140
141    #[test]
142    fn serialize_empty() {
143        let param_type_empty = CommandRequest {
144            command: "test_command".into(),
145            parameter: String::default(),
146            command_type: String::default(),
147        };
148        assert_eq!(
149            serde_json::to_string(&param_type_empty).unwrap(),
150            r#"{"command":"test_command"}"#
151        );
152    }
153
154    #[test]
155    fn serialize_param() {
156        let with_param = CommandRequest {
157            command: "test_command".into(),
158            parameter: "param".into(),
159            ..Default::default()
160        };
161        assert_eq!(
162            serde_json::to_string(&with_param).unwrap(),
163            r#"{"command":"test_command","parameter":"param"}"#
164        );
165    }
166
167    #[test]
168    fn serialize_type() {
169        let with_type = CommandRequest {
170            command: "test_command".into(),
171            command_type: "type".into(),
172            ..Default::default()
173        };
174        assert_eq!(
175            serde_json::to_string(&with_type).unwrap(),
176            r#"{"command":"test_command","commandType":"type"}"#
177        );
178    }
179}