1#[derive(Debug)]
3pub struct Command<'a> {
4 pub cla: u8,
5 pub ins: u8,
6 pub p1: u8,
7 pub p2: u8,
8 pub le: Option<u16>,
9 pub payload: Option<&'a [u8]>,
10}
11
12impl<'a> Command<'a> {
13 pub fn new(cla: u8, ins: u8, p1: u8, p2: u8) -> Self {
16 Self {
17 cla,
18 ins,
19 p1,
20 p2,
21 le: None,
22 payload: None,
23 }
24 }
25
26 pub fn new_with_le(cla: u8, ins: u8, p1: u8, p2: u8, le: u16) -> Self {
29 Self {
30 cla,
31 ins,
32 p1,
33 p2,
34 le: Some(le),
35 payload: None,
36 }
37 }
38
39 pub fn new_with_payload(cla: u8, ins: u8, p1: u8, p2: u8, payload: &'a [u8]) -> Self {
42 Self {
43 cla,
44 ins,
45 p1,
46 p2,
47 le: None,
48 payload: Some(payload),
49 }
50 }
51
52 pub fn new_with_payload_le(
55 cla: u8,
56 ins: u8,
57 p1: u8,
58 p2: u8,
59 le: u16,
60 payload: &'a [u8],
61 ) -> Self {
62 Self {
63 cla,
64 ins,
65 p1,
66 p2,
67 le: Some(le),
68 payload: Some(payload),
69 }
70 }
71
72 pub fn write(&self, buf: &mut [u8]) {
74 let Command {
75 cla,
76 ins,
77 p1,
78 p2,
79 le,
80 payload,
81 } = self;
82
83 struct Mutator<'a> {
86 buf: &'a mut [u8],
87 i: usize,
88 }
89
90 impl<'a> Mutator<'a> {
91 fn push(&mut self, b: u8) {
92 self.buf[self.i] = b;
93 self.i += 1;
94 }
95
96 fn extend(&mut self, b: &[u8]) {
97 let len = b.len();
98 self.buf[self.i..self.i + len].copy_from_slice(b);
99 self.i += len;
100 }
101 }
102
103 let mut m = Mutator { buf, i: 0 };
104 m.extend(&[*cla, *ins, *p1, *p2]);
105
106 let has_payload = &payload.is_some();
107 if let Some(p) = payload {
108 if cfg!(feature = "longer_payloads") && p.len() > u8::MAX as usize {
111 m.push(0u8);
112 m.push(p.len() as u8);
113 m.push((p.len() >> 8) as u8);
114 } else {
115 m.push(p.len() as u8);
116 }
117
118 m.extend(p);
119 }
120
121 if let Some(l) = *le {
122 if cfg!(feature = "longer_payloads") && l > u8::MAX.into() {
123 if !has_payload {
124 m.push(0u8);
125 }
126 m.push(l as u8);
127 m.push((l >> 8) as u8);
128 } else {
129 m.push(l as u8);
130 }
131 }
132 }
133
134 #[allow(clippy::len_without_is_empty)]
136 pub fn len(&self) -> usize {
137 let (lc, payload) = match self.payload {
138 Some(p) => (
139 match cfg!(feature = "longer_payloads") && p.len() > u8::MAX as usize {
140 true => 2,
141 _ => 1,
142 },
143 p.len(),
144 ),
145 _ => (0, 0),
146 };
147
148 let le = match self.le {
149 Some(l) => match cfg!(feature = "longer_payloads") && l > u8::MAX.into() {
150 true => match self.payload.is_some() {
151 true => 2,
152 _ => 3,
153 },
154 _ => 1,
155 },
156 _ => 0,
157 };
158
159 4 + lc + payload + le
161 }
162}
163
164#[cfg(feature = "std")]
165impl<'a> From<Command<'a>> for Vec<u8> {
166 fn from(command: Command) -> Self {
168 let len = command.len();
169 let mut buf = Vec::with_capacity(len);
170
171 #[allow(clippy::uninit_vec)]
172 unsafe {
173 buf.set_len(len);
174 }
175
176 command.write(&mut buf);
177
178 buf
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn command_to_vec() {
188 assert_eq!(
189 vec![0x01, 0x02, 0x03, 0x04, 0x03, 0x05, 0x06, 0x07, 0x08],
190 Vec::from(Command::new_with_payload_le(
191 0x01,
192 0x02,
193 0x03,
194 0x04,
195 0x08,
196 &[0x05, 0x06, 0x07]
197 )),
198 );
199 }
200}