rusp_lib/
usp_decoder.rs

1use anyhow::{anyhow, Context, Result};
2use quick_protobuf::message::MessageRead;
3use quick_protobuf::BytesReader;
4
5use crate::usp::{self, Error, Msg, Notify};
6use crate::usp_record::mod_Record::OneOfrecord_type;
7use crate::usp_record::{NoSessionContextRecord, Record, SessionContextRecord};
8
9/// Decodes a slice of bytes containing a Protobuf encoded USP Record into a Record structure for
10/// further processing
11///
12/// # Arguments
13///
14/// * `bytes` - A slice of bytes containing the Protobuf encoded USP Record
15///
16/// # Example
17///
18/// ```
19/// use rusp_lib::usp_decoder::try_decode_record;
20/// let record =
21///     try_decode_record(&[
22///         0x0a, 0x03, 0x31, 0x2e, 0x30, 0x1a, 0x23, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a,
23///         0x61, 0x78, 0x2d, 0x75, 0x73, 0x70, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2d, 0x6e,
24///         0x6f, 0x73, 0x73, 0x6c, 0x2d, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74,
25///         0x3a, 0x4d, 0x12, 0x4b, 0x0a, 0x08, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74, 0x10, 0x03,
26///         0x12, 0x3f, 0x0a, 0x3d, 0x42, 0x3b, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72,
27///         0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x42, 0x28, 0x0a, 0x03, 0x6f,
28///         0x75, 0x69, 0x12, 0x0d, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x63, 0x6c,
29///         0x61, 0x73, 0x73, 0x1a, 0x0d, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x6e, 0x75,
30///         0x6d, 0x62, 0x65, 0x72, 0x22, 0x03, 0x31, 0x2e, 0x30,
31///     ]);
32/// ```
33pub fn try_decode_record(bytes: &[u8]) -> Result<Record> {
34    let mut reader = BytesReader::from_bytes(bytes);
35    Record::from_reader(&mut reader, bytes).context("while parsing protobuf as USP Record")
36}
37
38/// Decodes a slice of bytes containing a Protobuf encoded USP Msg into a Msg structure for further
39/// processing
40///
41/// # Arguments
42///
43/// * `bytes` - A slice of bytes containing the Protobuf encoded USP Message
44///
45/// # Example
46///
47/// ```
48/// use rusp_lib::usp_decoder::try_decode_msg;
49/// let msg =
50///     try_decode_msg(&[
51///         0x0a, 0x1a, 0x0a, 0x16, 0x41, 0x58, 0x53, 0x53, 0x2d, 0x31, 0x35, 0x34,
52///         0x34, 0x31, 0x31, 0x34, 0x30, 0x34, 0x35, 0x2e, 0x34, 0x34, 0x32, 0x35,
53///         0x39, 0x36, 0x10, 0x02, 0x12, 0x46, 0x12, 0x44, 0x0a, 0x42, 0x0a, 0x40,
54///         0x0a, 0x22, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x63,
55///         0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x54, 0x50, 0x2e,
56///         0x31, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
57///         0x15, 0x62, 0x1b, 0x00, 0x00, 0x1a, 0x15, 0x55, 0x6e, 0x73, 0x75, 0x70,
58///         0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d,
59///         0x65, 0x74, 0x65, 0x72
60///     ]);
61/// ```
62pub fn try_decode_msg(bytes: &[u8]) -> Result<Msg> {
63    let mut reader = BytesReader::from_bytes(bytes);
64    Msg::from_reader(&mut reader, bytes).context("while parsing protobuf as USP Message")
65}
66
67/// Implementation of some extension methods for `Msg`s
68impl Msg {
69    /// Tries to decode a slice of bytes containing a Protobuf encoded USP Message
70    ///
71    /// This function also performs additional checks required by the USP specification, see also
72    /// [`Msg::check_validity`]
73    ///
74    /// # Arguments
75    ///
76    /// * `bytes` - A slice of bytes containing the Protobuf encoded USP Message
77    ///
78    /// # Example
79    ///
80    /// ```
81    /// use rusp_lib::usp::Msg;
82    /// let msg =
83    ///     Msg::from_bytes(&[
84    ///         0x0a, 0x1a, 0x0a, 0x16, 0x41, 0x58, 0x53, 0x53, 0x2d, 0x31, 0x35, 0x34,
85    ///         0x34, 0x31, 0x31, 0x34, 0x30, 0x34, 0x35, 0x2e, 0x34, 0x34, 0x32, 0x35,
86    ///         0x39, 0x36, 0x10, 0x02, 0x12, 0x46, 0x12, 0x44, 0x0a, 0x42, 0x0a, 0x40,
87    ///         0x0a, 0x22, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x63,
88    ///         0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x54, 0x50, 0x2e,
89    ///         0x31, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
90    ///         0x15, 0x62, 0x1b, 0x00, 0x00, 0x1a, 0x15, 0x55, 0x6e, 0x73, 0x75, 0x70,
91    ///         0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d,
92    ///         0x65, 0x74, 0x65, 0x72
93    ///     ])
94    ///     .unwrap();
95    /// ```
96    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
97        let this = try_decode_msg(bytes)?;
98        this.check_validity()?;
99        Ok(this)
100    }
101
102    /// Retrieves the message ID from a Msg structure
103    ///
104    /// # Arguments
105    ///
106    /// * `self` - A decoded USP Msg structure
107    ///
108    /// # Example
109    ///
110    /// ```
111    /// use rusp_lib::usp_decoder::try_decode_msg;
112    /// let msg =
113    ///     try_decode_msg(&[
114    ///         0x0a, 0x1a, 0x0a, 0x16, 0x41, 0x58, 0x53, 0x53, 0x2d, 0x31, 0x35, 0x34,
115    ///         0x34, 0x31, 0x31, 0x34, 0x30, 0x34, 0x35, 0x2e, 0x34, 0x34, 0x32, 0x35,
116    ///         0x39, 0x36, 0x10, 0x02, 0x12, 0x46, 0x12, 0x44, 0x0a, 0x42, 0x0a, 0x40,
117    ///         0x0a, 0x22, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x63,
118    ///         0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x54, 0x50, 0x2e,
119    ///         0x31, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
120    ///         0x15, 0x62, 0x1b, 0x00, 0x00, 0x1a, 0x15, 0x55, 0x6e, 0x73, 0x75, 0x70,
121    ///         0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d,
122    ///         0x65, 0x74, 0x65, 0x72
123    ///     ]);
124    /// assert_eq!(msg.unwrap().msg_id(), "AXSS-1544114045.442596");
125    /// ```
126    #[must_use]
127    pub fn msg_id(&self) -> &str {
128        self.header
129            .as_ref()
130            .map_or("", |header| header.msg_id.as_ref())
131    }
132
133    /// Checks whether the body contains a message of type request
134    ///
135    /// # Arguments
136    ///
137    /// * `self` - A decoded USP Msg structure
138    ///
139    /// # Example
140    ///
141    /// ```
142    /// use rusp_lib::usp_decoder::try_decode_msg;
143    /// let msg =
144    ///     try_decode_msg(&[
145    ///         0x0a, 0x08, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74,
146    ///         0x10, 0x03, 0x12, 0x28, 0x0a, 0x26, 0x42, 0x24,
147    ///         0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x10,
148    ///         0x01, 0x42, 0x19, 0x0a, 0x06, 0x30, 0x30, 0x34,
149    ///         0x34, 0x46, 0x46, 0x12, 0x03, 0x46, 0x6f, 0x6f,
150    ///         0x1a, 0x05, 0x30, 0x31, 0x32, 0x33, 0x34, 0x22,
151    ///         0x03, 0x31, 0x2e, 0x33,
152    ///     ]).unwrap();
153    /// assert_eq!(msg.is_request(), true);
154    /// ```
155    ///
156    /// ```
157    /// use rusp_lib::usp_decoder::try_decode_msg;
158    /// let msg =
159    ///     try_decode_msg(&[
160    ///         0x0a, 0x1a, 0x0a, 0x16, 0x41, 0x58, 0x53, 0x53, 0x2d, 0x31, 0x35, 0x34,
161    ///         0x34, 0x31, 0x31, 0x34, 0x30, 0x34, 0x35, 0x2e, 0x34, 0x34, 0x32, 0x35,
162    ///         0x39, 0x36, 0x10, 0x02, 0x12, 0x46, 0x12, 0x44, 0x0a, 0x42, 0x0a, 0x40,
163    ///         0x0a, 0x22, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x63,
164    ///         0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x54, 0x50, 0x2e,
165    ///         0x31, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
166    ///         0x15, 0x62, 0x1b, 0x00, 0x00, 0x1a, 0x15, 0x55, 0x6e, 0x73, 0x75, 0x70,
167    ///         0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d,
168    ///         0x65, 0x74, 0x65, 0x72
169    ///     ]).unwrap();
170    /// assert_eq!(msg.is_request(), false);
171    /// ```
172    #[must_use]
173    pub const fn is_request(&self) -> bool {
174        if let Some(body) = self.body.as_ref() {
175            matches!(&body.msg_body, usp::mod_Body::OneOfmsg_body::request(_))
176        } else {
177            false
178        }
179    }
180
181    /// Checks whether the body contains a message of type notify (request)
182    ///
183    /// # Arguments
184    ///
185    /// * `self` - A decoded USP Msg structure
186    ///
187    /// # Example
188    ///
189    /// ```
190    /// use rusp_lib::usp_decoder::try_decode_msg;
191    /// let msg =
192    ///     try_decode_msg(&[
193    ///         0x0a, 0x08, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74,
194    ///         0x10, 0x03, 0x12, 0x28, 0x0a, 0x26, 0x42, 0x24,
195    ///         0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x10,
196    ///         0x01, 0x42, 0x19, 0x0a, 0x06, 0x30, 0x30, 0x34,
197    ///         0x34, 0x46, 0x46, 0x12, 0x03, 0x46, 0x6f, 0x6f,
198    ///         0x1a, 0x05, 0x30, 0x31, 0x32, 0x33, 0x34, 0x22,
199    ///         0x03, 0x31, 0x2e, 0x33,
200    ///     ]).unwrap();
201    /// assert_eq!(msg.is_notify_request(), true);
202    /// ```
203    ///
204    /// ```
205    /// use rusp_lib::usp_decoder::try_decode_msg;
206    /// let msg =
207    ///     try_decode_msg(&[
208    ///         0x0a, 0x1a, 0x0a, 0x16, 0x41, 0x58, 0x53, 0x53, 0x2d, 0x31, 0x35, 0x34,
209    ///         0x34, 0x31, 0x31, 0x34, 0x30, 0x34, 0x35, 0x2e, 0x34, 0x34, 0x32, 0x35,
210    ///         0x39, 0x36, 0x10, 0x02, 0x12, 0x46, 0x12, 0x44, 0x0a, 0x42, 0x0a, 0x40,
211    ///         0x0a, 0x22, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x63,
212    ///         0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x54, 0x50, 0x2e,
213    ///         0x31, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
214    ///         0x15, 0x62, 0x1b, 0x00, 0x00, 0x1a, 0x15, 0x55, 0x6e, 0x73, 0x75, 0x70,
215    ///         0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d,
216    ///         0x65, 0x74, 0x65, 0x72
217    ///     ]).unwrap();
218    /// assert_eq!(msg.is_notify_request(), false);
219    /// ```
220    #[must_use]
221    pub const fn is_notify_request(&self) -> bool {
222        self.get_notify_request().is_some()
223    }
224
225    /// Retrieves the notify request from the Msg
226    ///
227    /// # Arguments
228    ///
229    /// * `self` - A decoded USP Msg structure
230    ///
231    /// # Example
232    ///
233    /// ```
234    /// use rusp_lib::usp_decoder::try_decode_msg;
235    /// let msg =
236    ///     try_decode_msg(&[
237    ///         0x0a, 0x08, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74,
238    ///         0x10, 0x03, 0x12, 0x28, 0x0a, 0x26, 0x42, 0x24,
239    ///         0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x10,
240    ///         0x01, 0x42, 0x19, 0x0a, 0x06, 0x30, 0x30, 0x34,
241    ///         0x34, 0x46, 0x46, 0x12, 0x03, 0x46, 0x6f, 0x6f,
242    ///         0x1a, 0x05, 0x30, 0x31, 0x32, 0x33, 0x34, 0x22,
243    ///         0x03, 0x31, 0x2e, 0x33,
244    ///     ]).unwrap();
245    /// assert!(msg.get_notify_request().is_some());
246    /// ```
247    ///
248    /// ```
249    /// use rusp_lib::usp_decoder::try_decode_msg;
250    /// let msg =
251    ///     try_decode_msg(&[
252    ///         0x0a, 0x1a, 0x0a, 0x16, 0x41, 0x58, 0x53, 0x53, 0x2d, 0x31, 0x35, 0x34,
253    ///         0x34, 0x31, 0x31, 0x34, 0x30, 0x34, 0x35, 0x2e, 0x34, 0x34, 0x32, 0x35,
254    ///         0x39, 0x36, 0x10, 0x02, 0x12, 0x46, 0x12, 0x44, 0x0a, 0x42, 0x0a, 0x40,
255    ///         0x0a, 0x22, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x63,
256    ///         0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x54, 0x50, 0x2e,
257    ///         0x31, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
258    ///         0x15, 0x62, 0x1b, 0x00, 0x00, 0x1a, 0x15, 0x55, 0x6e, 0x73, 0x75, 0x70,
259    ///         0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d,
260    ///         0x65, 0x74, 0x65, 0x72
261    ///     ]).unwrap();
262    /// assert!(msg.get_notify_request().is_none());
263    /// ```
264    #[must_use]
265    pub const fn get_notify_request(&self) -> Option<&Notify> {
266        if let Some(body) = self.body.as_ref() {
267            if let usp::mod_Body::OneOfmsg_body::request(request) = &body.msg_body {
268                if let usp::mod_Request::OneOfreq_type::notify(notify) = &request.req_type {
269                    return Some(notify);
270                }
271            }
272        }
273
274        None
275    }
276
277    /// Checks whether the body contains a message of type response
278    ///
279    /// # Arguments
280    ///
281    /// * `self` - A decoded USP Msg structure
282    ///
283    /// # Example
284    ///
285    /// ```
286    /// use rusp_lib::usp_decoder::try_decode_msg;
287    /// let msg =
288    ///     try_decode_msg(&[
289    ///         0x0a, 0x08, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74,
290    ///         0x10, 0x03, 0x12, 0x28, 0x0a, 0x26, 0x42, 0x24,
291    ///         0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x10,
292    ///         0x01, 0x42, 0x19, 0x0a, 0x06, 0x30, 0x30, 0x34,
293    ///         0x34, 0x46, 0x46, 0x12, 0x03, 0x46, 0x6f, 0x6f,
294    ///         0x1a, 0x05, 0x30, 0x31, 0x32, 0x33, 0x34, 0x22,
295    ///         0x03, 0x31, 0x2e, 0x33,
296    ///     ]).unwrap();
297    /// assert_eq!(msg.is_response(), false);
298    /// ```
299    ///
300    /// ```
301    /// use rusp_lib::usp_decoder::try_decode_msg;
302    /// let msg =
303    ///     try_decode_msg(&[
304    ///         0x0a, 0x1a, 0x0a, 0x16, 0x41, 0x58, 0x53, 0x53, 0x2d, 0x31, 0x35, 0x34,
305    ///         0x34, 0x31, 0x31, 0x34, 0x30, 0x34, 0x35, 0x2e, 0x34, 0x34, 0x32, 0x35,
306    ///         0x39, 0x36, 0x10, 0x02, 0x12, 0x46, 0x12, 0x44, 0x0a, 0x42, 0x0a, 0x40,
307    ///         0x0a, 0x22, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x63,
308    ///         0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x54, 0x50, 0x2e,
309    ///         0x31, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
310    ///         0x15, 0x62, 0x1b, 0x00, 0x00, 0x1a, 0x15, 0x55, 0x6e, 0x73, 0x75, 0x70,
311    ///         0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d,
312    ///         0x65, 0x74, 0x65, 0x72
313    ///     ]).unwrap();
314    /// assert_eq!(msg.is_response(), true);
315    /// ```
316    #[must_use]
317    pub const fn is_response(&self) -> bool {
318        if let Some(body) = self.body.as_ref() {
319            matches!(&body.msg_body, usp::mod_Body::OneOfmsg_body::response(_))
320        } else {
321            false
322        }
323    }
324
325    /// Checks whether the body contains a message of type response
326    ///
327    /// # Arguments
328    ///
329    /// * `self` - A decoded USP Msg structure
330    ///
331    /// # Example
332    ///
333    /// ```
334    /// use rusp_lib::usp_decoder::try_decode_msg;
335    /// let msg =
336    ///     try_decode_msg(&[
337    ///         0x0a, 0x08, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74,
338    ///         0x10, 0x03, 0x12, 0x28, 0x0a, 0x26, 0x42, 0x24,
339    ///         0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x10,
340    ///         0x01, 0x42, 0x19, 0x0a, 0x06, 0x30, 0x30, 0x34,
341    ///         0x34, 0x46, 0x46, 0x12, 0x03, 0x46, 0x6f, 0x6f,
342    ///         0x1a, 0x05, 0x30, 0x31, 0x32, 0x33, 0x34, 0x22,
343    ///         0x03, 0x31, 0x2e, 0x33,
344    ///     ]).unwrap();
345    /// assert_eq!(msg.is_error(), false);
346    /// ```
347    ///
348    /// ```
349    /// use rusp_lib::usp_decoder::try_decode_msg;
350    /// let msg =
351    ///     try_decode_msg(&[
352    ///         0x0a, 0x1a, 0x0a, 0x16, 0x41, 0x58, 0x53, 0x53, 0x2d, 0x31, 0x35, 0x34,
353    ///         0x34, 0x31, 0x31, 0x34, 0x30, 0x34, 0x35, 0x2e, 0x34, 0x34, 0x32, 0x35,
354    ///         0x39, 0x36, 0x10, 0x02, 0x12, 0x46, 0x12, 0x44, 0x0a, 0x42, 0x0a, 0x40,
355    ///         0x0a, 0x22, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x63,
356    ///         0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x54, 0x50, 0x2e,
357    ///         0x31, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
358    ///         0x15, 0x62, 0x1b, 0x00, 0x00, 0x1a, 0x15, 0x55, 0x6e, 0x73, 0x75, 0x70,
359    ///         0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d,
360    ///         0x65, 0x74, 0x65, 0x72
361    ///     ]).unwrap();
362    /// assert_eq!(msg.is_error(), false);
363    /// ```
364    ///
365    /// ```
366    /// use rusp_lib::usp_decoder::try_decode_msg;
367    /// let msg =
368    ///     try_decode_msg(&[
369    ///         0x0a, 0x05, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x12,
370    ///         0x17, 0x1a, 0x15, 0x0d, 0x5b, 0x1b, 0x00, 0x00,
371    ///         0x12, 0x0e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
372    ///         0x61, 0x6c, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72,
373    ///     ]).unwrap();
374    /// assert_eq!(msg.is_error(), true);
375    /// ```
376    #[must_use]
377    pub fn is_error(&self) -> bool {
378        self.get_error().is_some()
379    }
380
381    /// Retrieves the notify request from the Msg
382    ///
383    /// # Arguments
384    ///
385    /// * `self` - A decoded USP Msg structure
386    ///
387    /// # Example
388    ///
389    /// ```
390    /// use rusp_lib::usp_decoder::try_decode_msg;
391    /// let msg =
392    ///     try_decode_msg(&[
393    ///         0x0a, 0x08, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74,
394    ///         0x10, 0x03, 0x12, 0x28, 0x0a, 0x26, 0x42, 0x24,
395    ///         0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x10,
396    ///         0x01, 0x42, 0x19, 0x0a, 0x06, 0x30, 0x30, 0x34,
397    ///         0x34, 0x46, 0x46, 0x12, 0x03, 0x46, 0x6f, 0x6f,
398    ///         0x1a, 0x05, 0x30, 0x31, 0x32, 0x33, 0x34, 0x22,
399    ///         0x03, 0x31, 0x2e, 0x33,
400    ///     ]).unwrap();
401    /// assert!(msg.get_error().is_none());
402    /// ```
403    ///
404    /// ```
405    /// use rusp_lib::usp_decoder::try_decode_msg;
406    /// let msg =
407    ///     try_decode_msg(&[
408    ///         0x0a, 0x1a, 0x0a, 0x16, 0x41, 0x58, 0x53, 0x53, 0x2d, 0x31, 0x35, 0x34,
409    ///         0x34, 0x31, 0x31, 0x34, 0x30, 0x34, 0x35, 0x2e, 0x34, 0x34, 0x32, 0x35,
410    ///         0x39, 0x36, 0x10, 0x02, 0x12, 0x46, 0x12, 0x44, 0x0a, 0x42, 0x0a, 0x40,
411    ///         0x0a, 0x22, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x63,
412    ///         0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x54, 0x50, 0x2e,
413    ///         0x31, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
414    ///         0x15, 0x62, 0x1b, 0x00, 0x00, 0x1a, 0x15, 0x55, 0x6e, 0x73, 0x75, 0x70,
415    ///         0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d,
416    ///         0x65, 0x74, 0x65, 0x72
417    ///     ]).unwrap();
418    /// assert!(msg.get_error().is_none());
419    /// ```
420    ///
421    /// ```
422    /// use rusp_lib::usp_decoder::try_decode_msg;
423    /// let msg =
424    ///     try_decode_msg(&[
425    ///         0x0a, 0x05, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x12,
426    ///         0x17, 0x1a, 0x15, 0x0d, 0x5b, 0x1b, 0x00, 0x00,
427    ///         0x12, 0x0e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
428    ///         0x61, 0x6c, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72,
429    ///     ]).unwrap();
430    /// assert!(msg.get_error().is_some());
431    /// ```
432    #[must_use]
433    pub fn get_error(&self) -> Option<Error> {
434        if let Some(body) = self.body.as_ref() {
435            if let usp::mod_Body::OneOfmsg_body::error(error) = &body.msg_body {
436                return Some(error.clone());
437            }
438        }
439
440        None
441    }
442
443    /// Checks the validity of this [`Msg`] according to the USP specification
444    ///
445    /// Although the type itself guarantees its validity against the protobuf schema, the USP
446    /// specification places additional constrains on the values used
447    ///
448    /// # Example
449    ///
450    /// ```
451    /// use rusp_lib::usp_decoder::try_decode_msg;
452    /// let msg =
453    ///     try_decode_msg(&[
454    ///         0x0a, 0x09, 0x0a, 0x07, 0x6e, 0x6f, 0x2d, 0x62,
455    ///         0x6f, 0x64, 0x79, 0x12, 0x00,
456    ///     ]).unwrap();
457    /// assert!(msg.check_validity().is_err());
458    /// ```
459    pub fn check_validity(&self) -> Result<()> {
460        use crate::usp::mod_Body::OneOfmsg_body;
461        use crate::usp::mod_Request::OneOfreq_type;
462        use crate::usp::mod_Response::OneOfresp_type;
463        use crate::usp::{Request, Response};
464
465        self.header
466            .as_ref()
467            .filter(|h| !h.msg_id.is_empty())
468            .ok_or_else(|| anyhow!("Empty message ID"))?;
469
470        let body = self
471            .body
472            .as_ref()
473            .filter(|b| !matches!(b.msg_body, OneOfmsg_body::None))
474            .ok_or_else(|| anyhow!("Invalid message body"))?;
475
476        match body.msg_body {
477            OneOfmsg_body::request(Request {
478                req_type: OneOfreq_type::None,
479            }) => Err(anyhow!("Invalid Request message")),
480            OneOfmsg_body::response(Response {
481                resp_type: OneOfresp_type::None,
482            }) => Err(anyhow!("Invalid Response message")),
483            _ => Ok(()),
484        }
485    }
486}
487
488impl SessionContextRecord {
489    /// Gets the payload of this [`SessionContextRecord`], flattening it if necessary
490    pub fn payload_flatten(&mut self) -> &mut Vec<u8> {
491        if self.payload.len() != 1 {
492            let old = std::mem::take(&mut self.payload);
493            self.payload = vec![old.into_iter().flatten().collect()];
494        }
495
496        &mut self.payload[0]
497    }
498}
499
500impl Record {
501    /// Tries to decode a slice of bytes containing a Protobuf encoded USP Record
502    ///
503    /// This function also performs additional checks required by the USP specification, see also
504    /// [`Record::check_validity`]
505    ///
506    /// # Arguments
507    ///
508    /// * `bytes` - A slice of bytes containing the Protobuf encoded USP Record
509    ///
510    /// # Example
511    ///
512    /// ```
513    /// use rusp_lib::usp_record::Record;
514    /// let record =
515    ///     Record::from_bytes(&[
516    ///         0x0a, 0x03, 0x31, 0x2e, 0x33, 0x12, 0x07, 0x64,
517    ///         0x6f, 0x63, 0x3a, 0x3a, 0x74, 0x6f, 0x1a, 0x09,
518    ///         0x64, 0x6f, 0x63, 0x3a, 0x3a, 0x66, 0x72, 0x6f,
519    ///         0x6d, 0x3a, 0x35, 0x12, 0x33, 0x0a, 0x07, 0x0a,
520    ///         0x03, 0x67, 0x65, 0x74, 0x10, 0x01, 0x12, 0x28,
521    ///         0x0a, 0x26, 0x0a, 0x24, 0x0a, 0x22, 0x44, 0x65,
522    ///         0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x76,
523    ///         0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e,
524    ///         0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
525    ///         0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e,
526    ///     ])
527    ///     .unwrap();
528    /// ```
529    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
530        let this = try_decode_record(bytes)?;
531        this.check_validity()?;
532        Ok(this)
533    }
534    /// Checks the validity of this [`Record`] according to the USP specification
535    ///
536    /// Although the type itself guarantees its validity against the protobuf schema, the USP
537    /// specification places additional constrains on the values used
538    ///
539    /// # Example
540    ///
541    /// ```
542    /// use rusp_lib::usp_decoder::try_decode_record;
543    /// let no_session_empty_payload =
544    ///     try_decode_record(&[
545    ///         0x0a, 0x03, 0x31, 0x2e, 0x33, 0x12, 0x07, 0x64,
546    ///         0x6f, 0x63, 0x3a, 0x3a, 0x74, 0x6f, 0x1a, 0x09,
547    ///         0x64, 0x6f, 0x63, 0x3a, 0x3a, 0x66, 0x72, 0x6f,
548    ///         0x6d, 0x3a, 0x00,
549    ///     ]).unwrap();
550    /// assert!(no_session_empty_payload.check_validity().is_err());
551    /// ```
552    pub fn check_validity(&self) -> Result<()> {
553        if self.version.is_empty() {
554            return Err(anyhow!("Invalid USP version"));
555        }
556
557        if self.to_id.is_empty() {
558            return Err(anyhow!("Invalid to_id field in Record"));
559        }
560        if self.from_id.is_empty() {
561            return Err(anyhow!("Invalid from_id field in Record"));
562        }
563
564        match &self.record_type {
565            OneOfrecord_type::None => Err(anyhow!("Invalid Record type")),
566            OneOfrecord_type::no_session_context(NoSessionContextRecord { payload })
567                if payload.is_empty() =>
568            {
569                Err(anyhow!(
570                    "NoSessionContext Record containing an empty payload"
571                ))
572            }
573            _ => Ok(()),
574        }
575    }
576
577    /// Flattens the payload of the [`Record`] and returns a mutable reference to it
578    ///
579    /// This function will return [`None`] for Record types that do not contain a payload
580    pub fn payload_flatten(&mut self) -> Option<&mut Vec<u8>> {
581        use crate::usp_record::mod_Record::OneOfrecord_type;
582
583        match &mut self.record_type {
584            OneOfrecord_type::no_session_context(no_session) => Some(&mut no_session.payload),
585            OneOfrecord_type::session_context(session) => Some(session.payload_flatten()),
586            _ => None,
587        }
588    }
589}
590
591#[cfg(test)]
592mod tests {
593    use super::*;
594
595    #[test]
596    fn empty_msg_id() {
597        let raw = [
598            0x0a, 0x02, 0x10, 0x01, 0x12, 0x28, 0x0a, 0x26, 0x0a, 0x24, 0x0a, 0x22, 0x44, 0x65,
599            0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66,
600            0x6f, 0x2e, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73,
601            0x69, 0x6f, 0x6e, 0x2e,
602        ];
603        let msg = try_decode_msg(&raw)
604            .expect("raw should be a valid USP Message according to the protobuf schema");
605        assert!(msg.check_validity().is_err());
606    }
607
608    #[test]
609    fn invalid_record_to_id() {
610        let raw = [
611            0x0a, 0x03, 0x31, 0x2e, 0x33, 0x1a, 0x09, 0x64, 0x6f, 0x63, 0x3a, 0x3a, 0x66, 0x72,
612            0x6f, 0x6d, 0x3a, 0x35, 0x12, 0x33, 0x0a, 0x07, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x10,
613            0x01, 0x12, 0x28, 0x0a, 0x26, 0x0a, 0x24, 0x0a, 0x22, 0x44, 0x65, 0x76, 0x69, 0x63,
614            0x65, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53,
615            0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
616            0x2e,
617        ];
618        let record = try_decode_record(&raw)
619            .expect("raw should be a valid Record according to the protobuf schema");
620        assert!(record.check_validity().is_err());
621
622        let OneOfrecord_type::no_session_context(NoSessionContextRecord { payload: msg_raw }) =
623            record.record_type
624        else {
625            panic!("Record should have a NoSessionContext type");
626        };
627
628        let msg = try_decode_msg(&msg_raw)
629            .expect("msg_raw should be a valid USP Message according to the protobuf schema");
630        msg.check_validity().unwrap();
631    }
632
633    #[test]
634    fn invalid_record_from_id() {
635        let raw = [
636            0x0a, 0x03, 0x31, 0x2e, 0x33, 0x12, 0x07, 0x64, 0x6f, 0x63, 0x3a, 0x3a, 0x74, 0x6f,
637            0x3a, 0x35, 0x12, 0x33, 0x0a, 0x07, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x10, 0x01, 0x12,
638            0x28, 0x0a, 0x26, 0x0a, 0x24, 0x0a, 0x22, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e,
639            0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x6f, 0x66,
640            0x74, 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e,
641        ];
642        let record = try_decode_record(&raw)
643            .expect("raw should be a valid Record according to the protobuf schema");
644        assert!(record.check_validity().is_err());
645
646        let OneOfrecord_type::no_session_context(NoSessionContextRecord { payload: msg_raw }) =
647            record.record_type
648        else {
649            panic!("Record should have a NoSessionContext type");
650        };
651
652        let msg = try_decode_msg(&msg_raw)
653            .expect("msg_raw should be a valid USP Message according to the protobuf schema");
654        msg.check_validity().unwrap();
655    }
656
657    #[test]
658    fn flat_record() {
659        use crate::usp_record::mod_Record::OneOfrecord_type;
660
661        let raw = [
662            0x0a, 0x03, 0x31, 0x2e, 0x33, 0x12, 0x07, 0x64, 0x6f, 0x63, 0x3a, 0x3a, 0x74, 0x6f,
663            0x1a, 0x09, 0x64, 0x6f, 0x63, 0x3a, 0x3a, 0x66, 0x72, 0x6f, 0x6d, 0x42, 0x3c, 0x08,
664            0xd2, 0x09, 0x10, 0x01, 0x18, 0x02, 0x3a, 0x33, 0x0a, 0x07, 0x0a, 0x03, 0x67, 0x65,
665            0x74, 0x10, 0x01, 0x12, 0x28, 0x0a, 0x26, 0x0a, 0x24, 0x0a, 0x22, 0x44, 0x65, 0x76,
666            0x69, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f,
667            0x2e, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69,
668            0x6f, 0x6e, 0x2e,
669        ];
670        let mut record = Record::from_bytes(&raw).expect("raw should be a valid Record");
671        let payload = record.payload_flatten().unwrap().clone();
672        assert!(!payload.is_empty());
673
674        let split = payload.chunks(2).map(Vec::from).collect::<Vec<_>>();
675        assert!(split.len() > 1);
676
677        let OneOfrecord_type::session_context(session) = &mut record.record_type else {
678            panic!("Record should be of type SessionContext");
679        };
680        session.payload = split;
681
682        let flatten = record.payload_flatten().unwrap();
683        assert_eq!(flatten, &payload);
684    }
685}