someip_sd_wire/
repr.rs

1use crate::{error::*, packet::*};
2use core::fmt;
3
4/// A high-level representation of a SOME/IP-SD message.
5///
6/// # Creating a Repr
7///
8/// The preferred way to create a `Repr` is using `Repr::new()`, which automatically
9/// calculates the correct length fields. However, you can also construct it manually
10/// using struct initialization if needed.
11#[allow(dead_code)]
12#[derive(Debug, PartialEq, Eq, Clone, Copy)]
13pub struct Repr<'a> {
14    /// Flags (1 byte) - typically used for reboot/unicast flags
15    pub flags: u8,
16    /// Reserved field (3 bytes) - should be 0x000000
17    pub reserved: u32,
18    /// Entries array (variable length)
19    pub entries: &'a [u8],
20    /// Options array (variable length)
21    pub options: &'a [u8],
22}
23
24impl<'a> Repr<'a> {
25    /// Create a new SOME/IP-SD message representation.
26    /// The length fields are automatically calculated.
27    ///
28    /// # Arguments
29    ///
30    /// * `flags` - Flags byte (reboot, unicast flags)
31    /// * `entries` - Raw entries array data
32    /// * `options` - Raw options array data
33    ///
34    /// # Returns
35    ///
36    /// A new `Repr` instance with reserved field set to 0.
37    pub fn new(flags: u8, entries: &'a [u8], options: &'a [u8]) -> Self {
38        Repr {
39            flags,
40            reserved: 0,
41            entries,
42            options,
43        }
44    }
45
46    /// Parse a SOME/IP-SD packet into a high-level representation
47    ///
48    /// # Arguments
49    ///
50    /// * `packet` - The packet to parse
51    ///
52    /// # Returns
53    ///
54    /// * `Result<Repr>` - The parsed representation or an error
55    pub fn parse<T>(packet: &'a Packet<T>) -> core::result::Result<Repr<'a>, Error>
56    where
57        T: AsRef<[u8]>,
58    {
59        packet.check_len()?;
60
61        let flags = packet.flags();
62        let reserved = packet.reserved();
63        let entries = packet.entries_array();
64        let options = packet.options_array();
65
66        Ok(Repr {
67            flags,
68            reserved,
69            entries,
70            options,
71        })
72    }
73
74    /// Emits the high-level representation of the SOME/IP-SD packet into the provided packet/buffer.
75    ///
76    /// # Arguments
77    ///
78    /// * `packet` - A mutable reference to the packet where the high-level representation will be written.
79    pub fn emit<T>(&self, packet: &mut Packet<&mut T>)
80    where
81        T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
82    {
83        packet.set_flags(self.flags);
84        packet.set_reserved(self.reserved);
85        packet.set_entries_length(self.entries.len() as u32);
86        
87        // Copy entries data
88        let entries_mut = packet.entries_array_mut();
89        entries_mut.copy_from_slice(self.entries);
90
91        packet.set_options_length(self.options.len() as u32);
92        
93        // Copy options data
94        let options_mut = packet.options_array_mut();
95        options_mut.copy_from_slice(self.options);
96    }
97
98    /// Get the total wire format size needed for this representation
99    ///
100    /// # Returns
101    ///
102    /// * `usize` - The total size in bytes
103    pub fn buffer_len(&self) -> usize {
104        use crate::field;
105        field::entries::OPTIONS_ARRAY(self.entries.len(), self.options.len()).end
106    }
107}
108
109impl<'a> fmt::Display for Repr<'a> {
110    /// Formats the high-level representation as a string.
111    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112        write!(
113            f,
114            "SOME/IP-SD Message: flags=0x{:02X}, entries_len={}, options_len={}",
115            self.flags,
116            self.entries.len(),
117            self.options.len()
118        )
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125
126    #[test]
127    fn test_repr_new() {
128        let entries = [0u8; 16];
129        let options = [0u8; 8];
130        
131        let repr = Repr::new(0x80, &entries, &options);
132        
133        assert_eq!(repr.flags, 0x80);
134        assert_eq!(repr.reserved, 0);
135        assert_eq!(repr.entries.len(), 16);
136        assert_eq!(repr.options.len(), 8);
137    }
138
139    #[test]
140    fn test_repr_parse_emit_roundtrip() {
141        // Create original representation
142        let entries_data = [1, 2, 3, 4, 5, 6, 7, 8];
143        let options_data = [9, 10, 11, 12];
144        let original = Repr::new(0xC0, &entries_data, &options_data);
145        
146        // Emit to buffer (12 header + 8 entries + 4 options)
147        let mut buffer = [0u8; 12 + 8 + 4];
148        let mut packet = Packet::new_unchecked(&mut buffer[..]);
149        original.emit(&mut packet);
150        
151        // Parse back
152        let parsed = Repr::parse(&packet).unwrap();
153        
154        assert_eq!(parsed.flags, original.flags);
155        assert_eq!(parsed.reserved, 0);
156        assert_eq!(parsed.entries, original.entries);
157        assert_eq!(parsed.options, original.options);
158    }
159
160    #[test]
161    fn test_repr_buffer_len() {
162        let entries = [0u8; 32];
163        let options = [0u8; 16];
164        
165        let repr = Repr::new(0x00, &entries, &options);
166        
167        assert_eq!(repr.buffer_len(), 12 + 32 + 16);
168    }
169
170    #[test]
171    fn test_repr_empty_entries_and_options() {
172        let entries: &[u8] = &[];
173        let options: &[u8] = &[];
174        
175        let repr = Repr::new(0x00, entries, options);
176        
177        let mut buffer = [0u8; 12];
178        let mut packet = Packet::new_unchecked(&mut buffer[..]);
179        repr.emit(&mut packet);
180        
181        assert_eq!(packet.entries_length(), 0);
182        assert_eq!(packet.options_length(), 0);
183    }
184}