1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub enum RpcErrorCode {
9 FormatViolation,
11 GenericError,
14 InternalError,
17 MessageTypeNotSupported,
20 NotImplemented,
22 NotSupported,
24 OccurrenceConstraintViolation,
27 PropertyConstraintViolation,
30 ProtocolError,
32 RpcFrameworkError,
35 SecurityError,
38 TypeConstraintViolation,
41}
42
43impl RpcErrorCode {
44 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}