1use crate::error::AraComError;
8use crate::transport::{AraDeserialize, AraSerialize};
9
10macro_rules! impl_int {
15 ($t:ty) => {
16 impl AraSerialize for $t {
17 fn ara_serialize(&self, buf: &mut Vec<u8>) -> Result<(), AraComError> {
18 buf.extend_from_slice(&self.to_be_bytes());
19 Ok(())
20 }
21
22 fn serialized_size(&self) -> usize {
23 std::mem::size_of::<$t>()
24 }
25 }
26
27 impl AraDeserialize for $t {
28 fn ara_deserialize(buf: &[u8]) -> Result<Self, AraComError> {
29 const N: usize = std::mem::size_of::<$t>();
30 if buf.len() < N {
31 return Err(AraComError::Deserialization {
32 message: format!(
33 "need {} bytes for {}, got {}",
34 N,
35 stringify!($t),
36 buf.len()
37 ),
38 });
39 }
40 let arr: [u8; N] = buf[..N].try_into().unwrap();
41 Ok(<$t>::from_be_bytes(arr))
42 }
43 }
44 };
45}
46
47impl_int!(u8);
48impl_int!(u16);
49impl_int!(u32);
50impl_int!(u64);
51impl_int!(i8);
52impl_int!(i16);
53impl_int!(i32);
54impl_int!(i64);
55
56impl AraSerialize for f32 {
61 fn ara_serialize(&self, buf: &mut Vec<u8>) -> Result<(), AraComError> {
62 buf.extend_from_slice(&self.to_bits().to_be_bytes());
63 Ok(())
64 }
65
66 fn serialized_size(&self) -> usize {
67 4
68 }
69}
70
71impl AraDeserialize for f32 {
72 fn ara_deserialize(buf: &[u8]) -> Result<Self, AraComError> {
73 if buf.len() < 4 {
74 return Err(AraComError::Deserialization {
75 message: format!("need 4 bytes for f32, got {}", buf.len()),
76 });
77 }
78 let arr: [u8; 4] = buf[..4].try_into().unwrap();
79 Ok(f32::from_bits(u32::from_be_bytes(arr)))
80 }
81}
82
83impl AraSerialize for f64 {
88 fn ara_serialize(&self, buf: &mut Vec<u8>) -> Result<(), AraComError> {
89 buf.extend_from_slice(&self.to_bits().to_be_bytes());
90 Ok(())
91 }
92
93 fn serialized_size(&self) -> usize {
94 8
95 }
96}
97
98impl AraDeserialize for f64 {
99 fn ara_deserialize(buf: &[u8]) -> Result<Self, AraComError> {
100 if buf.len() < 8 {
101 return Err(AraComError::Deserialization {
102 message: format!("need 8 bytes for f64, got {}", buf.len()),
103 });
104 }
105 let arr: [u8; 8] = buf[..8].try_into().unwrap();
106 Ok(f64::from_bits(u64::from_be_bytes(arr)))
107 }
108}
109
110impl AraSerialize for bool {
115 fn ara_serialize(&self, buf: &mut Vec<u8>) -> Result<(), AraComError> {
116 buf.push(if *self { 0x01 } else { 0x00 });
117 Ok(())
118 }
119
120 fn serialized_size(&self) -> usize {
121 1
122 }
123}
124
125impl AraDeserialize for bool {
126 fn ara_deserialize(buf: &[u8]) -> Result<Self, AraComError> {
127 if buf.is_empty() {
128 return Err(AraComError::Deserialization {
129 message: "need 1 byte for bool, got 0".to_string(),
130 });
131 }
132 match buf[0] {
133 0x00 => Ok(false),
134 0x01 => Ok(true),
135 v => Err(AraComError::Deserialization {
136 message: format!("invalid bool byte: 0x{v:02X}"),
137 }),
138 }
139 }
140}
141
142const UTF8_BOM: [u8; 3] = [0xEF, 0xBB, 0xBF];
151
152impl AraSerialize for String {
153 fn ara_serialize(&self, buf: &mut Vec<u8>) -> Result<(), AraComError> {
154 if self.is_empty() {
155 buf.extend_from_slice(&0u32.to_be_bytes());
156 return Ok(());
157 }
158 let bytes = self.as_bytes();
159 let total_len = (3 + bytes.len() + 1) as u32;
161 buf.extend_from_slice(&total_len.to_be_bytes());
162 buf.extend_from_slice(&UTF8_BOM);
163 buf.extend_from_slice(bytes);
164 buf.push(0x00);
165 Ok(())
166 }
167
168 fn serialized_size(&self) -> usize {
169 if self.is_empty() {
170 4
171 } else {
172 4 + 3 + self.len() + 1
173 }
174 }
175}
176
177impl AraDeserialize for String {
178 fn ara_deserialize(buf: &[u8]) -> Result<Self, AraComError> {
179 if buf.len() < 4 {
180 return Err(AraComError::Deserialization {
181 message: format!("need 4-byte length prefix for String, got {}", buf.len()),
182 });
183 }
184 let len = u32::from_be_bytes(buf[..4].try_into().unwrap()) as usize;
185 if len == 0 {
186 return Ok(String::new());
187 }
188 if buf.len() < 4 + len {
189 return Err(AraComError::Deserialization {
190 message: format!(
191 "String payload truncated: need {} bytes, got {}",
192 len,
193 buf.len() - 4
194 ),
195 });
196 }
197 let payload = &buf[4..4 + len];
198 let content = if payload.starts_with(&UTF8_BOM) {
200 &payload[3..]
201 } else {
202 payload
203 };
204 let content = if content.last() == Some(&0x00) {
206 &content[..content.len() - 1]
207 } else {
208 content
209 };
210 let s = std::str::from_utf8(content).map_err(|e| AraComError::Deserialization {
211 message: format!("String is not valid UTF-8: {e}"),
212 })?;
213 Ok(s.to_owned())
214 }
215}
216
217impl<T: AraSerialize> AraSerialize for Vec<T> {
224 fn ara_serialize(&self, buf: &mut Vec<u8>) -> Result<(), AraComError> {
225 let capacity: usize = self.iter().map(|item| item.serialized_size()).sum();
226 let mut elements_buf: Vec<u8> = Vec::with_capacity(capacity);
227 for item in self {
228 item.ara_serialize(&mut elements_buf)?;
229 }
230 let byte_len = elements_buf.len() as u32;
231 buf.extend_from_slice(&byte_len.to_be_bytes());
232 buf.extend_from_slice(&elements_buf);
233 Ok(())
234 }
235
236 fn serialized_size(&self) -> usize {
237 4 + self
238 .iter()
239 .map(|item| item.serialized_size())
240 .sum::<usize>()
241 }
242}
243
244impl<T: AraDeserialize + AraSerialize> AraDeserialize for Vec<T> {
245 fn ara_deserialize(buf: &[u8]) -> Result<Self, AraComError> {
246 if buf.len() < 4 {
247 return Err(AraComError::Deserialization {
248 message: format!("need 4-byte byte-length prefix for Vec, got {}", buf.len()),
249 });
250 }
251 let byte_len = u32::from_be_bytes(buf[..4].try_into().unwrap()) as usize;
252 if buf.len() < 4 + byte_len {
253 return Err(AraComError::Deserialization {
254 message: format!(
255 "Vec payload truncated: need {} bytes, got {}",
256 byte_len,
257 buf.len() - 4
258 ),
259 });
260 }
261 let payload = &buf[4..4 + byte_len];
262 let mut offset = 0;
263 let mut result = Vec::new();
264 while offset < payload.len() {
265 let item = T::ara_deserialize(&payload[offset..])?;
266 offset += item.serialized_size();
267 if offset > payload.len() {
268 return Err(AraComError::Deserialization {
269 message: format!(
270 "Vec element overran payload: offset {} exceeds {} bytes",
271 offset,
272 payload.len()
273 ),
274 });
275 }
276 result.push(item);
277 }
278 Ok(result)
279 }
280}
281
282#[cfg(test)]
287mod tests {
288 use super::*;
289
290 fn round_trip<T>(value: T) -> T
291 where
292 T: AraSerialize + AraDeserialize + Copy + std::fmt::Debug + PartialEq,
293 {
294 let mut buf = Vec::new();
295 value.ara_serialize(&mut buf).unwrap();
296 assert_eq!(buf.len(), value.serialized_size());
297 T::ara_deserialize(&buf).unwrap()
298 }
299
300 #[test]
303 fn test_u8_round_trip() {
304 assert_eq!(round_trip(0u8), 0);
305 assert_eq!(round_trip(255u8), 255);
306 }
307
308 #[test]
309 fn test_u16_big_endian() {
310 let mut buf = Vec::new();
311 0x0102u16.ara_serialize(&mut buf).unwrap();
312 assert_eq!(buf, [0x01, 0x02]);
313 assert_eq!(u16::ara_deserialize(&buf).unwrap(), 0x0102);
314 }
315
316 #[test]
317 fn test_u32_round_trip() {
318 assert_eq!(round_trip(0xDEAD_BEEFu32), 0xDEAD_BEEF);
319 }
320
321 #[test]
322 fn test_u64_round_trip() {
323 assert_eq!(round_trip(u64::MAX), u64::MAX);
324 }
325
326 #[test]
327 fn test_i32_negative() {
328 assert_eq!(round_trip(-1i32), -1);
329 assert_eq!(round_trip(i32::MIN), i32::MIN);
330 }
331
332 #[test]
333 fn test_f32_round_trip() {
334 assert_eq!(round_trip(1.5f32), 1.5f32);
335 assert!(round_trip(f32::NAN).is_nan());
336 }
337
338 #[test]
339 fn test_f64_round_trip() {
340 assert_eq!(round_trip(std::f64::consts::PI), std::f64::consts::PI);
341 }
342
343 #[test]
344 fn test_bool_round_trip() {
345 assert!(!round_trip(false));
346 assert!(round_trip(true));
347 }
348
349 #[test]
350 fn test_bool_encoding() {
351 let mut buf = Vec::new();
352 true.ara_serialize(&mut buf).unwrap();
353 assert_eq!(buf, [0x01]);
354 let mut buf = Vec::new();
355 false.ara_serialize(&mut buf).unwrap();
356 assert_eq!(buf, [0x00]);
357 }
358
359 #[test]
360 fn test_deserialize_insufficient_bytes() {
361 let result = u32::ara_deserialize(&[0x00, 0x01]);
362 assert!(result.is_err());
363 }
364
365 #[test]
366 fn test_bool_invalid_byte() {
367 let result = bool::ara_deserialize(&[0x02]);
368 assert!(result.is_err());
369 }
370
371 #[test]
374 fn test_string_round_trip() {
375 let original = "hello SOME/IP".to_string();
376 let mut buf = Vec::new();
377 original.ara_serialize(&mut buf).unwrap();
378 assert_eq!(buf.len(), original.serialized_size());
379 let decoded = String::ara_deserialize(&buf).unwrap();
380 assert_eq!(decoded, original);
381 }
382
383 #[test]
384 fn test_empty_string() {
385 let original = String::new();
386 let mut buf = Vec::new();
387 original.ara_serialize(&mut buf).unwrap();
388 assert_eq!(buf, [0x00, 0x00, 0x00, 0x00]);
390 assert_eq!(String::ara_deserialize(&buf).unwrap(), "");
391 }
392
393 #[test]
394 fn test_string_bom_nul() {
395 let s = "AB".to_string();
397 let mut buf = Vec::new();
398 s.ara_serialize(&mut buf).unwrap();
399 assert_eq!(
400 buf,
401 [0x00, 0x00, 0x00, 0x06, 0xEF, 0xBB, 0xBF, 0x41, 0x42, 0x00]
402 );
403 }
404
405 #[test]
408 fn test_vec_u32_round_trip() {
409 let original: Vec<u32> = vec![1, 2, 3, 0xDEAD_BEEF];
410 let mut buf = Vec::new();
411 original.ara_serialize(&mut buf).unwrap();
412 assert_eq!(buf.len(), original.serialized_size());
413 assert_eq!(&buf[..4], &[0x00, 0x00, 0x00, 0x10]);
414 let decoded: Vec<u32> = Vec::ara_deserialize(&buf).unwrap();
415 assert_eq!(decoded, original);
416 }
417
418 #[test]
419 fn test_empty_vec() {
420 let original: Vec<u8> = vec![];
421 let mut buf = Vec::new();
422 original.ara_serialize(&mut buf).unwrap();
423 assert_eq!(buf, [0x00, 0x00, 0x00, 0x00]);
424 let decoded: Vec<u8> = Vec::ara_deserialize(&buf).unwrap();
425 assert!(decoded.is_empty());
426 }
427
428 #[test]
429 fn test_vec_u16_byte_length() {
430 let v: Vec<u16> = vec![1u16, 2u16];
432 let mut buf = Vec::new();
433 v.ara_serialize(&mut buf).unwrap();
434 assert_eq!(&buf[..4], &[0x00, 0x00, 0x00, 0x04]);
435 }
436}