someip_wire/
payload.rs

1use crate::{error::*, field, packet::*, types::*};
2use core::fmt;
3
4/// A high-level representation of a Some/IP 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 field. 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    /// Message ID (32 bits)
15    pub message_id: MessageId,
16    /// Length field (32 bits) - automatically calculated as 8 + data.len() when using `new()`
17    pub length: u32,
18    /// Request ID (32 bits)
19    pub request_id: RequestId,
20    /// Protocol version (8 bits)
21    pub protocol_version: u8,
22    /// Interface version (8 bits)
23    pub interface_version: u8,
24    /// Message type (8 bits)
25    pub message_type: MessageType,
26    /// Return code (8 bits)
27    pub return_code: crate::types::ReturnCode,
28    /// Payload data (variable length)
29    pub data: &'a [u8],
30}
31
32impl<'a> Repr<'a> {
33    /// Create a new SOME/IP message representation.
34    /// The length field is automatically calculated as 8 (header bytes) + data.len().
35    ///
36    /// # Arguments
37    ///
38    /// * `message_id` - The message ID
39    /// * `request_id` - The request ID
40    /// * `protocol_version` - Protocol version (typically 0x01)
41    /// * `interface_version` - Interface version
42    /// * `message_type` - The message type
43    /// * `return_code` - The return code
44    /// * `data` - The payload data
45    ///
46    /// # Returns
47    ///
48    /// A new `Repr` instance with the length field automatically calculated.
49    pub fn new(
50        message_id: MessageId,
51        request_id: RequestId,
52        protocol_version: u8,
53        interface_version: u8,
54        message_type: MessageType,
55        return_code: crate::types::ReturnCode,
56        data: &'a [u8],
57    ) -> Self {
58        Repr {
59            message_id,
60            length: 8 + data.len() as u32,
61            request_id,
62            protocol_version,
63            interface_version,
64            message_type,
65            return_code,
66            data,
67        }
68    }
69
70    /// Get the length field value (8 header bytes + payload length)
71    pub fn length(&self) -> u32 {
72        self.length
73    }
74    pub fn parse<T>(packet: &'a Packet<T>) -> core::result::Result<Repr<'a>, Error>
75    where
76        T: AsRef<[u8]>,
77    {
78        let buffer = packet.as_slice();
79
80        if buffer.len() < field::header::HEADER_LENGTH {
81            return Err(Error);
82        }
83
84        let message_id = MessageId::from_u32(u32::from_be_bytes(
85            buffer[field::header::MESSAGE_ID].try_into().unwrap(),
86        ));
87        let length = u32::from_be_bytes(buffer[field::header::LENGTH].try_into().unwrap());
88        let request_id = RequestId::from_u32(u32::from_be_bytes(
89            buffer[field::header::REQUEST_ID].try_into().unwrap(),
90        ));
91        let protocol_version = buffer[field::header::PROTOCOL_VERSION.start];
92        let interface_version = buffer[field::header::INTERFACE_VERSION.start];
93        let message_type_byte = buffer[field::header::MESSAGE_TYPE.start];
94        let message_type = MessageType::from_u8(message_type_byte).ok_or(Error)?;
95        let return_code_byte = buffer[field::header::RETURN_CODE.start];
96        let return_code = crate::types::ReturnCode::from_u8(return_code_byte).ok_or(Error)?;
97
98        // Length includes Request ID (4) + Protocol Version (1) + Interface Version (1) 
99        // + Message Type (1) + Return Code (1) + Payload = 8 bytes + payload
100        let payload_start = field::header::RETURN_CODE.end;
101        let payload_length = length.saturating_sub(8); // Subtract the 8 header bytes after Message ID
102        let payload_end = payload_start + (payload_length as usize);
103        if buffer.len() < payload_end {
104            return Err(Error);
105        }
106        let data = &buffer[payload_start..payload_end];
107
108        Ok(Repr {
109            message_id,
110            length,
111            request_id,
112            protocol_version,
113            interface_version,
114            message_type,
115            return_code,
116            data,
117        })
118    }
119
120    /// Emits the high-level representation of the Some/IP packet into the provided packet/buffer.
121    ///
122    /// # Arguments
123    ///
124    /// * `packet` - A mutable reference to the packet where the high-level representation will be written.
125    pub fn emit<T>(&self, packet: &mut Packet<&mut T>)
126    where
127        T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
128    {
129        packet.set_message_id(self.message_id);
130        packet.set_payload_length(self.length);
131        packet.set_request_id(self.request_id);
132        packet.set_protocol_version(self.protocol_version);
133        packet.set_interface_version(self.interface_version);
134        packet.set_message_type(self.message_type.as_u8());
135        packet.set_return_code(self.return_code.as_u8());
136
137        // Copy payload data
138        let payload_mut = packet.payload_data_mut();
139        payload_mut[..self.data.len()].copy_from_slice(self.data);
140    }
141}
142
143impl<'a> fmt::Display for Repr<'a> {
144    /// Formats the high-level representation as a string.
145    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146        write!(
147            f,
148            "SOME/IP Payload: message_id={}, length={}, request_id={}, protocol_version={}, interface_version={}, message_type={}, return_code={}, data_len={}",
149            self.message_id,
150            self.length,
151            self.request_id,
152            self.protocol_version,
153            self.interface_version,
154            self.message_type,
155            self.return_code,
156            self.data.len()
157        )
158    }
159}