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}