1use std::{num::ParseIntError, str::Utf8Error};
2
3use crate::{
4 XvcCommand,
5 error::ParseVersionError,
6 protocol::{Version, XvcInfo},
7};
8
9const XVC_SERVER_PREFIX: &[u8] = b"xvcServer_v";
10
11pub(crate) const CMD_GET_INFO: &[u8] = b"getinfo:";
12pub(crate) const CMD_SET_TCK: &[u8] = b"settck:";
13pub(crate) const CMD_SHIFT: &[u8] = b"shift:";
14
15struct SliceReader<'a>(&'a [u8]);
17
18impl<'a> SliceReader<'a> {
19 fn remaining(&self) -> usize {
20 self.0.len()
21 }
22
23 fn advance(&mut self, n: usize) {
24 self.0 = &self.0[n..];
25 }
26
27 fn get_u32_le(&mut self) -> u32 {
28 let v = u32::from_le_bytes([self.0[0], self.0[1], self.0[2], self.0[3]]);
29 self.advance(4);
30 v
31 }
32
33 fn copy_to_boxed_slice(&mut self, n: usize) -> Box<[u8]> {
34 let out: Box<[u8]> = self.0[..n].into();
35 self.advance(n);
36 out
37 }
38}
39
40impl XvcInfo {
41 pub fn parse(buf: &mut &[u8]) -> ParseResult<XvcInfo> {
42 let Some(newline_index) = buf.iter().position(|b| *b == b'\n') else {
43 return Err(ParseErr::Incomplete);
44 };
45 let line = &buf[..newline_index];
46 *buf = &buf[newline_index + 1..];
47 let rest = line
48 .strip_prefix(XVC_SERVER_PREFIX)
49 .ok_or_else(|| ParseErr::InvalidCommand(line.into()))?;
50 let colon_index = rest
51 .iter()
52 .position(|byte| *byte == b':')
53 .ok_or_else(|| ParseErr::InvalidCommand(line.into()))?;
54 let version = core::str::from_utf8(&rest[..colon_index])?.parse::<Version>()?;
55 let max_vector_len = core::str::from_utf8(&rest[colon_index + 1..])?.parse::<u32>()?;
56 Ok(XvcInfo::new(version, max_vector_len))
57 }
58}
59
60#[derive(Eq, PartialEq, Clone, Debug)]
64pub enum ParseErr {
65 Incomplete,
67 InvalidCommand(Box<[u8]>),
69 TooManyBytes { max: usize, got: usize },
73 Utf8Error(Utf8Error),
75 ParseIntError(ParseIntError),
77 ParseVersionError(ParseVersionError),
79}
80
81impl From<Utf8Error> for ParseErr {
82 fn from(value: Utf8Error) -> Self {
83 ParseErr::Utf8Error(value)
84 }
85}
86
87impl From<ParseIntError> for ParseErr {
88 fn from(value: ParseIntError) -> Self {
89 ParseErr::ParseIntError(value)
90 }
91}
92
93impl From<ParseVersionError> for ParseErr {
94 fn from(value: ParseVersionError) -> Self {
95 ParseErr::ParseVersionError(value)
96 }
97}
98
99pub type ParseResult<T> = core::result::Result<T, ParseErr>;
100
101impl XvcCommand {
102 pub fn parse(buf: &mut &[u8]) -> ParseResult<XvcCommand> {
128 let (cmd, n) = if buf.starts_with(CMD_GET_INFO) {
129 (XvcCommand::GetInfo, CMD_GET_INFO.len())
130 } else if buf.starts_with(CMD_SET_TCK) {
131 (XvcCommand::SetTck, CMD_SET_TCK.len())
132 } else if buf.starts_with(CMD_SHIFT) {
133 (XvcCommand::Shift, CMD_SHIFT.len())
134 } else {
135 return if CMD_GET_INFO.starts_with(buf)
136 || CMD_SET_TCK.starts_with(buf)
137 || CMD_SHIFT.starts_with(buf)
138 {
139 Err(ParseErr::Incomplete)
140 } else {
141 Err(ParseErr::InvalidCommand((*buf).into()))
142 };
143 };
144 *buf = &buf[n..];
145 Ok(cmd)
146 }
147}
148
149pub struct SetTck {
150 period: u32,
151}
152
153impl SetTck {
154 pub fn period(&self) -> u32 {
155 self.period
156 }
157}
158
159impl SetTck {
160 pub fn parse(buf: &mut &[u8]) -> ParseResult<Self> {
161 let mut r = SliceReader(buf);
162 if r.remaining() < 4 {
163 return Err(ParseErr::Incomplete);
164 }
165 let period = r.get_u32_le();
166 *buf = r.0;
167 Ok(SetTck { period })
168 }
169}
170
171pub struct Shift {
172 num_bits: u32,
173 tdi: Box<[u8]>,
174 tms: Box<[u8]>,
175}
176
177impl Shift {
178 pub fn num_bits(&self) -> u32 {
179 self.num_bits
180 }
181
182 #[cfg(test)]
183 pub fn tdi(&self) -> &[u8] {
184 &self.tdi
185 }
186
187 #[cfg(test)]
188 pub fn tms(&self) -> &[u8] {
189 &self.tms
190 }
191
192 pub fn into_tms_tdi(self) -> (Box<[u8]>, Box<[u8]>) {
193 (self.tms, self.tdi)
194 }
195}
196
197impl Shift {
198 pub fn parse_num_bits(buf: &mut &[u8]) -> ParseResult<u32> {
199 let mut r = SliceReader(buf);
200 if r.remaining() < 4 {
201 return Err(ParseErr::Incomplete);
202 }
203 let n = r.get_u32_le();
204 *buf = r.0;
205 Ok(n)
206 }
207
208 pub fn parse_tdi_or_tms(
210 buf: &mut &[u8],
211 num_bytes: usize,
212 max_len: usize,
213 ) -> ParseResult<Box<[u8]>> {
214 if num_bytes > max_len {
215 return Err(ParseErr::TooManyBytes {
216 max: max_len,
217 got: num_bytes,
218 });
219 }
220 let mut r = SliceReader(buf);
221 if r.remaining() < num_bytes {
222 return Err(ParseErr::Incomplete);
223 }
224 let out = r.copy_to_boxed_slice(num_bytes);
225 *buf = r.0;
226 Ok(out)
227 }
228
229 pub fn parse(buf: &mut &[u8], max_len: usize) -> ParseResult<Shift> {
230 let num_bits = Self::parse_num_bits(buf)?;
231 let num_bytes = num_bits.div_ceil(8) as usize;
232 let tms = Self::parse_tdi_or_tms(buf, num_bytes, max_len)?;
233 let tdi = Self::parse_tdi_or_tms(buf, num_bytes, max_len)?;
234 Ok(Shift { num_bits, tdi, tms })
235 }
236}
237
238#[cfg(test)]
239mod tests {
240 use std::vec::Vec;
241
242 use super::*;
243
244 #[test]
245 fn parses_valid_xvc_info() {
246 let mut info1: &[u8] = b"xvcServer_v1.0:4\n";
247 assert_eq!(
248 XvcInfo::parse(&mut info1),
249 Ok(XvcInfo::new(Version::new(1, 0), 4))
250 );
251
252 let mut info2: &[u8] = b"xvcServer_v10.2:24\n";
253 assert_eq!(
254 XvcInfo::parse(&mut info2),
255 Ok(XvcInfo::new(Version::new(10, 2), 24))
256 );
257 }
258
259 #[test]
260 fn xvc_info_incomplete_no_newline() {
261 let mut buf: &[u8] = b"xvcServer_v1.0:4"; assert!(matches!(
263 XvcInfo::parse(&mut buf),
264 Err(ParseErr::Incomplete)
265 ));
266 }
267
268 #[test]
269 fn xvc_info_invalid_prefix() {
270 let mut buf: &[u8] = b"badprefix:1.0:4\n";
271 assert!(matches!(
272 XvcInfo::parse(&mut buf),
273 Err(ParseErr::InvalidCommand(_))
274 ));
275 }
276
277 #[test]
278 fn xvc_info_missing_colon() {
279 let mut buf: &[u8] = b"xvcServer_v1.0\n";
280 assert!(matches!(
281 XvcInfo::parse(&mut buf),
282 Err(ParseErr::InvalidCommand(_))
283 ));
284 }
285
286 #[test]
287 fn xvc_info_malformed_version() {
288 let mut buf: &[u8] = b"xvcServer_v1.a:4\n";
289 assert!(matches!(
290 XvcInfo::parse(&mut buf),
291 Err(ParseErr::ParseVersionError(_))
292 ));
293 }
294
295 #[test]
296 fn xvc_info_invalid_max_vector_len() {
297 let mut buf: &[u8] = b"xvcServer_v1.0:NaN\n";
298 assert!(matches!(
299 XvcInfo::parse(&mut buf),
300 Err(ParseErr::ParseIntError(_))
301 ));
302 }
303
304 #[test]
305 fn xvc_command_parse_valid_and_rest() {
306 let mut buf: &[u8] = b"settck:\x64";
307 let cmd = XvcCommand::parse(&mut buf).expect("should parse settck");
308 assert_eq!(cmd, XvcCommand::SetTck);
309 assert_eq!(buf, b"\x64");
310 }
311
312 #[test]
313 fn xvc_command_parse_incomplete() {
314 let mut buf: &[u8] = b"getin";
315 assert!(matches!(
316 XvcCommand::parse(&mut buf),
317 Err(ParseErr::Incomplete)
318 ));
319 }
320
321 #[test]
322 fn xvc_command_parse_invalid() {
323 let mut buf: &[u8] = b"unknown:";
324 assert!(matches!(
325 XvcCommand::parse(&mut buf),
326 Err(ParseErr::InvalidCommand(_))
327 ));
328 }
329
330 #[test]
331 fn set_tck_parse_ok_and_incomplete() {
332 let mut buf: &[u8] = &[0x01u8, 0x00, 0x00, 0x00];
333 let set = SetTck::parse(&mut buf).expect("should parse period");
334 assert_eq!(set.period(), 1);
335 assert!(buf.is_empty());
336
337 let mut short: &[u8] = &[0u8, 0u8, 0u8];
338 assert!(matches!(
339 SetTck::parse(&mut short),
340 Err(ParseErr::Incomplete)
341 ));
342 }
343
344 #[test]
345 fn shift_parse_num_bits_behaviour() {
346 let mut short: &[u8] = &[0u8, 0, 0];
347 assert!(matches!(
348 Shift::parse_num_bits(&mut short),
349 Err(ParseErr::Incomplete)
350 ));
351 let mut v: &[u8] = &[0x0Cu8, 0, 0, 0]; let num_bits = Shift::parse_num_bits(&mut v).expect("should parse num bits");
353 assert_eq!(num_bits, 12);
354 assert!(v.is_empty());
355 }
356
357 #[test]
358 fn parse_tdi_or_tms_edge_cases() {
359 let mut buf: &[u8] = &[0u8; 4];
360 assert!(matches!(
361 Shift::parse_tdi_or_tms(&mut buf, 5, 4),
362 Err(ParseErr::TooManyBytes { .. })
363 ));
364
365 let mut buf: &[u8] = &[0u8; 1];
366 assert!(matches!(
367 Shift::parse_tdi_or_tms(&mut buf, 2, 4),
368 Err(ParseErr::Incomplete)
369 ));
370
371 let mut buf: &[u8] = &[0xAAu8; 4];
372 let slice = Shift::parse_tdi_or_tms(&mut buf, 4, 4).expect("should parse all bytes");
373 assert_eq!(&slice[..], &[0xAAu8; 4]);
374 assert!(buf.is_empty());
375 }
376
377 #[test]
378 fn shift_parse_ok() {
379 let mut buf: Vec<u8> = Vec::new();
380 buf.extend_from_slice(&12u32.to_le_bytes());
381 let tms = [0xAAu8, 0xBB];
382 let tdi = [0x11u8, 0x22];
383 buf.extend_from_slice(&tms);
384 buf.extend_from_slice(&tdi);
385
386 let mut slice: &[u8] = &buf;
387 let shift = Shift::parse(&mut slice, 4).expect("shift parse should succeed");
388 assert_eq!(shift.num_bits(), 12);
389 assert_eq!(shift.tms(), &tms);
390 assert_eq!(shift.tdi(), &tdi);
391 assert!(slice.is_empty());
392 }
393
394 #[test]
395 fn shift_parse_too_many_bytes_error() {
396 let mut buf: Vec<u8> = Vec::new();
397 buf.extend_from_slice(&16u32.to_le_bytes()); buf.extend_from_slice(&[0u8, 0u8]);
399 buf.extend_from_slice(&[0u8, 0u8]);
400
401 let mut slice: &[u8] = &buf;
402 assert!(matches!(
403 Shift::parse(&mut slice, 1),
404 Err(ParseErr::TooManyBytes { .. })
405 ));
406 }
407}