1#[cfg(feature = "alloc")]
16use alloc::vec::Vec;
17
18use crate::{ESC, END, ProtocolError, ProtocolResult};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct Payload {
23 #[cfg(feature = "std")]
25 data: Vec<u8>,
26 #[cfg(all(feature = "alloc", not(feature = "std")))]
27 data: alloc::vec::Vec<u8>,
28 #[cfg(all(not(feature = "alloc"), not(feature = "std")))]
29 data: [u8; 256],
30 #[cfg(all(not(feature = "alloc"), not(feature = "std")))]
31 len: usize,
32}
33
34impl Default for Payload {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40impl Payload {
41 pub fn new() -> Self {
43 #[cfg(any(feature = "std", feature = "alloc"))]
44 {
45 Payload { data: Vec::new() }
46 }
47 #[cfg(all(not(feature = "alloc"), not(feature = "std")))]
48 {
49 Payload {
50 data: [0u8; 256],
51 len: 0,
52 }
53 }
54 }
55
56 pub fn empty() -> Self {
58 Self::new()
59 }
60
61 pub fn from_string(s: &str) -> Self {
63 let mut p = Self::new();
64 p.push_str(s);
65 p
66 }
67
68 pub fn from_bytes(bytes: &[u8]) -> Self {
70 let mut p = Self::new();
71 for &b in bytes {
72 p.push_byte(b);
73 }
74 p
75 }
76
77 pub fn push_byte(&mut self, b: u8) {
79 #[cfg(any(feature = "std", feature = "alloc"))]
80 {
81 self.data.push(b);
82 }
83 #[cfg(all(not(feature = "alloc"), not(feature = "std")))]
84 {
85 if self.len < 256 {
86 self.data[self.len] = b;
87 self.len += 1;
88 }
89 }
90 }
91
92 pub fn push_str(&mut self, s: &str) {
94 for b in s.bytes() {
95 self.push_byte(b);
96 }
97 }
98
99 pub fn push_u16_le(&mut self, v: u16) {
101 self.push_byte((v & 0xFF) as u8);
102 self.push_byte((v >> 8) as u8);
103 }
104
105 pub fn push_u32_le(&mut self, v: u32) {
107 self.push_byte((v & 0xFF) as u8);
108 self.push_byte(((v >> 8) & 0xFF) as u8);
109 self.push_byte(((v >> 16) & 0xFF) as u8);
110 self.push_byte((v >> 24) as u8);
111 }
112
113 pub fn as_bytes(&self) -> &[u8] {
115 #[cfg(any(feature = "std", feature = "alloc"))]
116 {
117 &self.data
118 }
119 #[cfg(all(not(feature = "alloc"), not(feature = "std")))]
120 {
121 &self.data[..self.len]
122 }
123 }
124
125 pub fn len(&self) -> usize {
127 #[cfg(any(feature = "std", feature = "alloc"))]
128 {
129 self.data.len()
130 }
131 #[cfg(all(not(feature = "alloc"), not(feature = "std")))]
132 {
133 self.len
134 }
135 }
136
137 pub fn is_empty(&self) -> bool {
139 self.len() == 0
140 }
141
142 #[cfg(any(feature = "std", feature = "alloc"))]
144 pub fn encode(&self) -> Vec<u8> {
145 let mut out = Vec::with_capacity(self.len() * 2); for &b in self.as_bytes() {
148 match b {
149 END => {
150 out.push(ESC);
151 out.push(END);
152 }
153 ESC => {
154 out.push(ESC);
155 out.push(ESC);
156 }
157 _ => out.push(b),
158 }
159 }
160
161 out
162 }
163
164 pub fn decode(data: &[u8]) -> ProtocolResult<Self> {
166 let mut payload = Self::new();
167 let mut i = 0;
168
169 while i < data.len() {
170 let b = data[i];
171
172 if b == ESC {
173 if i + 1 >= data.len() {
175 return Err(ProtocolError::InvalidEscape);
176 }
177
178 let next = data[i + 1];
179 match next {
180 END => payload.push_byte(END), ESC => payload.push_byte(ESC), _ => return Err(ProtocolError::InvalidEscape),
183 }
184 i += 2;
185 } else {
186 payload.push_byte(b);
187 i += 1;
188 }
189 }
190
191 Ok(payload)
192 }
193
194 pub fn as_str(&self) -> Option<&str> {
196 core::str::from_utf8(self.as_bytes()).ok()
197 }
198
199 pub fn read_u16_le(&self, offset: usize) -> Option<u16> {
201 let bytes = self.as_bytes();
202 if offset + 2 > bytes.len() {
203 return None;
204 }
205 Some(u16::from_le_bytes([bytes[offset], bytes[offset + 1]]))
206 }
207
208 pub fn read_u32_le(&self, offset: usize) -> Option<u32> {
210 let bytes = self.as_bytes();
211 if offset + 4 > bytes.len() {
212 return None;
213 }
214 Some(u32::from_le_bytes([
215 bytes[offset],
216 bytes[offset + 1],
217 bytes[offset + 2],
218 bytes[offset + 3],
219 ]))
220 }
221}
222
223pub struct PayloadEncoder {
225 payload: Payload,
226}
227
228impl Default for PayloadEncoder {
229 fn default() -> Self {
230 Self::new()
231 }
232}
233
234impl PayloadEncoder {
235 pub fn new() -> Self {
236 PayloadEncoder {
237 payload: Payload::new(),
238 }
239 }
240
241 pub fn string(mut self, s: &str) -> Self {
243 let len = s.len();
244 if len <= 126 {
245 self.payload.push_byte((len as u8) + 0x80);
246 } else {
247 self.payload.push_byte(0xFF);
248 self.payload.push_u16_le(len as u16);
249 }
250 self.payload.push_str(s);
251 self
252 }
253
254 pub fn bytes(mut self, data: &[u8]) -> Self {
256 let len = data.len();
257 if len <= 126 {
258 self.payload.push_byte((len as u8) + 0x80);
259 } else {
260 self.payload.push_byte(0xFF);
261 self.payload.push_u16_le(len as u16);
262 }
263 for &b in data {
264 self.payload.push_byte(b);
265 }
266 self
267 }
268
269 pub fn byte(mut self, b: u8) -> Self {
271 self.payload.push_byte(b);
272 self
273 }
274
275 pub fn u16_le(mut self, v: u16) -> Self {
277 self.payload.push_u16_le(v);
278 self
279 }
280
281 pub fn u32_le(mut self, v: u32) -> Self {
283 self.payload.push_u32_le(v);
284 self
285 }
286
287 pub fn build(self) -> Payload {
289 self.payload
290 }
291}
292
293pub struct PayloadDecoder<'a> {
295 data: &'a [u8],
296 pos: usize,
297}
298
299impl<'a> PayloadDecoder<'a> {
300 pub fn new(payload: &'a Payload) -> Self {
301 PayloadDecoder {
302 data: payload.as_bytes(),
303 pos: 0,
304 }
305 }
306
307 pub fn remaining(&self) -> usize {
309 self.data.len().saturating_sub(self.pos)
310 }
311
312 pub fn byte(&mut self) -> Option<u8> {
314 if self.pos < self.data.len() {
315 let b = self.data[self.pos];
316 self.pos += 1;
317 Some(b)
318 } else {
319 None
320 }
321 }
322
323 pub fn u16_le(&mut self) -> Option<u16> {
325 if self.pos + 2 <= self.data.len() {
326 let v = u16::from_le_bytes([self.data[self.pos], self.data[self.pos + 1]]);
327 self.pos += 2;
328 Some(v)
329 } else {
330 None
331 }
332 }
333
334 pub fn u32_le(&mut self) -> Option<u32> {
336 if self.pos + 4 <= self.data.len() {
337 let v = u32::from_le_bytes([
338 self.data[self.pos],
339 self.data[self.pos + 1],
340 self.data[self.pos + 2],
341 self.data[self.pos + 3],
342 ]);
343 self.pos += 4;
344 Some(v)
345 } else {
346 None
347 }
348 }
349
350 pub fn string(&mut self) -> Option<&'a str> {
352 let len_byte = self.byte()?;
353
354 let len = if len_byte == 0xFF {
355 self.u16_le()? as usize
356 } else if len_byte >= 0x80 {
357 (len_byte - 0x80) as usize
358 } else {
359 self.pos -= 1;
361 let start = self.pos;
362 while self.pos < self.data.len() && self.data[self.pos] >= 0x20 && self.data[self.pos] <= 0x7E {
363 self.pos += 1;
364 }
365 let s = core::str::from_utf8(&self.data[start..self.pos]).ok()?;
366 return Some(s);
367 };
368
369 if self.pos + len > self.data.len() {
370 return None;
371 }
372
373 let s = core::str::from_utf8(&self.data[self.pos..self.pos + len]).ok()?;
374 self.pos += len;
375 Some(s)
376 }
377
378 pub fn bytes(&mut self) -> Option<&'a [u8]> {
380 let len_byte = self.byte()?;
381
382 let len = if len_byte == 0xFF {
383 self.u16_le()? as usize
384 } else if len_byte >= 0x80 {
385 (len_byte - 0x80) as usize
386 } else {
387 return None; };
389
390 if self.pos + len > self.data.len() {
391 return None;
392 }
393
394 let data = &self.data[self.pos..self.pos + len];
395 self.pos += len;
396 Some(data)
397 }
398}
399
400#[cfg(test)]
401mod tests {
402 use super::*;
403
404 #[test]
405 fn test_escape_roundtrip() {
406 let original = Payload::from_bytes(&[0x00, 0x1B, 0x42, 0x00, 0x1B]);
407 let encoded = original.encode();
408 let decoded = Payload::decode(&encoded).unwrap();
409 assert_eq!(decoded.as_bytes(), original.as_bytes());
410 }
411
412 #[test]
413 fn test_string_encoding() {
414 let payload = PayloadEncoder::new()
415 .string("/home/hue")
416 .byte(3) .build();
418
419 let mut decoder = PayloadDecoder::new(&payload);
420 assert_eq!(decoder.string(), Some("/home/hue"));
421 assert_eq!(decoder.byte(), Some(3));
422 }
423
424 #[test]
425 fn test_short_length_prefix() {
426 let payload = PayloadEncoder::new().string("abc").build();
428 let bytes = payload.as_bytes();
429 assert_eq!(bytes[0], 0x83); assert_eq!(&bytes[1..4], b"abc");
431 }
432
433 #[test]
434 fn test_extended_length() {
435 let long_str = "x".repeat(200);
437 let payload = PayloadEncoder::new().string(&long_str).build();
438 let bytes = payload.as_bytes();
439 assert_eq!(bytes[0], 0xFF); assert_eq!(bytes[1], 200); assert_eq!(bytes[2], 0); }
443}