Skip to main content

ocpp_types/v16/
error.rs

1//! RPC framework error codes from Table 7 ("Valid Error Codes") of the
2//! OCPP-J 1.6 specification -- the `errorCode` values a `CALLERROR` frame
3//! may carry.
4
5/// One of the error codes OCPP-J 1.6 allows in a `CALLERROR` frame.
6///
7/// Note the spelling: `OccurenceConstraintViolation` is missing an "r".
8/// That's the spec, not a typo here -- later versions correct it to
9/// `OccurrenceConstraintViolation` (see `v201::RpcErrorCode`), so the two
10/// are deliberately distinct variants across versions.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub enum RpcErrorCode {
14    /// Requested Action is not known by receiver
15    NotImplemented,
16    /// Requested Action is recognized but not supported by the receiver
17    NotSupported,
18    /// An internal error occurred and the receiver was not able to process
19    /// the requested Action successfully
20    InternalError,
21    /// Payload for Action is incomplete
22    ProtocolError,
23    /// During the processing of Action a security issue occurred
24    /// preventing receiver from completing the Action successfully
25    SecurityError,
26    /// Payload for Action is syntactically incorrect or not conform the
27    /// PDU structure for Action
28    FormationViolation,
29    /// Payload is syntactically correct but at least one field contains an
30    /// invalid value
31    PropertyConstraintViolation,
32    /// Payload for Action is syntactically correct but at least one of the
33    /// fields violates occurence constraints
34    OccurenceConstraintViolation,
35    /// Payload for Action is syntactically correct but at least one of the
36    /// fields violates data type constraints (e.g. "somestring": 12)
37    TypeConstraintViolation,
38    /// Any other error not covered by the previous ones
39    GenericError,
40}
41
42impl RpcErrorCode {
43    /// The spec's own description for this error code (see `Display`,
44    /// which uses this).
45    pub const fn description(&self) -> &'static str {
46        match self {
47            Self::NotImplemented => "Requested Action is not known by receiver",
48            Self::NotSupported => {
49                "Requested Action is recognized but not supported by the receiver"
50            }
51            Self::InternalError => {
52                "An internal error occurred and the receiver was not able to process the requested Action successfully"
53            }
54            Self::ProtocolError => "Payload for Action is incomplete",
55            Self::SecurityError => {
56                "During the processing of Action a security issue occurred preventing receiver from completing the Action successfully"
57            }
58            Self::FormationViolation => {
59                "Payload for Action is syntactically incorrect or not conform the PDU structure for Action"
60            }
61            Self::PropertyConstraintViolation => {
62                "Payload is syntactically correct but at least one field contains an invalid value"
63            }
64            Self::OccurenceConstraintViolation => {
65                "Payload for Action is syntactically correct but at least one of the fields violates occurence constraints"
66            }
67            Self::TypeConstraintViolation => {
68                "Payload for Action is syntactically correct but at least one of the fields violates data type constraints (e.g. \"somestring\": 12)"
69            }
70            Self::GenericError => "Any other error not covered by the previous ones",
71        }
72    }
73}
74
75impl core::fmt::Display for RpcErrorCode {
76    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77        f.write_str(self.description())
78    }
79}
80
81impl core::error::Error for RpcErrorCode {}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn has_exactly_the_ten_codes_defined_by_the_ocpp_1_6j_spec() {
89        let all = [
90            RpcErrorCode::NotImplemented,
91            RpcErrorCode::NotSupported,
92            RpcErrorCode::InternalError,
93            RpcErrorCode::ProtocolError,
94            RpcErrorCode::SecurityError,
95            RpcErrorCode::FormationViolation,
96            RpcErrorCode::PropertyConstraintViolation,
97            RpcErrorCode::OccurenceConstraintViolation,
98            RpcErrorCode::TypeConstraintViolation,
99            RpcErrorCode::GenericError,
100        ];
101
102        assert_eq!(all.len(), 10);
103    }
104
105    #[test]
106    fn display_shows_the_spec_description() {
107        use core::fmt::Write;
108        let mut buf = heapless::String::<128>::new();
109        write!(buf, "{}", RpcErrorCode::NotImplemented).unwrap();
110
111        assert_eq!(buf.as_str(), "Requested Action is not known by receiver");
112    }
113
114    #[test]
115    fn implements_the_core_error_trait() {
116        fn assert_error<T: core::error::Error>() {}
117        assert_error::<RpcErrorCode>();
118    }
119
120    #[cfg(feature = "serde")]
121    #[test]
122    fn serializes_using_the_exact_wire_spelling() {
123        let mut buf = [0u8; 64];
124        let json = serde_json_core::to_slice(&RpcErrorCode::OccurenceConstraintViolation, &mut buf)
125            .unwrap();
126
127        assert_eq!(&buf[..json], br#""OccurenceConstraintViolation""#);
128    }
129}