1#[derive(Debug, Clone, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct MessageId(heapless::String<36>);
13
14impl MessageId {
15 pub fn as_str(&self) -> &str {
16 &self.0
17 }
18}
19
20impl TryFrom<&str> for MessageId {
21 type Error = ();
22
23 fn try_from(value: &str) -> Result<Self, Self::Error> {
24 heapless::String::try_from(value).map(Self).map_err(|_| ())
27 }
28}
29
30#[cfg(feature = "serde")]
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
39pub struct EmptyPayload;
40
41#[cfg(feature = "serde")]
42impl serde::Serialize for EmptyPayload {
43 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
44 use serde::ser::SerializeMap;
45 serializer.serialize_map(Some(0))?.end()
46 }
47}
48
49#[cfg(feature = "serde")]
50impl<'de> serde::Deserialize<'de> for EmptyPayload {
51 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
52 struct EmptyPayloadVisitor;
53
54 impl<'de> serde::de::Visitor<'de> for EmptyPayloadVisitor {
55 type Value = EmptyPayload;
56
57 fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
58 f.write_str("a JSON object")
59 }
60
61 fn visit_map<A: serde::de::MapAccess<'de>>(
62 self,
63 mut map: A,
64 ) -> Result<Self::Value, A::Error> {
65 while map
66 .next_entry::<serde::de::IgnoredAny, serde::de::IgnoredAny>()?
67 .is_some()
68 {}
69 Ok(EmptyPayload)
70 }
71 }
72
73 deserializer.deserialize_map(EmptyPayloadVisitor)
74 }
75}
76
77#[cfg(feature = "serde")]
82#[derive(Debug, Clone, PartialEq, Eq)]
83pub struct Call<T> {
84 pub message_id: MessageId,
85 pub payload: T,
86}
87
88#[cfg(feature = "serde")]
89impl<T: crate::Action + serde::Serialize> serde::Serialize for Call<T> {
90 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
91 use serde::ser::SerializeTuple;
92
93 let mut tup = serializer.serialize_tuple(4)?;
94 tup.serialize_element(&2u8)?;
95 tup.serialize_element(&self.message_id)?;
96 tup.serialize_element(T::ACTION)?;
97 tup.serialize_element(&self.payload)?;
98 tup.end()
99 }
100}
101
102#[cfg(feature = "serde")]
103impl<'de, T: crate::Action + serde::Deserialize<'de>> serde::Deserialize<'de> for Call<T> {
104 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
105 struct CallVisitor<T>(core::marker::PhantomData<T>);
106
107 impl<'de, T: crate::Action + serde::Deserialize<'de>> serde::de::Visitor<'de> for CallVisitor<T> {
108 type Value = Call<T>;
109
110 fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
111 write!(f, "a CALL array [2, messageId, \"{}\", payload]", T::ACTION)
112 }
113
114 fn visit_seq<A: serde::de::SeqAccess<'de>>(
115 self,
116 mut seq: A,
117 ) -> Result<Self::Value, A::Error> {
118 let message_type_id: u8 = seq
119 .next_element()?
120 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
121 if message_type_id != 2 {
122 return Err(serde::de::Error::invalid_value(
123 serde::de::Unexpected::Unsigned(message_type_id as u64),
124 &"2 (CALL)",
125 ));
126 }
127
128 let message_id: MessageId = seq
129 .next_element()?
130 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
131
132 let action: &str = seq
133 .next_element()?
134 .ok_or_else(|| serde::de::Error::invalid_length(2, &self))?;
135 if action != T::ACTION {
136 return Err(serde::de::Error::invalid_value(
137 serde::de::Unexpected::Str(action),
138 &T::ACTION,
139 ));
140 }
141
142 let payload: T = seq
143 .next_element()?
144 .ok_or_else(|| serde::de::Error::invalid_length(3, &self))?;
145
146 Ok(Call {
147 message_id,
148 payload,
149 })
150 }
151 }
152
153 deserializer.deserialize_tuple(4, CallVisitor(core::marker::PhantomData))
154 }
155}
156
157#[cfg(feature = "serde")]
162#[derive(Debug, Clone, PartialEq, Eq)]
163pub struct CallResult<T> {
164 pub message_id: MessageId,
165 pub payload: T,
166}
167
168#[cfg(feature = "serde")]
169impl<T: serde::Serialize> serde::Serialize for CallResult<T> {
170 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
171 use serde::ser::SerializeTuple;
172
173 let mut tup = serializer.serialize_tuple(3)?;
174 tup.serialize_element(&3u8)?;
175 tup.serialize_element(&self.message_id)?;
176 tup.serialize_element(&self.payload)?;
177 tup.end()
178 }
179}
180
181#[cfg(feature = "serde")]
182impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for CallResult<T> {
183 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
184 struct CallResultVisitor<T>(core::marker::PhantomData<T>);
185
186 impl<'de, T: serde::Deserialize<'de>> serde::de::Visitor<'de> for CallResultVisitor<T> {
187 type Value = CallResult<T>;
188
189 fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
190 f.write_str("a CALLRESULT array [3, messageId, payload]")
191 }
192
193 fn visit_seq<A: serde::de::SeqAccess<'de>>(
194 self,
195 mut seq: A,
196 ) -> Result<Self::Value, A::Error> {
197 let message_type_id: u8 = seq
198 .next_element()?
199 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
200 if message_type_id != 3 {
201 return Err(serde::de::Error::invalid_value(
202 serde::de::Unexpected::Unsigned(message_type_id as u64),
203 &"3 (CALLRESULT)",
204 ));
205 }
206
207 let message_id: MessageId = seq
208 .next_element()?
209 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
210
211 let payload: T = seq
212 .next_element()?
213 .ok_or_else(|| serde::de::Error::invalid_length(2, &self))?;
214
215 Ok(CallResult {
216 message_id,
217 payload,
218 })
219 }
220 }
221
222 deserializer.deserialize_tuple(3, CallResultVisitor(core::marker::PhantomData))
223 }
224}
225
226macro_rules! error_envelope {
232 ($name:ident, $discriminant:literal, $expecting:literal) => {
233 #[cfg(feature = "serde")]
234 #[derive(Debug, Clone, PartialEq, Eq)]
235 pub struct $name<E, D = EmptyPayload, const DESC_CAP: usize = 1024> {
236 pub message_id: MessageId,
237 pub error_code: E,
238 pub error_description: heapless::String<DESC_CAP>,
239 pub error_details: D,
240 }
241
242 #[cfg(feature = "serde")]
243 impl<E: serde::Serialize, D: serde::Serialize, const DESC_CAP: usize> serde::Serialize
244 for $name<E, D, DESC_CAP>
245 {
246 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
247 use serde::ser::SerializeTuple;
248
249 let mut tup = serializer.serialize_tuple(5)?;
250 tup.serialize_element(&$discriminant)?;
251 tup.serialize_element(&self.message_id)?;
252 tup.serialize_element(&self.error_code)?;
253 tup.serialize_element(&self.error_description)?;
254 tup.serialize_element(&self.error_details)?;
255 tup.end()
256 }
257 }
258
259 #[cfg(feature = "serde")]
260 impl<'de, E: serde::Deserialize<'de>, D: serde::Deserialize<'de>, const DESC_CAP: usize>
261 serde::Deserialize<'de> for $name<E, D, DESC_CAP>
262 {
263 fn deserialize<Dz: serde::Deserializer<'de>>(deserializer: Dz) -> Result<Self, Dz::Error> {
264 struct Visitor<E, D, const DESC_CAP: usize>(core::marker::PhantomData<(E, D)>);
265
266 impl<'de, E: serde::Deserialize<'de>, D: serde::Deserialize<'de>, const DESC_CAP: usize>
267 serde::de::Visitor<'de> for Visitor<E, D, DESC_CAP>
268 {
269 type Value = $name<E, D, DESC_CAP>;
270
271 fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
272 f.write_str($expecting)
273 }
274
275 fn visit_seq<A: serde::de::SeqAccess<'de>>(
276 self,
277 mut seq: A,
278 ) -> Result<Self::Value, A::Error> {
279 let message_type_id: u8 = seq
280 .next_element()?
281 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
282 if message_type_id != $discriminant {
283 return Err(serde::de::Error::invalid_value(
284 serde::de::Unexpected::Unsigned(message_type_id as u64),
285 &$expecting,
286 ));
287 }
288
289 let message_id = seq
290 .next_element()?
291 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
292 let error_code = seq
293 .next_element()?
294 .ok_or_else(|| serde::de::Error::invalid_length(2, &self))?;
295 let error_description = seq
296 .next_element()?
297 .ok_or_else(|| serde::de::Error::invalid_length(3, &self))?;
298 let error_details = seq
299 .next_element()?
300 .ok_or_else(|| serde::de::Error::invalid_length(4, &self))?;
301
302 Ok($name {
303 message_id,
304 error_code,
305 error_description,
306 error_details,
307 })
308 }
309 }
310
311 deserializer.deserialize_tuple(5, Visitor(core::marker::PhantomData))
312 }
313 }
314 };
315}
316
317error_envelope!(
326 CallError,
327 4u8,
328 "a CALLERROR array [4, messageId, errorCode, errorDescription, errorDetails]"
329);
330
331error_envelope!(
335 CallResultError,
336 5u8,
337 "a CALLRESULTERROR array [5, messageId, errorCode, errorDescription, errorDetails]"
338);
339
340#[cfg(feature = "serde")]
345#[derive(Debug, Clone, PartialEq, Eq)]
346pub struct SendMessage<T> {
347 pub message_id: MessageId,
348 pub payload: T,
349}
350
351#[cfg(feature = "serde")]
352impl<T: crate::Action + serde::Serialize> serde::Serialize for SendMessage<T> {
353 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
354 use serde::ser::SerializeTuple;
355
356 let mut tup = serializer.serialize_tuple(4)?;
357 tup.serialize_element(&6u8)?;
358 tup.serialize_element(&self.message_id)?;
359 tup.serialize_element(T::ACTION)?;
360 tup.serialize_element(&self.payload)?;
361 tup.end()
362 }
363}
364
365#[cfg(feature = "serde")]
366impl<'de, T: crate::Action + serde::Deserialize<'de>> serde::Deserialize<'de> for SendMessage<T> {
367 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
368 struct SendVisitor<T>(core::marker::PhantomData<T>);
369
370 impl<'de, T: crate::Action + serde::Deserialize<'de>> serde::de::Visitor<'de> for SendVisitor<T> {
371 type Value = SendMessage<T>;
372
373 fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
374 write!(f, "a SEND array [6, messageId, \"{}\", payload]", T::ACTION)
375 }
376
377 fn visit_seq<A: serde::de::SeqAccess<'de>>(
378 self,
379 mut seq: A,
380 ) -> Result<Self::Value, A::Error> {
381 let message_type_id: u8 = seq
382 .next_element()?
383 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
384 if message_type_id != 6 {
385 return Err(serde::de::Error::invalid_value(
386 serde::de::Unexpected::Unsigned(message_type_id as u64),
387 &"6 (SEND)",
388 ));
389 }
390
391 let message_id: MessageId = seq
392 .next_element()?
393 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
394
395 let action: &str = seq
396 .next_element()?
397 .ok_or_else(|| serde::de::Error::invalid_length(2, &self))?;
398 if action != T::ACTION {
399 return Err(serde::de::Error::invalid_value(
400 serde::de::Unexpected::Str(action),
401 &T::ACTION,
402 ));
403 }
404
405 let payload: T = seq
406 .next_element()?
407 .ok_or_else(|| serde::de::Error::invalid_length(3, &self))?;
408
409 Ok(SendMessage {
410 message_id,
411 payload,
412 })
413 }
414 }
415
416 deserializer.deserialize_tuple(4, SendVisitor(core::marker::PhantomData))
417 }
418}
419
420#[cfg(test)]
421mod tests {
422 use super::*;
423
424 extern crate std;
428
429 #[cfg(feature = "serde")]
430 #[test]
431 fn empty_payload_serializes_as_an_empty_object() {
432 let mut buf = [0u8; 16];
433 let len = serde_json_core::to_slice(&EmptyPayload, &mut buf).unwrap();
434 assert_eq!(&buf[..len], b"{}");
435 }
436
437 #[cfg(feature = "serde")]
438 #[test]
439 fn empty_payload_accepts_and_discards_a_populated_object() {
440 let (parsed, _): (EmptyPayload, usize) =
441 serde_json_core::from_str(r#"{"foo": 1, "bar": [1, 2, 3]}"#).unwrap();
442 assert_eq!(parsed, EmptyPayload);
443 }
444
445 #[cfg(feature = "serde")]
446 #[test]
447 fn call_serializes_and_round_trips_a_real_message_type() {
448 use crate::v16::{AuthorizeRequest, IdTag};
449
450 let call = Call {
451 message_id: MessageId::try_from("19223201").unwrap(),
452 payload: AuthorizeRequest {
453 id_tag: IdTag::try_from("ABC123").unwrap(),
454 },
455 };
456
457 let mut buf = [0u8; 128];
458 let len = serde_json_core::to_slice(&call, &mut buf).unwrap();
459 assert_eq!(
460 core::str::from_utf8(&buf[..len]).unwrap(),
461 r#"[2,"19223201","Authorize",{"idTag":"ABC123"}]"#
462 );
463
464 let (parsed, _): (Call<AuthorizeRequest>, usize) =
465 serde_json_core::from_slice(&buf[..len]).unwrap();
466 assert_eq!(parsed, call);
467 }
468
469 #[cfg(feature = "serde")]
470 #[test]
471 fn call_rejects_the_wrong_message_type_id() {
472 use crate::v16::AuthorizeRequest;
473
474 let json = r#"[3,"1","Authorize",{"idTag":"ABC123"}]"#;
475 let result: Result<(Call<AuthorizeRequest>, usize), _> = serde_json_core::from_str(json);
476 assert!(result.is_err());
477 }
478
479 #[cfg(feature = "serde")]
480 #[test]
481 fn call_rejects_a_mismatched_action() {
482 use crate::v16::AuthorizeRequest;
483
484 let json = r#"[2,"1","Heartbeat",{"idTag":"ABC123"}]"#;
485 let result: Result<(Call<AuthorizeRequest>, usize), _> = serde_json_core::from_str(json);
486 assert!(result.is_err());
487 }
488
489 #[cfg(all(feature = "serde", not(feature = "alloc")))]
493 #[test]
494 fn call_result_serializes_and_round_trips_a_real_message_type() {
495 use crate::v16::HeartbeatResponse;
496
497 let result: CallResult<HeartbeatResponse> = CallResult {
498 message_id: MessageId::try_from("19223201").unwrap(),
499 payload: HeartbeatResponse {
500 current_time: crate::OcppTimestamp::parse_rfc3339("2013-02-01T20:53:32.486Z").unwrap(),
501 },
502 };
503
504 let mut buf = [0u8; 128];
505 let len = serde_json_core::to_slice(&result, &mut buf).unwrap();
506 assert_eq!(
507 core::str::from_utf8(&buf[..len]).unwrap(),
508 r#"[3,"19223201",{"currentTime":"2013-02-01T20:53:32.486Z"}]"#
509 );
510
511 let (parsed, _): (CallResult<HeartbeatResponse>, usize) =
512 serde_json_core::from_slice(&buf[..len]).unwrap();
513 assert_eq!(parsed, result);
514 }
515
516 #[cfg(feature = "serde")]
517 #[test]
518 fn call_result_rejects_the_wrong_message_type_id() {
519 use crate::v16::HeartbeatResponse;
520
521 let json = r#"[2,"1",{"currentTime":"2013-02-01T20:53:32.486Z"}]"#;
522 let result: Result<(CallResult<HeartbeatResponse>, usize), _> =
523 serde_json_core::from_str(json);
524 assert!(result.is_err());
525 }
526
527 #[cfg(feature = "serde")]
528 #[test]
529 fn call_error_serializes_and_round_trips_a_real_error_code() {
530 use crate::v16::RpcErrorCode;
531
532 let error: CallError<RpcErrorCode> = CallError {
533 message_id: MessageId::try_from("19223201").unwrap(),
534 error_code: RpcErrorCode::NotImplemented,
535 error_description: heapless::String::try_from("unrecognized action").unwrap(),
536 error_details: EmptyPayload,
537 };
538
539 let mut buf = [0u8; 128];
540 let len = serde_json_core::to_slice(&error, &mut buf).unwrap();
541 assert_eq!(
542 core::str::from_utf8(&buf[..len]).unwrap(),
543 r#"[4,"19223201","NotImplemented","unrecognized action",{}]"#
544 );
545
546 let (parsed, _): (CallError<RpcErrorCode>, usize) =
547 serde_json_core::from_slice(&buf[..len]).unwrap();
548 assert_eq!(parsed, error);
549 }
550
551 #[cfg(feature = "serde")]
552 #[test]
553 fn call_error_rejects_the_wrong_message_type_id() {
554 use crate::v16::RpcErrorCode;
555
556 let json = r#"[5,"1","NotImplemented","",{}]"#;
557 let result: Result<(CallError<RpcErrorCode>, usize), _> = serde_json_core::from_str(json);
558 assert!(result.is_err());
559 }
560
561 #[cfg(feature = "serde")]
562 #[test]
563 fn call_result_error_uses_discriminant_five_not_four() {
564 use crate::v201::RpcErrorCode;
565
566 let error: CallResultError<RpcErrorCode> = CallResultError {
567 message_id: MessageId::try_from("1").unwrap(),
568 error_code: RpcErrorCode::FormatViolation,
569 error_description: heapless::String::try_from("").unwrap(),
570 error_details: EmptyPayload,
571 };
572
573 let mut buf = [0u8; 128];
574 let len = serde_json_core::to_slice(&error, &mut buf).unwrap();
575 assert!(core::str::from_utf8(&buf[..len]).unwrap().starts_with("[5,"));
576
577 let call_error_json = r#"[4,"1","FormatViolation","",{}]"#;
580 let result: Result<(CallResultError<RpcErrorCode>, usize), _> =
581 serde_json_core::from_str(call_error_json);
582 assert!(result.is_err());
583 }
584
585 #[cfg(all(feature = "serde", not(feature = "alloc")))]
586 #[test]
587 fn send_message_serializes_and_round_trips_a_real_send_type_message() {
588 std::thread::Builder::new()
602 .stack_size(16 * 1024 * 1024)
603 .spawn(|| {
604 use crate::v21::NotifyPeriodicEventStream;
605
606 let send: SendMessage<NotifyPeriodicEventStream> = SendMessage {
607 message_id: MessageId::try_from("19223201").unwrap(),
608 payload: NotifyPeriodicEventStream {
609 basetime: crate::OcppTimestamp::parse_rfc3339("2024-08-27T12:30:40Z").unwrap(),
610 custom_data: None,
611 data: heapless::Vec::new(),
612 id: 123,
613 pending: 0,
614 },
615 };
616
617 let mut buf = [0u8; 256];
618 let len = serde_json_core::to_slice(&send, &mut buf).unwrap();
619 let json = core::str::from_utf8(&buf[..len]).unwrap();
620 assert!(json.starts_with(r#"[6,"19223201","NotifyPeriodicEventStream","#));
621
622 let (parsed, _): (SendMessage<NotifyPeriodicEventStream>, usize) =
623 serde_json_core::from_slice(&buf[..len]).unwrap();
624 assert_eq!(parsed, send);
625 })
626 .unwrap()
627 .join()
628 .unwrap();
629 }
630
631 #[test]
632 fn message_id_round_trips_a_short_string() {
633 let id = MessageId::try_from("19223201").unwrap();
634 assert_eq!(id.as_str(), "19223201");
635 }
636
637 #[test]
638 fn message_id_rejects_strings_over_36_bytes() {
639 let too_long = "a".repeat(37);
640 assert!(MessageId::try_from(too_long.as_str()).is_err());
641 }
642
643 #[test]
644 fn message_id_accepts_exactly_36_bytes() {
645 let exactly_36 = "a".repeat(36);
646 assert!(MessageId::try_from(exactly_36.as_str()).is_ok());
647 }
648
649 #[test]
655 fn message_id_error_type_stays_unit_regardless_of_the_heapless_version() {
656 fn assert_unit_error<T>()
657 where
658 for<'a> T: TryFrom<&'a str, Error = ()>,
659 {
660 }
661
662 assert_unit_error::<MessageId>();
663 }
664}