1use doip_definitions::{header::PayloadType, payload::DoipPayload, DoipMessage};
2use heapless::Vec;
3
4use crate::{
5 doip_message::{header::HeaderCodec, payload::PayloadCodec},
6 error::EncodeError,
7 DoipCodec, Encoder,
8};
9
10impl<const N: usize> Encoder<DoipMessage<N>, N> for DoipCodec<N> {
11 type Error = EncodeError;
12
13 fn to_bytes(&mut self, item: DoipMessage<N>, dst: &mut Vec<u8, N>) -> Result<(), Self::Error> {
14 validate_payload_match(&item)?;
15
16 let header_len = item.header.payload_length as usize;
17 let () = HeaderCodec {}.to_bytes(item.header, dst)?;
18
19 let before_len = dst.len();
20 let () = PayloadCodec {}.to_bytes(item.payload, dst)?;
21 let after_len = dst.len();
22
23 validate_payload_length(header_len, after_len - before_len)?;
24
25 Ok(())
26 }
27}
28
29fn validate_payload_match<const N: usize>(item: &DoipMessage<N>) -> Result<(), EncodeError> {
30 let valid = match item.payload {
31 DoipPayload::GenericNack(_) => item.header.payload_type == PayloadType::GenericNack,
32 DoipPayload::VehicleIdentificationRequest(_) => {
33 item.header.payload_type == PayloadType::VehicleIdentificationRequest
34 }
35 DoipPayload::VehicleIdentificationRequestEid(_) => {
36 item.header.payload_type == PayloadType::VehicleIdentificationRequestEid
37 }
38 DoipPayload::VehicleIdentificationRequestVin(_) => {
39 item.header.payload_type == PayloadType::VehicleIdentificationRequestVin
40 }
41 DoipPayload::VehicleAnnouncementMessage(_) => {
42 item.header.payload_type == PayloadType::VehicleAnnouncementMessage
43 }
44 DoipPayload::RoutingActivationRequest(_) => {
45 item.header.payload_type == PayloadType::RoutingActivationRequest
46 }
47 DoipPayload::RoutingActivationResponse(_) => {
48 item.header.payload_type == PayloadType::RoutingActivationResponse
49 }
50 DoipPayload::AliveCheckRequest(_) => {
51 item.header.payload_type == PayloadType::AliveCheckRequest
52 }
53 DoipPayload::AliveCheckResponse(_) => {
54 item.header.payload_type == PayloadType::AliveCheckResponse
55 }
56 DoipPayload::EntityStatusRequest(_) => {
57 item.header.payload_type == PayloadType::EntityStatusRequest
58 }
59 DoipPayload::EntityStatusResponse(_) => {
60 item.header.payload_type == PayloadType::EntityStatusResponse
61 }
62 DoipPayload::PowerInformationRequest(_) => {
63 item.header.payload_type == PayloadType::PowerInformationRequest
64 }
65 DoipPayload::PowerInformationResponse(_) => {
66 item.header.payload_type == PayloadType::PowerInformationResponse
67 }
68 DoipPayload::DiagnosticMessage(_) => {
69 item.header.payload_type == PayloadType::DiagnosticMessage
70 }
71 DoipPayload::DiagnosticMessageAck(_) => {
72 item.header.payload_type == PayloadType::DiagnosticMessageAck
73 }
74 DoipPayload::DiagnosticMessageNack(_) => {
75 item.header.payload_type == PayloadType::DiagnosticMessageNack
76 }
77 };
78
79 if valid {
80 Ok(())
81 } else {
82 Err(EncodeError::PayloadTypeValidation)
83 }
84}
85
86fn validate_payload_length(header_len: usize, length: usize) -> Result<(), EncodeError> {
87 if header_len != length {
88 return Err(EncodeError::PayloadLengthValidation);
89 }
90 Ok(())
91}
92
93#[cfg(feature = "std")]
94impl<const N: usize> tokio_util::codec::Encoder<DoipMessage<N>> for DoipCodec<N> {
95 type Error = EncodeError;
96
97 fn encode(
98 &mut self,
99 item: DoipMessage<N>,
100 dst: &mut tokio_util::bytes::BytesMut,
101 ) -> Result<(), Self::Error> {
102 println!("{:?}", item);
103 let mut heapless_dst = heapless::Vec::<u8, N>::new();
104
105 DoipCodec {}.to_bytes(item, &mut heapless_dst)?;
106 dst.extend_from_slice(&heapless_dst);
107
108 Ok(())
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use doip_definitions::{
115 header::{DoipHeader, PayloadType, ProtocolVersion},
116 payload::{AliveCheckRequest, DoipPayload, GenericNack, NackCode},
117 DoipMessage,
118 };
119
120 use crate::encoder::validate_payload_length;
121
122 use super::validate_payload_match;
123
124 #[test]
125 fn test_validate_payload_match() {
126 let item_valid = DoipMessage {
127 header: DoipHeader {
128 protocol_version: ProtocolVersion::Iso13400_2012,
129 inverse_protocol_version: 0xfd,
130 payload_type: PayloadType::GenericNack,
131 payload_length: 1u32,
132 },
133 payload: DoipPayload::<1>::GenericNack(GenericNack {
134 nack_code: NackCode::OutOfMemory,
135 }),
136 };
137 let valid = validate_payload_match(&item_valid);
138 assert!(valid.is_ok());
139
140 let item_invalid = DoipMessage {
141 header: DoipHeader {
142 protocol_version: ProtocolVersion::Iso13400_2012,
143 inverse_protocol_version: 0xfd,
144 payload_type: PayloadType::GenericNack,
145 payload_length: 1u32,
146 },
147 payload: DoipPayload::<1>::AliveCheckRequest(AliveCheckRequest {}),
148 };
149
150 let invalid = validate_payload_match(&item_invalid);
151 assert!(invalid.is_err());
152 }
153
154 #[test]
155 fn test_validate_payload_length() {
156 let valid = validate_payload_length(1, 1);
157 assert!(valid.is_ok());
158
159 let invalid = validate_payload_length(1, 2);
160 assert!(invalid.is_err());
161 }
162}