Skip to main content

ara_com/
serialization.rs

1//! Standard-type impls for `AraSerialize` / `AraDeserialize`.
2//!
3//! These impls live in `ara-com` (where the traits are defined) so that the
4//! orphan rule is satisfied.  Transport backends such as `ara-com-someip`
5//! re-export these impls and add **only** backend-specific helpers on top.
6
7use crate::error::AraComError;
8use crate::transport::{AraDeserialize, AraSerialize};
9
10// ---------------------------------------------------------------------------
11// Helper macro — big-endian integer types
12// ---------------------------------------------------------------------------
13
14macro_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
56// ---------------------------------------------------------------------------
57// f32
58// ---------------------------------------------------------------------------
59
60impl 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
83// ---------------------------------------------------------------------------
84// f64
85// ---------------------------------------------------------------------------
86
87impl 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
110// ---------------------------------------------------------------------------
111// bool — 0x00 = false, 0x01 = true
112// ---------------------------------------------------------------------------
113
114impl 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
142// ---------------------------------------------------------------------------
143// String — SOME/IP wire format:
144//   4-byte big-endian total byte length (including BOM + NUL) +
145//   UTF-8 BOM (0xEF 0xBB 0xBF) + UTF-8 bytes + NUL (0x00)
146//
147// Special case: empty string serializes as 4 zero bytes only (vsomeip compat).
148// ---------------------------------------------------------------------------
149
150const 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        // total length = 3 (BOM) + string bytes + 1 (NUL)
160        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        // Skip UTF-8 BOM if present
199        let content = if payload.starts_with(&UTF8_BOM) {
200            &payload[3..]
201        } else {
202            payload
203        };
204        // Strip trailing NUL if present
205        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
217// ---------------------------------------------------------------------------
218// Vec<T> — SOME/IP wire format:
219//   4-byte big-endian **byte length** of all serialized elements, then elements.
220//   (NOT element count — SOME/IP uses byte length prefix per PRS_SOMEIP_00462)
221// ---------------------------------------------------------------------------
222
223impl<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// ---------------------------------------------------------------------------
283// Tests
284// ---------------------------------------------------------------------------
285
286#[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    // --- integer types ---
301
302    #[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    // --- String ---
372
373    #[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        // Empty string: just 4 zero bytes (vsomeip compat — no BOM/NUL)
389        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        // "AB" => length=6 (3 BOM + 2 chars + 1 NUL), then BOM, "A", "B", NUL
396        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    // --- Vec<T> ---
406
407    #[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        // 2 x u16 = 4 bytes of payload, so prefix should be 0x00000004, NOT element count 0x00000002
431        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}