Skip to main content

xvc_protocol/
rw.rs

1/// Read and write implementations for the protocol messages
2use std::io::{self, Read, Write};
3
4use crate::{
5    BorrowedMessage, Message, OwnedMessage, XvcCommand, XvcInfo,
6    codec::{ParseErr, SetTck, Shift},
7    error::ReadError,
8};
9
10/// Protocol decoder.
11///
12/// `Decoder` holds an internal buffer and reads from an underlying stream
13/// until a complete protocol frame or command can be parsed. It enforces a
14/// maximum buffer size to protect against oversized messages.
15///
16/// Typical usage:
17///
18/// ```rust
19/// use xvc_protocol::{Message, XvcInfo};
20/// use std::io::Cursor;
21///
22/// // Read a single message from a byte stream
23/// let mut data = b"getinfo:".as_slice();
24/// let mut dec = xvc_protocol::rw::Decoder::new(1024);
25/// let msg = dec.read_message(&mut data).unwrap();
26/// assert!(matches!(msg, Message::GetInfo));
27/// ```
28pub struct Decoder {
29    buf: Vec<u8>,
30    /// Limit on the internal buffer. Triggers `TooManyBytes` if exceeded.
31    max_buf: usize,
32    /// Per-vector limit for `Shift` payloads, enforced by the codec parser.
33    max_shift: usize,
34}
35
36impl Decoder {
37    /// Create a new decoder for reading protocol [`Message`]s.
38    ///
39    /// `max_shift` is the maximum number of bytes allowed for each of the TMS
40    /// and TDI vectors in a `Shift` command. The internal buffer is sized to
41    /// accommodate the full shift payload.
42    pub fn new(max_shift: usize) -> Self {
43        // Worst-case buffer during command parsing:
44        // command prefix ("settck:" = 7 bytes) + 4-byte num_bits field
45        // + two shift vectors. Padded to 16 for simplicity.
46        let max_buf = max_shift.saturating_mul(2).saturating_add(16);
47        Self {
48            buf: Vec::new(),
49            max_buf,
50            max_shift,
51        }
52    }
53
54    fn read_chunk(&mut self, reader: &mut impl Read) -> Result<(), ReadError> {
55        let mut temp = [0u8; 1024];
56        let read = loop {
57            match reader.read(&mut temp) {
58                Ok(n) => break n,
59                Err(e) if e.kind() == io::ErrorKind::Interrupted => {
60                    continue; // retry
61                }
62                Err(e) => return Err(e.into()), // real error
63            }
64        };
65        if read == 0 {
66            // EOF with partial data or on an empty buffer — either way unexpected.
67            return Err(io::Error::new(
68                io::ErrorKind::UnexpectedEof,
69                "unexpected EOF while reading",
70            )
71            .into());
72        }
73
74        if self.max_buf < read + self.buf.len() {
75            return Err(ReadError::TooManyBytes {
76                max: self.max_buf,
77                need: read + self.buf.len(),
78            });
79        }
80        self.buf.extend_from_slice(&temp[..read]);
81
82        Ok(())
83    }
84
85    /// Read an `XvcInfo` frame from `reader`.
86    ///
87    /// This method incrementally fills the internal buffer from `reader` until
88    /// a complete XVC server info frame is available and returns the parsed
89    /// `XvcInfo`. If EOF is encountered with partial data buffered, a
90    /// `ReadError::InvalidCommand` is returned.
91    pub fn read_xvc_info(&mut self, reader: &mut impl Read) -> Result<XvcInfo, ReadError> {
92        self.buf.clear();
93        loop {
94            let mut slice: &[u8] = &self.buf;
95            match XvcInfo::parse(&mut slice) {
96                Ok(frame) => {
97                    return Ok(frame);
98                }
99                Err(ParseErr::Incomplete) => {
100                    self.read_chunk(reader)?;
101                }
102                Err(other) => return Err(other.into()),
103            }
104        }
105    }
106
107    /// Read a single protocol `Message` from `reader`.
108    ///
109    /// The decoder reads from `reader` until a full command and its payload
110    /// are available, enforces negotiated limits (e.g. maximum shift buffer
111    /// size) and returns the parsed `Message`. On EOF with a partial
112    /// command present, a `ReadError::InvalidCommand` is returned.
113    ///
114    /// Example:
115    ///
116    /// ```rust
117    /// use std::io::Cursor;
118    /// let mut cursor = Cursor::new(b"getinfo:");
119    /// let mut dec = xvc_protocol::rw::Decoder::new(1024);
120    /// let msg = dec.read_message(&mut cursor).unwrap();
121    /// assert!(matches!(msg, xvc_protocol::Message::GetInfo));
122    /// ```
123    pub fn read_message(&mut self, reader: &mut impl Read) -> Result<OwnedMessage, ReadError> {
124        self.buf.clear();
125        let cmd = loop {
126            let mut slice: &[u8] = &self.buf;
127            match XvcCommand::parse(&mut slice) {
128                Ok(cmd) => {
129                    let consumed = self.buf.len() - slice.len();
130                    self.buf.drain(..consumed);
131                    break cmd;
132                }
133                Err(ParseErr::Incomplete) => {
134                    self.read_chunk(reader)?;
135                }
136                Err(other) => return Err(other.into()),
137            }
138        };
139        match cmd {
140            XvcCommand::GetInfo => Ok(Message::GetInfo),
141            XvcCommand::SetTck => loop {
142                let mut slice: &[u8] = &self.buf;
143                match SetTck::parse(&mut slice) {
144                    Ok(tck) => {
145                        return Ok(Message::SetTck {
146                            period_ns: tck.period(),
147                        });
148                    }
149                    Err(ParseErr::Incomplete) => {
150                        self.read_chunk(reader)?;
151                    }
152                    Err(other) => return Err(other.into()),
153                }
154            },
155            XvcCommand::Shift => loop {
156                let mut slice: &[u8] = &self.buf;
157                match Shift::parse(&mut slice, self.max_shift) {
158                    Ok(shift) => {
159                        let num_bits = shift.num_bits();
160                        let (tms, tdi) = shift.into_tms_tdi();
161                        return Ok(Message::Shift { num_bits, tms, tdi });
162                    }
163                    Err(ParseErr::Incomplete) => {
164                        self.read_chunk(reader)?;
165                    }
166                    Err(other) => return Err(other.into()),
167                }
168            },
169        }
170    }
171}
172
173impl XvcInfo {
174    /// Write this `XvcInfo` to `writer` in the protocol's server-info format.
175    ///
176    /// The output has the form `xvcServer_v<major>.<minor>:<max_vector_len>\n`.
177    /// This is the canonical representation sent by servers to announce
178    /// capabilities to clients.
179    pub fn write_to(&self, writer: &mut impl Write) -> io::Result<()> {
180        writeln!(
181            writer,
182            "xvcServer_v{}:{}",
183            self.version(),
184            self.max_vector_len()
185        )
186    }
187
188    /// Read an `XvcInfo` from `reader` using an internal `Decoder`.
189    ///
190    /// Example:
191    ///
192    /// ```rust
193    /// use std::io::Cursor;
194    /// let mut c = Cursor::new(b"xvcServer_v1.0:32\n");
195    /// let info = xvc_protocol::XvcInfo::from_reader(&mut c).unwrap();
196    /// assert_eq!(info.max_vector_len(), 32);
197    /// ```
198    pub fn from_reader(reader: &mut impl Read) -> Result<XvcInfo, ReadError> {
199        Decoder::new(4096).read_xvc_info(reader)
200    }
201}
202
203impl Message<Box<[u8]>> {
204    /// Read a `Message` from `reader` using an internal `Decoder`.
205    ///
206    /// This is a convenience wrapper that constructs a `Decoder` configured
207    /// with `max_shift_bytes` and delegates to its `read_message` method.
208    ///
209    /// Example:
210    ///
211    /// ```rust
212    /// use std::io::Cursor;
213    /// let mut c = Cursor::new(b"getinfo:");
214    /// let msg = xvc_protocol::OwnedMessage::from_reader(&mut c, 1024).unwrap();
215    /// assert!(matches!(msg, xvc_protocol::Message::GetInfo));
216    /// ```
217    pub fn from_reader(
218        reader: &mut impl Read,
219        max_shift_bytes: usize,
220    ) -> Result<OwnedMessage, ReadError> {
221        Decoder::new(max_shift_bytes).read_message(reader)
222    }
223
224    /// Borrows this message into a [BorrowedMessage]
225    pub fn borrow<'a>(&'a self) -> BorrowedMessage<'a> {
226        match self {
227            Message::GetInfo => BorrowedMessage::GetInfo,
228            Message::SetTck { period_ns } => Message::SetTck {
229                period_ns: *period_ns,
230            },
231            Message::Shift { num_bits, tms, tdi } => BorrowedMessage::Shift {
232                num_bits: *num_bits,
233                tms,
234                tdi,
235            },
236        }
237    }
238}
239
240impl<B: AsRef<[u8]>> Message<B> {
241    /// Serialize this `Message` to `writer` in the protocol command format.
242    ///
243    /// - `GetInfo` is written as `getinfo:`
244    /// - `SetTck` is written as `settck:` followed by a 4-byte little-endian period
245    /// - `Shift` is written as `shift:` followed by a 4-byte little-endian `num_bits`,
246    ///   then the `tms` and `tdi` payload bytes
247    ///
248    /// The function writes raw bytes and returns any I/O error encountered.
249    pub fn write_to(&self, writer: &mut impl Write) -> io::Result<()> {
250        use crate::codec::{CMD_GET_INFO, CMD_SET_TCK, CMD_SHIFT};
251        match self {
252            Message::GetInfo => writer.write_all(CMD_GET_INFO),
253            Message::SetTck {
254                period_ns: period_in_ns,
255            } => {
256                writer.write_all(CMD_SET_TCK)?;
257                writer.write_all(&period_in_ns.to_le_bytes())
258            }
259            Message::Shift { num_bits, tms, tdi } => {
260                writer.write_all(CMD_SHIFT)?;
261                writer.write_all(&num_bits.to_le_bytes())?;
262                writer.write_all(tms.as_ref())?;
263                writer.write_all(tdi.as_ref())
264            }
265        }
266    }
267}
268
269#[cfg(test)]
270mod test {
271    use std::{io, io::Cursor, vec};
272
273    use crate::{BorrowedMessage, OwnedMessage};
274
275    use super::*;
276
277    const DEFAULT_MAX_SHIFT_BYTES: usize = 1024;
278
279    #[test]
280    fn write_server_info() {
281        let mut out = Vec::new();
282        XvcInfo::default().write_to(&mut out).unwrap();
283        assert_eq!(out, b"xvcServer_v1.0:10485760\n".to_vec());
284    }
285
286    #[test]
287    fn read_server_info() {
288        let data = b"xvcServer_v1.0:32\n";
289        let mut cursor = std::io::Cursor::new(data);
290        let info = XvcInfo::from_reader(&mut cursor).unwrap();
291        assert_eq!(info.version(), crate::protocol::Version::V1_0);
292        assert_eq!(info.max_vector_len(), 32)
293    }
294
295    #[test]
296    fn read_getinfo() {
297        let data = b"getinfo:".to_vec();
298        let mut cursor = Cursor::new(data);
299        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
300            Message::GetInfo => {}
301            _ => panic!("expected GetInfo"),
302        }
303    }
304
305    #[test]
306    fn write_getinfo() {
307        let mut out = Vec::new();
308        BorrowedMessage::GetInfo.write_to(&mut out).unwrap();
309        assert_eq!(out, b"getinfo:".to_vec());
310    }
311
312    #[test]
313    fn read_settck() {
314        let period: u32 = 0x1234_5678;
315        let mut data = b"settck:".to_vec();
316        data.extend_from_slice(&period.to_le_bytes());
317        let mut cursor = Cursor::new(data);
318        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
319            Message::SetTck {
320                period_ns: period_in_ns,
321            } => assert_eq!(period_in_ns, period),
322            _ => panic!("expected SetTck"),
323        }
324    }
325
326    #[test]
327    fn write_settck() {
328        let period: u32 = 0x1234_5678;
329        let mut out = Vec::new();
330        BorrowedMessage::SetTck { period_ns: period }
331            .write_to(&mut out)
332            .unwrap();
333        let mut expected = b"settck:".to_vec();
334        expected.extend_from_slice(&period.to_le_bytes());
335        assert_eq!(out, expected);
336    }
337
338    #[test]
339    fn read_shift() {
340        let num_bits: u32 = 13; // 2 bytes
341        let num_bytes = num_bits.div_ceil(8) as usize;
342        let tms = vec![0xAAu8; num_bytes];
343        let tdi = vec![0x55u8; num_bytes];
344
345        let mut data = b"shift:".to_vec();
346        data.extend_from_slice(&num_bits.to_le_bytes());
347        data.extend_from_slice(&tms);
348        data.extend_from_slice(&tdi);
349
350        let mut cursor = Cursor::new(data);
351        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
352            Message::Shift {
353                num_bits: nb,
354                tms: tms_vector,
355                tdi: tdi_vector,
356            } => {
357                assert_eq!(nb, num_bits);
358                assert_eq!(&*tms_vector, &tms[..]);
359                assert_eq!(&*tdi_vector, &tdi[..]);
360            }
361            _ => panic!("expected Shift"),
362        }
363    }
364
365    #[test]
366    fn write_shift() {
367        let num_bits: u32 = 13; // 2 bytes
368        let num_bytes = num_bits.div_ceil(8) as usize;
369        let tms = vec![0xAAu8; num_bytes];
370        let tdi = vec![0x55u8; num_bytes];
371
372        let cmd = BorrowedMessage::Shift {
373            num_bits,
374            tms: &tms,
375            tdi: &tdi,
376        };
377        let mut out = Vec::new();
378        cmd.write_to(&mut out).unwrap();
379
380        let mut expected = b"shift:".to_vec();
381        expected.extend_from_slice(&num_bits.to_le_bytes());
382        expected.extend_from_slice(&tms);
383        expected.extend_from_slice(&tdi);
384
385        assert_eq!(out, expected);
386    }
387
388    #[test]
389    fn invalid_prefix() {
390        let data = b"xx".to_vec();
391        let mut cursor = Cursor::new(data);
392        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES) {
393            Err(ReadError::InvalidCommand(p)) => assert_eq!(p, "xx"),
394            other => panic!("expected InvalidCommand, got {:?}", other),
395        }
396    }
397
398    #[test]
399    fn too_many_bytes_shift() {
400        let num_bytes_exceed = 1024 + 1;
401        let num_bits = (num_bytes_exceed * 8) as u32;
402        let mut data = b"shift:".to_vec();
403        data.extend_from_slice(&num_bits.to_le_bytes());
404        let mut cursor = Cursor::new(data);
405        match OwnedMessage::from_reader(&mut cursor, 1024) {
406            Err(ReadError::TooManyBytes { max, need: got }) => {
407                assert_eq!(max, 1024);
408                assert_eq!(got, num_bytes_exceed);
409            }
410            other => panic!("expected TooManyBytes, got {:?}", other),
411        }
412    }
413
414    #[test]
415    fn read_xvc_info_with_max_u32_vector_len() {
416        let data = b"xvcServer_v1.0:4294967295\n";
417        let mut cursor = Cursor::new(data);
418        let info = XvcInfo::from_reader(&mut cursor).unwrap();
419        assert_eq!(info.version(), crate::protocol::Version::V1_0);
420        assert_eq!(info.max_vector_len(), u32::MAX);
421    }
422
423    #[test]
424    fn read_xvc_info_with_zero_vector_len() {
425        let data = b"xvcServer_v1.0:0\n";
426        let mut cursor = Cursor::new(data);
427        let info = XvcInfo::from_reader(&mut cursor).unwrap();
428        assert_eq!(info.version(), crate::protocol::Version::V1_0);
429        assert_eq!(info.max_vector_len(), 0);
430    }
431
432    #[test]
433    fn read_xvc_info_with_large_version_numbers() {
434        let data = b"xvcServer_v999.999:1024\n";
435        let mut cursor = Cursor::new(data);
436        let info = XvcInfo::from_reader(&mut cursor).unwrap();
437        assert_eq!(info.version(), crate::protocol::Version::new(999, 999));
438        assert_eq!(info.max_vector_len(), 1024);
439    }
440
441    #[test]
442    fn read_xvc_info_incomplete_then_complete() {
443        let data = b"xvcServer_v1.0:4\n";
444        let mut cursor = Cursor::new(data);
445        match XvcInfo::from_reader(&mut cursor) {
446            Ok(info) => assert_eq!(info.max_vector_len(), 4),
447            Err(e) => panic!("unexpected error: {:?}", e),
448        }
449    }
450
451    #[test]
452    fn write_xvc_info_max_values() {
453        let mut out = Vec::new();
454        let info = XvcInfo::new(crate::protocol::Version::new(255, 255), u32::MAX);
455        info.write_to(&mut out).unwrap();
456        assert_eq!(out, b"xvcServer_v255.255:4294967295\n".to_vec());
457    }
458
459    #[test]
460    fn read_getinfo_with_extra_data() {
461        let data = b"getinfo:getinfo:";
462        let mut cursor = Cursor::new(data);
463        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
464            Message::GetInfo => {}
465            _ => panic!("expected GetInfo"),
466        }
467    }
468
469    #[test]
470    fn read_getinfo_exact() {
471        let data = b"getinfo:";
472        let mut cursor = Cursor::new(data);
473        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
474            Message::GetInfo => {}
475            _ => panic!("expected GetInfo"),
476        }
477    }
478
479    #[test]
480    fn read_settck_zero_period() {
481        let period: u32 = 0;
482        let mut data = b"settck:".to_vec();
483        data.extend_from_slice(&period.to_le_bytes());
484        let mut cursor = Cursor::new(data);
485        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
486            Message::SetTck {
487                period_ns: period_in_ns,
488            } => assert_eq!(period_in_ns, 0),
489            _ => panic!("expected SetTck"),
490        }
491    }
492
493    #[test]
494    fn read_settck_max_period() {
495        let period: u32 = u32::MAX;
496        let mut data = b"settck:".to_vec();
497        data.extend_from_slice(&period.to_le_bytes());
498        let mut cursor = Cursor::new(data);
499        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
500            Message::SetTck {
501                period_ns: period_in_ns,
502            } => assert_eq!(period_in_ns, u32::MAX),
503            _ => panic!("expected SetTck"),
504        }
505    }
506
507    #[test]
508    fn read_settck_incomplete() {
509        // Command parsed successfully but stream ends before the 4-byte payload
510        let data = b"settck:".to_vec();
511        let mut cursor = Cursor::new(data);
512        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES) {
513            Err(ReadError::IoError(_)) => {}
514            other => panic!("expected IoError (unexpected EOF), got {:?}", other),
515        }
516    }
517
518    #[test]
519    fn read_settck_partial_period() {
520        let mut data = b"settck:".to_vec();
521        data.extend_from_slice(&[0xAA, 0xBB]);
522        let mut cursor = Cursor::new(data);
523        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES) {
524            Err(ReadError::IoError(e)) if e.kind() == io::ErrorKind::UnexpectedEof => {}
525            other => panic!("expected UnexpectedEof, got {:?}", other),
526        }
527    }
528
529    #[test]
530    fn read_shift_zero_bits() {
531        let num_bits: u32 = 0;
532        let mut data = b"shift:".to_vec();
533        data.extend_from_slice(&num_bits.to_le_bytes());
534
535        let mut cursor = Cursor::new(data);
536        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
537            Message::Shift {
538                num_bits: nb,
539                tms: tms_vector,
540                tdi: tdi_vector,
541            } => {
542                assert_eq!(nb, 0);
543                assert_eq!(&*tms_vector, &[] as &[u8]);
544                assert_eq!(&*tdi_vector, &[] as &[u8]);
545            }
546            _ => panic!("expected Shift"),
547        }
548    }
549
550    #[test]
551    fn read_shift_one_bit() {
552        let num_bits: u32 = 1;
553        let tms = vec![0x00u8];
554        let tdi = vec![0x01u8];
555
556        let mut data = b"shift:".to_vec();
557        data.extend_from_slice(&num_bits.to_le_bytes());
558        data.extend_from_slice(&tms);
559        data.extend_from_slice(&tdi);
560
561        let mut cursor = Cursor::new(data);
562        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
563            Message::Shift {
564                num_bits: nb,
565                tms: tms_vector,
566                tdi: tdi_vector,
567            } => {
568                assert_eq!(nb, 1);
569                assert_eq!(&*tms_vector, &tms[..]);
570                assert_eq!(&*tdi_vector, &tdi[..]);
571            }
572            _ => panic!("expected Shift"),
573        }
574    }
575
576    #[test]
577    fn read_shift_max_bits() {
578        let num_bits: u32 = u32::MAX;
579        let mut data = b"shift:".to_vec();
580        data.extend_from_slice(&num_bits.to_le_bytes());
581
582        let mut cursor = Cursor::new(data);
583        match OwnedMessage::from_reader(&mut cursor, 1024) {
584            Err(ReadError::TooManyBytes { .. }) => {}
585            other => panic!("expected TooManyBytes, got {:?}", other),
586        }
587    }
588
589    #[test]
590    fn read_shift_incomplete_num_bits() {
591        let mut data = b"shift:".to_vec();
592        data.extend_from_slice(&[0xAA, 0xBB]);
593
594        let mut cursor = Cursor::new(data);
595        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES) {
596            Err(ReadError::IoError(e)) if e.kind() == io::ErrorKind::UnexpectedEof => {}
597            other => panic!("expected UnexpectedEof, got {:?}", other),
598        }
599    }
600
601    #[test]
602    fn read_shift_incomplete_tms() {
603        let num_bits: u32 = 16;
604        let mut data = b"shift:".to_vec();
605        data.extend_from_slice(&num_bits.to_le_bytes());
606        data.extend_from_slice(&[0xAA]);
607
608        let mut cursor = Cursor::new(data);
609        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES) {
610            Err(ReadError::IoError(e)) if e.kind() == io::ErrorKind::UnexpectedEof => {}
611            other => panic!("expected UnexpectedEof, got {:?}", other),
612        }
613    }
614
615    #[test]
616    fn read_shift_incomplete_tdi() {
617        let num_bits: u32 = 8;
618        let mut data = b"shift:".to_vec();
619        data.extend_from_slice(&num_bits.to_le_bytes());
620        data.extend_from_slice(&[0xAA]); // TMS only
621
622        let mut cursor = Cursor::new(data);
623        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES) {
624            Err(ReadError::IoError(e)) if e.kind() == io::ErrorKind::UnexpectedEof => {}
625            other => panic!("expected UnexpectedEof, got {:?}", other),
626        }
627    }
628
629    #[test]
630    fn read_shift_large_vectors() {
631        let num_bits: u32 = 1000;
632        let num_bytes = num_bits.div_ceil(8) as usize;
633        let tms = vec![0xAA; num_bytes];
634        let tdi = vec![0x55; num_bytes];
635
636        let mut data = b"shift:".to_vec();
637        data.extend_from_slice(&num_bits.to_le_bytes());
638        data.extend_from_slice(&tms);
639        data.extend_from_slice(&tdi);
640
641        let mut cursor = Cursor::new(data);
642        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
643            Message::Shift {
644                num_bits: nb,
645                tms: tms_vector,
646                tdi: tdi_vector,
647            } => {
648                assert_eq!(nb, num_bits);
649                assert_eq!(&*tms_vector, &tms[..]);
650                assert_eq!(&*tdi_vector, &tdi[..]);
651            }
652            _ => panic!("expected Shift"),
653        }
654    }
655
656    #[test]
657    fn shift_at_exact_max_vector_size_succeeds() {
658        // Vectors that are exactly max_shift bytes must be accepted.
659        let max_shift = 4;
660        let num_bytes = 4usize;
661        let num_bits: u32 = (num_bytes * 8) as u32;
662
663        let mut data = b"shift:".to_vec();
664        data.extend_from_slice(&num_bits.to_le_bytes());
665        data.extend_from_slice(&[0xAA; 4]);
666        data.extend_from_slice(&[0x55; 4]);
667
668        let mut cursor = Cursor::new(data);
669        assert!(
670            OwnedMessage::from_reader(&mut cursor, max_shift).is_ok(),
671            "vectors exactly at max_shift should be accepted"
672        );
673    }
674
675    #[test]
676    fn shift_over_max_vector_size_fails() {
677        // Vectors one byte over max_shift must be rejected with TooManyBytes.
678        let max_shift = 4;
679        let num_bytes = 5usize;
680        let num_bits: u32 = (num_bytes * 8) as u32;
681
682        let mut data = b"shift:".to_vec();
683        data.extend_from_slice(&num_bits.to_le_bytes());
684        data.extend_from_slice(&[0xAA; 5]);
685        data.extend_from_slice(&[0x55; 5]);
686
687        let mut cursor = Cursor::new(data);
688        match OwnedMessage::from_reader(&mut cursor, max_shift) {
689            Err(ReadError::TooManyBytes { .. }) => {}
690            other => panic!("expected TooManyBytes, got {:?}", other),
691        }
692    }
693
694    #[test]
695    fn write_shift_zero_bits() {
696        let cmd = BorrowedMessage::Shift {
697            num_bits: 0,
698            tms: &[],
699            tdi: &[],
700        };
701        let mut out = Vec::new();
702        cmd.write_to(&mut out).unwrap();
703
704        let mut expected = b"shift:".to_vec();
705        expected.extend_from_slice(&0u32.to_le_bytes());
706        assert_eq!(out, expected);
707    }
708
709    #[test]
710    fn write_shift_max_bits() {
711        let cmd = BorrowedMessage::Shift {
712            num_bits: u32::MAX,
713            tms: &[0xFFu8; 512],
714            tdi: &[0xAAu8; 512],
715        };
716        let mut out = Vec::new();
717        cmd.write_to(&mut out).unwrap();
718
719        let mut expected = b"shift:".to_vec();
720        expected.extend_from_slice(&u32::MAX.to_le_bytes());
721        expected.extend_from_slice(&[0xFF; 512]);
722        expected.extend_from_slice(&[0xAA; 512]);
723        assert_eq!(out, expected);
724    }
725
726    #[test]
727    fn invalid_command_name() {
728        let data = b"invalid:".to_vec();
729        let mut cursor = Cursor::new(data);
730        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES) {
731            Err(ReadError::InvalidCommand(_)) => {}
732            other => panic!("expected InvalidCommand, got {:?}", other),
733        }
734    }
735
736    #[test]
737    fn empty_input() {
738        let data = b"".to_vec();
739        let mut cursor = Cursor::new(data);
740        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES) {
741            Err(ReadError::IoError(_)) => {}
742            other => panic!("expected IoError, got {:?}", other),
743        }
744    }
745
746    #[test]
747    fn only_delimiter() {
748        let data = b":".to_vec();
749        let mut cursor = Cursor::new(data);
750        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES) {
751            Err(ReadError::InvalidCommand(_)) => {}
752            other => panic!("expected InvalidCommand, got {:?}", other),
753        }
754    }
755
756    #[test]
757    fn binary_garbage_input() {
758        let data = vec![0xFF, 0xFE, 0xFD, 0xFC];
759        let mut cursor = Cursor::new(data);
760        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES) {
761            Err(ReadError::InvalidCommand(_)) => {}
762            other => panic!("expected InvalidCommand, got {:?}", other),
763        }
764    }
765
766    #[test]
767    fn roundtrip_xvc_info() {
768        let original = XvcInfo::new(crate::protocol::Version::new(1, 0), 8192);
769        let mut buffer = Vec::new();
770        original.write_to(&mut buffer).unwrap();
771
772        let mut cursor = Cursor::new(buffer);
773        let parsed = XvcInfo::from_reader(&mut cursor).unwrap();
774
775        assert_eq!(parsed.version(), original.version());
776        assert_eq!(parsed.max_vector_len(), original.max_vector_len());
777    }
778
779    #[test]
780    fn roundtrip_getinfo() {
781        let original = BorrowedMessage::GetInfo;
782        let mut buffer = Vec::new();
783        original.write_to(&mut buffer).unwrap();
784
785        let mut cursor = Cursor::new(buffer);
786        let parsed = OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap();
787
788        assert_eq!(parsed.borrow(), original);
789    }
790
791    #[test]
792    fn roundtrip_settck() {
793        let original = Message::SetTck {
794            period_ns: 0x12345678,
795        };
796        let mut buffer = Vec::new();
797        original.write_to(&mut buffer).unwrap();
798
799        let mut cursor = Cursor::new(buffer);
800        let parsed = OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap();
801
802        assert_eq!(parsed.borrow(), original);
803    }
804
805    #[test]
806    fn roundtrip_shift() {
807        let num_bits = 128;
808        let num_bytes = (num_bits / 8) as usize;
809        let original = OwnedMessage::Shift {
810            num_bits,
811            tms: vec![0xAA; num_bytes].into_boxed_slice(),
812            tdi: vec![0x55; num_bytes].into_boxed_slice(),
813        };
814        let mut buffer = Vec::new();
815        original.write_to(&mut buffer).unwrap();
816
817        let mut cursor = Cursor::new(buffer);
818        let parsed = OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap();
819
820        assert_eq!(parsed, original);
821    }
822
823    #[test]
824    fn shift_num_bits_rounding() {
825        let num_bits: u32 = 13;
826        let num_bytes = num_bits.div_ceil(8) as usize;
827        let tms = vec![0xAA; num_bytes];
828        let tdi = vec![0x55; num_bytes];
829
830        let mut data = b"shift:".to_vec();
831        data.extend_from_slice(&num_bits.to_le_bytes());
832        data.extend_from_slice(&tms);
833        data.extend_from_slice(&tdi);
834
835        let mut cursor = Cursor::new(data);
836        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
837            Message::Shift {
838                num_bits: nb,
839                tms: tms_vector,
840                tdi: tdi_vector,
841            } => {
842                assert_eq!(nb, 13);
843                assert_eq!(tms_vector.len(), 2);
844                assert_eq!(tdi_vector.len(), 2);
845            }
846            _ => panic!("expected Shift"),
847        }
848    }
849
850    #[test]
851    fn shift_1_bit_requires_1_byte() {
852        let num_bits: u32 = 1;
853        let tms = vec![0x00; 1];
854        let tdi = vec![0x01; 1];
855
856        let mut data = b"shift:".to_vec();
857        data.extend_from_slice(&num_bits.to_le_bytes());
858        data.extend_from_slice(&tms);
859        data.extend_from_slice(&tdi);
860
861        let mut cursor = Cursor::new(data);
862        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
863            Message::Shift {
864                num_bits: nb,
865                tms: tms_vector,
866                tdi: tdi_vector,
867            } => {
868                assert_eq!(nb, 1);
869                assert_eq!(tms_vector.len(), 1);
870                assert_eq!(tdi_vector.len(), 1);
871            }
872            _ => panic!("expected Shift"),
873        }
874    }
875
876    #[test]
877    fn shift_8_bits_requires_1_byte() {
878        let num_bits: u32 = 8;
879        let tms = vec![0xFF; 1];
880        let tdi = vec![0xAA; 1];
881
882        let mut data = b"shift:".to_vec();
883        data.extend_from_slice(&num_bits.to_le_bytes());
884        data.extend_from_slice(&tms);
885        data.extend_from_slice(&tdi);
886
887        let mut cursor = Cursor::new(data);
888        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
889            Message::Shift {
890                num_bits: nb,
891                tms: tms_vector,
892                tdi: tdi_vector,
893            } => {
894                assert_eq!(nb, 8);
895                assert_eq!(tms_vector.len(), 1);
896                assert_eq!(tdi_vector.len(), 1);
897            }
898            _ => panic!("expected Shift"),
899        }
900    }
901
902    #[test]
903    fn shift_9_bits_requires_2_bytes() {
904        let num_bits: u32 = 9;
905        let tms = vec![0xFF; 2];
906        let tdi = vec![0xAA; 2];
907
908        let mut data = b"shift:".to_vec();
909        data.extend_from_slice(&num_bits.to_le_bytes());
910        data.extend_from_slice(&tms);
911        data.extend_from_slice(&tdi);
912
913        let mut cursor = Cursor::new(data);
914        match OwnedMessage::from_reader(&mut cursor, DEFAULT_MAX_SHIFT_BYTES).unwrap() {
915            Message::Shift {
916                num_bits: nb,
917                tms: tms_vector,
918                tdi: tdi_vector,
919            } => {
920                assert_eq!(nb, 9);
921                assert_eq!(tms_vector.len(), 2);
922                assert_eq!(tdi_vector.len(), 2);
923            }
924            _ => panic!("expected Shift"),
925        }
926    }
927
928    #[test]
929    fn decoder_reusable_reads_two_messages() {
930        let mut cursor = Cursor::new(b"getinfo:");
931        let mut dec = Decoder::new(1024);
932        assert!(matches!(
933            dec.read_message(&mut cursor).unwrap(),
934            Message::GetInfo
935        ));
936        let mut cursor2 = Cursor::new(b"settck:\x42\x00\x00\x00");
937        assert!(matches!(
938            dec.read_message(&mut cursor2).unwrap(),
939            Message::SetTck { period_ns: 0x42 }
940        ));
941    }
942}