Skip to main content

ocpp_types/v21/
error.rs

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