1use std::fmt;
2
3use super::Frame;
4
5struct PropertyIterator<'a, I>
8where
9 I: Iterator<Item = (usize, &'a u8)>,
10{
11 inner: &'a Command<'a>,
12 cursor: I,
13}
14
15impl<'a, I> Iterator for PropertyIterator<'a, I>
16where
17 I: Iterator<Item = (usize, &'a u8)>,
18{
19 type Item = (&'a str, &'a str);
20
21 fn next(&mut self) -> Option<Self::Item> {
22 let (name_idx, name_size) = self.cursor.next()?;
23
24 for _ in 0..(*name_size) {
26 let _ = self
27 .cursor
28 .next()
29 .expect("Expected to jump over a name chunk byte...");
30 }
31
32 let name_start = name_idx + 1;
34 let name = {
35 let range = name_start..(name_start + *name_size as usize);
36 let slice = &self.inner.frame.bytes[range];
37
38 std::str::from_utf8(slice).unwrap_or("INVALID.UTF-8")
39 };
40
41 let (field_idx, field_size) = {
44 let mut field_size = [0u8; 4];
45 let mut field_idx = 0;
46
47 for idx in 0..4 {
48 let (pos, byte) = self
49 .cursor
50 .next()
51 .map(|(idx, n)| (idx, *n))
52 .expect("Unexpected EOF");
53 field_idx = pos;
54 field_size[idx] = byte;
55 }
56
57 (field_idx + 1, u32::from_be_bytes(field_size) as usize)
58 };
59
60 let field = {
62 let range = field_idx..(field_idx + field_size as usize);
63 let slice = &self.inner.frame.bytes[range];
64
65 std::str::from_utf8(slice).unwrap_or("INVALID.UTF-8")
66 };
67
68 for _ in 0..field_size {
70 let _ = self.cursor.next();
71 }
72
73 Some((name, field))
74 }
75}
76
77pub struct Command<'a> {
80 pub(crate) frame: Frame<'a>,
81}
82
83impl<'a> Command<'a> {
84 pub fn new(frame: Frame<'a>) -> Self {
85 Self { frame }
86 }
87
88 pub fn name(&self) -> &str {
89 let idx = if self.frame.bytes[0] == 0x4 { 2 } else { 9 };
90 let size = self.frame.bytes[idx];
91 let start = idx + 1;
92 let end = start + (size as usize);
93 let st = std::str::from_utf8(&self.frame.bytes[start..end]).unwrap_or("INVALID.UTF-8");
94 st
95 }
96
97 #[inline]
102 pub fn null_ready_properties(&self) -> Option<impl Iterator<Item = (&str, &str)>> {
103 if self.name() != "READY" {
104 return None;
105 }
106
107 let cursor = self
108 .frame
109 .bytes
110 .iter()
111 .enumerate()
112 .skip(if self.frame.bytes[0] == 0x4 { 3 } else { 10 } + self.name().len());
115
116 let it = PropertyIterator {
117 inner: self,
118 cursor,
119 };
120
121 Some(it)
122 }
123}
124
125impl<'a> fmt::Debug for Command<'a> {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 f.write_fmt(format_args!(
128 "Command {{ name: {:#?}, properties: {:#?} }}",
129 self.name(),
130 self.null_ready_properties()
131 .map(|it| it.collect::<Vec<_>>())
132 .unwrap_or_default(),
133 ))
134 }
135}