secop_core/
errors.rs

1// -----------------------------------------------------------------------------
2// Rust SECoP playground
3//
4// This program is free software; you can redistribute it and/or modify it under
5// the terms of the GNU General Public License as published by the Free Software
6// Foundation; either version 2 of the License, or (at your option) any later
7// version.
8//
9// This program is distributed in the hope that it will be useful, but WITHOUT
10// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
12// details.
13//
14// You should have received a copy of the GNU General Public License along with
15// this program; if not, write to the Free Software Foundation, Inc.,
16// 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17//
18// Module authors:
19//   Georg Brandl <g.brandl@fz-juelich.de>
20//
21// -----------------------------------------------------------------------------
22//
23//! Enumeration of possible SECoP errors.
24
25use std::{error, fmt, result};
26use serde_json::json;
27
28use crate::proto::Msg;
29
30
31pub type Result<T> = result::Result<T, Error>;
32
33#[derive(Debug)]
34pub enum ErrorKind {
35    // Internal
36    Config,
37    Programming,
38    Parsing,
39    // API defined
40    Protocol,
41    NoSuchModule,
42    NoSuchParameter,
43    NoSuchCommand,
44    CommandFailed,
45    CommandRunning,
46    ReadOnly,
47    BadValue,
48    CommunicationFailed,
49    Timeout,       // ATM also C.F.
50    HardwareError, // ATM also C.F.
51    IsBusy,
52    IsError,
53    Disabled,
54}
55
56#[derive(Debug)]
57pub struct Error {
58    kind: ErrorKind,
59    message: String,
60}
61
62impl Error {
63    pub fn new(kind: ErrorKind, msg: impl Into<String>) -> Self {
64        Self { kind, message: msg.into() }
65    }
66
67    pub fn bad_value(msg: impl Into<String>) -> Self {
68        Self { kind: ErrorKind::BadValue, message: msg.into() }
69    }
70
71    pub fn amend(mut self, msg: &str) -> Self {
72        self.message = format!("{} ({})", self.message, msg);
73        self
74    }
75
76    pub fn into_msg(self, msg: String) -> Msg {
77        Msg::ErrMsg {
78            class: self.wire().into(),
79            report: json!([msg, self.message, {}])
80        }
81    }
82
83    fn wire(&self) -> &str {
84        use self::ErrorKind::*;
85        match self.kind {
86            Config | Programming | Parsing => "InternalError",
87            Protocol => "ProtocolError",
88            NoSuchModule => "NoSuchModule",
89            NoSuchParameter => "NoSuchParameter",
90            NoSuchCommand => "NoSuchCommand",
91            CommandFailed => "CommandFailed",
92            CommandRunning => "CommandRunning",
93            ReadOnly => "ReadOnly",
94            BadValue => "BadValue",
95            CommunicationFailed => "CommunicationFailed",
96            Timeout => "CommunicationFailed",
97            HardwareError => "CommunicationFailed",
98            IsBusy => "IsBusy",
99            IsError => "IsError",
100            Disabled => "Disabled",
101        }
102    }
103
104    // Quick construction.
105
106    pub fn config(msg: impl Into<String>) -> Self {
107        Self { kind: ErrorKind::Config, message: msg.into() }
108    }
109
110    pub fn protocol(msg: impl Into<String>) -> Self {
111        Self { kind: ErrorKind::Protocol, message: msg.into() }
112    }
113
114    pub fn no_module() -> Self {
115        Self { kind: ErrorKind::NoSuchModule, message: "".into() }
116    }
117
118    pub fn no_param() -> Self {
119        Self { kind: ErrorKind::NoSuchParameter, message: "".into() }
120    }
121
122    pub fn no_command() -> Self {
123        Self { kind: ErrorKind::NoSuchCommand, message: "".into() }
124    }
125
126    pub fn comm_failed(msg: impl Into<String>) -> Self {
127        Self { kind: ErrorKind::CommunicationFailed, message: msg.into() }
128    }
129}
130
131/// Allow quick conversion of io::Error to SECoP errors.
132// TODO: is comm_failed the right kind?
133impl From<std::io::Error> for Error {
134    fn from(e: std::io::Error) -> Self {
135        Error::comm_failed(e.to_string())
136    }
137}
138
139impl error::Error for Error {}
140
141impl fmt::Display for Error {
142    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143        write!(f, "{}: {}", self.wire(), self.message)
144    }
145}