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