Skip to main content

packbits_rle/
lib.rs

1#![doc = include_str!("../README.md")]
2#![feature(seek_stream_len)]
3#![feature(iter_array_chunks)]
4use std::{
5    io::{self, ErrorKind},
6    iter,
7};
8
9mod reader;
10
11pub use reader::Reader;
12
13#[derive(Debug, thiserror::Error)]
14/// General error used in packbit extraction
15pub enum Error {
16    /// Input does not provide enough data to fill the requested size
17    #[error("Input does not contain enough packbits data to fill the buffer")]
18    NotEnoughInputData,
19
20    /// The output buffer is too small or the decoded size does not fit into the requested size
21    #[error("Output buffer is too small to hold decoded data")]
22    TooMuchOutputData,
23
24    /// Input has additional unread data left after decoding
25    #[error("Input has unread data left after filling the output buffer")]
26    TooMuchInputData,
27
28    /// An operation (like read or seek) on the underlying reader has failed
29    #[error(transparent)]
30    Io(#[from] io::Error),
31}
32
33impl From<Error> for io::Error {
34    fn from(value: Error) -> Self {
35        match value {
36            Error::Io(error) => error,
37            me => io::Error::other(me),
38        }
39    }
40}
41#[derive(Debug)]
42/// A packbits command, also called the flag-counter byte, specifying how the next few bytes in a stream will be treated
43pub enum Command {
44    /// Escape code, next byte will be emitted literally
45    Escape,
46    /// Copy the next `self.0` bytes verbatim to output
47    Literal(u8),
48    /// Repeat the next byte `self.0` times
49    Repeat(u16),
50}
51
52impl Command {
53    #[inline]
54    /// Produces a byte and returns the next decoder state ([`Operation`]) at the same time
55    pub fn execute<T: io::Read>(self, reader: &mut T) -> Result<(u8, Operation), OperationError> {
56        match self {
57            Command::Escape => {
58                let byte = Self::read_byte(reader)?;
59                Ok((byte, Operation::Literal(0)))
60            }
61            Command::Literal(count) => {
62                let literal = Self::read_byte(reader)?;
63                Ok((literal, Operation::Literal(count - 1)))
64            }
65            Command::Repeat(count) => {
66                let literal = Self::read_byte(reader)?;
67                Ok((literal, Operation::Repeat(literal, count - 1)))
68            }
69        }
70    }
71
72    #[inline]
73    fn read_byte<T: io::Read>(reader: &mut T) -> Result<u8, OperationError> {
74        let mut buf = [0u8];
75        match reader.read(&mut buf) {
76            Ok(0) => Err(OperationError::UnexpectedEof),
77            Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
78                Err(OperationError::UnexpectedEof)
79            }
80            Err(e) => Err(e)?,
81            Ok(_) => Ok(buf[0]),
82        }
83    }
84}
85
86impl From<i8> for Command {
87    #[inline]
88    fn from(val: i8) -> Self {
89        match val {
90            -128 => Command::Escape,
91            n if n < 0 => Command::Repeat((1 - n) as u16),
92            n => Command::Literal((1 + n) as u8),
93        }
94    }
95}
96
97impl From<u8> for Command {
98    #[inline]
99    fn from(val: u8) -> Self {
100        match val {
101            n if n < 128 => Command::Literal(1 + n),
102            128 => Command::Escape,
103            n => Command::Repeat(257 - n as u16),
104        }
105    }
106}
107
108#[derive(Debug)]
109/// Describes an unpacking operation, that can be fed additional data to recieved an output
110/// byte and the next operation
111pub enum Operation {
112    /// We're in the middle of returning literal bytes
113    Literal(u8),
114    /// The unpacker will emit `.1` more repetitions of byte `.0`
115    Repeat(u8, u16),
116}
117
118#[derive(Debug)]
119/// Describes an unpacking operation, that can be fed additional data to recieved an output
120/// byte and the next operation
121pub enum Operation16 {
122    /// We're in the middle of returning literal bytes
123    Literal(u8),
124    /// The unpacker will emit `.1` more repetitions of byte `.0`
125    Repeat(u16, u16),
126}
127
128#[derive(Debug, thiserror::Error)]
129/// Error for executing [`Operation`]s, on insufficient input it provides a [`Command`] to continue the
130/// operation when more data becomes available
131pub enum OperationError {
132    /// The input stream ended, before the operation could complete.
133    ///
134    /// If more data becomes available, the provided command can be used to continue unpacking
135    /// where we left off.
136    #[error("More input data is required to executed command")]
137    InsufficientInput(Command),
138
139    /// The input stream ended with no unfinished command, this could be a good place to stop
140    /// unpacking if enough input bytes have been read or enough output bytes provided.
141    #[error("More input data is required to continue")]
142    UnexpectedEof,
143
144    /// An operation like _read_ or _seek_ on the underlying underlying reader has failed.
145    #[error(transparent)]
146    Io(#[from] io::Error),
147}
148
149impl From<OperationError> for io::Error {
150    fn from(value: OperationError) -> Self {
151        match value {
152            OperationError::Io(error) => error,
153            other => io::Error::other(other),
154        }
155    }
156}
157
158impl Default for Operation {
159    fn default() -> Self {
160        Self::new()
161    }
162}
163
164impl Default for Operation16 {
165    fn default() -> Self {
166        Self::new()
167    }
168}
169impl Operation16 {
170    /// Create a new empty operation, advancing ([`Operation::advance`]) it will read an entire new operation from the
171    /// underlying reader.
172    pub fn new() -> Self {
173        Self::Literal(0)
174    }
175
176    #[inline]
177    fn read_byte<T: io::Read>(reader: &mut T) -> Result<u8, OperationError> {
178        let mut buf = [0u8];
179        match reader.read(&mut buf) {
180            Ok(0) => Err(OperationError::UnexpectedEof),
181            Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
182                Err(OperationError::UnexpectedEof)
183            }
184            Err(e) => Err(e)?,
185            Ok(_) => Ok(buf[0]),
186        }
187    }
188
189    #[inline]
190    fn read_word<T: io::Read>(reader: &mut T) -> Result<u16, OperationError> {
191        let mut buf = [0u8, 0u8];
192        match reader.read(&mut buf) {
193            Ok(0) => Err(OperationError::UnexpectedEof),
194            Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
195                Err(OperationError::UnexpectedEof)
196            }
197            Err(e) => Err(e)?,
198            Ok(_) => Ok(((buf[0] as u16) << 8) | buf[1] as u16),
199        }
200    }
201
202    #[inline]
203    /// Produce a byte and return next state of the decoder at the same time
204    ///
205    /// If `self` was already completed, this function will try to fetch the next command from the underlying
206    /// reader. Otherwise it will just perform the repetition, or read the next literal.
207    pub fn advance<T: io::Read>(&self, reader: &mut T) -> Result<(u16, Self), OperationError> {
208        match self {
209            op if op.is_completed() => match Self::read_byte(reader)? {
210                128 => match Self::read_byte(reader) {
211                    Ok(byte) => Ok((
212                        (byte as u16) << 8 | (Self::read_byte(reader)? as u16),
213                        Operation16::Literal(0),
214                    )),
215                    Err(OperationError::UnexpectedEof) => {
216                        Err(OperationError::InsufficientInput(Command::Escape))
217                    }
218                    Err(e) => Err(e),
219                },
220                n if n < 128 => match Self::read_word(reader) {
221                    Ok(byte) => Ok((byte, Operation16::Literal(n))),
222                    Err(OperationError::UnexpectedEof) => {
223                        Err(OperationError::InsufficientInput(Command::Literal(n + 1)))
224                    }
225                    Err(e) => Err(e),
226                },
227                n => match Self::read_word(reader) {
228                    Err(OperationError::UnexpectedEof) => Err(OperationError::InsufficientInput(
229                        Command::Repeat(256 - n as u16 + 1),
230                    )),
231                    Ok(byte) => Ok((byte, Operation16::Repeat(byte, 256 - n as u16))),
232                    Err(e) => Err(e),
233                },
234            },
235            Operation16::Repeat(value, count) => {
236                Ok((*value, Operation16::Repeat(*value, count - 1)))
237            }
238            Operation16::Literal(count) => match Self::read_word(reader) {
239                Ok(byte) => Ok((byte, Self::Literal(count - 1))),
240                Err(OperationError::UnexpectedEof) => {
241                    Err(OperationError::InsufficientInput(Command::Literal(*count)))
242                }
243                Err(e) => Err(e),
244            },
245        }
246    }
247
248    #[inline]
249    /// Determines if the current operation has been advanced to completion.
250    pub fn is_completed(&self) -> bool {
251        matches!(self, Self::Literal(0) | Self::Repeat(_, 0))
252    }
253}
254
255impl Operation {
256    /// Create a new empty operation, advancing ([`Operation::advance`]) it will read an entire new operation from the
257    /// underlying reader.
258    pub fn new() -> Self {
259        Self::Literal(0)
260    }
261
262    #[inline]
263    fn read_byte<T: io::Read>(reader: &mut T) -> Result<u8, OperationError> {
264        let mut buf = [0u8];
265        match reader.read(&mut buf) {
266            Ok(0) => Err(OperationError::UnexpectedEof),
267            Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
268                Err(OperationError::UnexpectedEof)
269            }
270            Err(e) => Err(e)?,
271            Ok(_) => Ok(buf[0]),
272        }
273    }
274
275    #[inline]
276    /// Produce a byte and return next state of the decoder at the same time
277    ///
278    /// If `self` was already completed, this function will try to fetch the next command from the underlying
279    /// reader. Otherwise it will just perform the repetition, or read the next literal.
280    pub fn advance<T: io::Read>(&self, reader: &mut T) -> Result<(u8, Self), OperationError> {
281        match self {
282            op if op.is_completed() => match Self::read_byte(reader)? {
283                128 => match Self::read_byte(reader) {
284                    Ok(byte) => Ok((byte, Operation::Literal(0))),
285                    Err(OperationError::UnexpectedEof) => {
286                        Err(OperationError::InsufficientInput(Command::Escape))
287                    }
288                    Err(e) => Err(e),
289                },
290                n if n < 128 => match Self::read_byte(reader) {
291                    Ok(byte) => Ok((byte, Operation::Literal(n))),
292                    Err(OperationError::UnexpectedEof) => {
293                        Err(OperationError::InsufficientInput(Command::Literal(n + 1)))
294                    }
295                    Err(e) => Err(e),
296                },
297                n => match Self::read_byte(reader) {
298                    Err(OperationError::UnexpectedEof) => Err(OperationError::InsufficientInput(
299                        Command::Repeat(256 - n as u16 + 1),
300                    )),
301                    Ok(byte) => Ok((byte, Operation::Repeat(byte, 256 - n as u16))),
302                    Err(e) => Err(e),
303                },
304            },
305            Operation::Repeat(value, count) => Ok((*value, Operation::Repeat(*value, count - 1))),
306            Operation::Literal(count) => match Self::read_byte(reader) {
307                Ok(byte) => Ok((byte, Self::Literal(count - 1))),
308                Err(OperationError::UnexpectedEof) => {
309                    Err(OperationError::InsufficientInput(Command::Literal(*count)))
310                }
311                Err(e) => Err(e),
312            },
313        }
314    }
315
316    #[inline]
317    /// Determines if the current operation has been advanced to completion.
318    pub fn is_completed(&self) -> bool {
319        matches!(self, Self::Literal(0) | Self::Repeat(_, 0))
320    }
321}
322
323#[cfg(test)]
324mod operation {
325    use crate::{Command, Operation, OperationError};
326    use std::io;
327
328    #[test]
329    fn read_literal() {
330        let mut reader = io::Cursor::new(b"\x01\xAB\xBC");
331        assert!(matches!(
332            Operation::default().advance(&mut reader),
333            Ok((0xab, Operation::Literal(1)))
334        ));
335    }
336
337    #[test]
338    fn read_repeat() {
339        let mut reader = io::Cursor::new(b"\xFF\xAB");
340        assert!(matches!(
341            Operation::default().advance(&mut reader),
342            Ok((0xab, Operation::Repeat(0xab, 1)))
343        ));
344    }
345
346    #[test]
347    fn read_escape() {
348        let mut reader = io::Cursor::new(b"\x80\xAB");
349        assert!(matches!(
350            Operation::default().advance(&mut reader),
351            Ok((0xAB, Operation::Repeat(_, 0) | Operation::Literal(0)))
352        ));
353    }
354
355    #[test]
356    fn read_partial_literal() {
357        let mut reader = io::Cursor::new(b"\x01");
358        assert!(matches!(
359            Operation::default().advance(&mut reader),
360            Err(OperationError::InsufficientInput(Command::Literal(2)))
361        ));
362    }
363
364    #[test]
365    fn read_partial_literal_to_completion() {
366        let mut reader = io::Cursor::new(b"\xAB");
367        assert!(matches!(
368            Command::Literal(2).execute(&mut reader),
369            Ok((0xab, Operation::Literal(1)))
370        ));
371    }
372
373    #[test]
374    fn read_partial_repeat() {
375        let mut reader = io::Cursor::new(b"\xFF");
376        assert!(matches!(
377            Operation::default().advance(&mut reader),
378            Err(OperationError::InsufficientInput(Command::Repeat(2)))
379        ));
380    }
381
382    #[test]
383    fn read_partial_repeat_to_completion() {
384        let mut reader = io::Cursor::new(b"\xAB");
385        assert!(matches!(
386            Command::Repeat(2).execute(&mut reader),
387            Ok((0xab, Operation::Repeat(0xab, 1)))
388        ));
389    }
390
391    #[test]
392    fn read_partial_escape() {
393        let mut reader = io::Cursor::new(b"\x80");
394        assert!(matches!(
395            Operation::default().advance(&mut reader),
396            Err(OperationError::InsufficientInput(Command::Escape))
397        ));
398    }
399
400    #[test]
401    fn read_partial_escape_to_completion() {
402        let mut reader = io::Cursor::new(b"\x80");
403        assert!(matches!(
404            Command::Escape.execute(&mut reader),
405            Ok((0x80, Operation::Literal(0) | Operation::Repeat(_, 0)))
406        ));
407    }
408}
409
410pub fn unpack_words_exact(input: &[u8], count: usize) -> Result<Vec<u8>, Error> {
411    let mut output = Vec::with_capacity(count);
412    let mut remaining_output = count;
413    let mut i = 0;
414
415    loop {
416        if remaining_output == 0 {
417            return if i == input.len() {
418                Ok(output)
419            } else {
420                Err(Error::TooMuchInputData)
421            };
422        }
423
424        if i == input.len() {
425            return Err(Error::NotEnoughInputData);
426        }
427
428        i = match input[i].into() {
429            Command::Escape => i + 1,
430            Command::Literal(count) => {
431                if input.len() < i + count as usize {
432                    return Err(Error::NotEnoughInputData);
433                }
434
435                if count as usize > remaining_output {
436                    return Err(Error::TooMuchOutputData);
437                }
438
439                output.extend(&input[i + 1..(i + 1 + (count as usize * 2))]);
440                remaining_output -= count as usize * 2;
441                i + count as usize * 2 + 1
442            }
443            Command::Repeat(count) => {
444                if input.len() < i + 2 {
445                    return Err(Error::NotEnoughInputData);
446                }
447
448                if count as usize * 2 > remaining_output {
449                    return Err(Error::TooMuchOutputData);
450                }
451
452                for _ in 0..(count as usize) {
453                    output.extend(&input[(i + 1)..=(i + 2)]);
454                }
455
456                remaining_output -= count as usize * 2;
457                i + 3
458            }
459        }
460    }
461}
462
463/// Unpack `input` into exactly `count` bytes
464pub fn unpack_exact(input: &[u8], count: usize) -> Result<Vec<u8>, Error> {
465    let mut output = Vec::with_capacity(count);
466    let mut remaining_output = count;
467    let mut i = 0;
468
469    loop {
470        if remaining_output == 0 {
471            return if i == input.len() {
472                Ok(output)
473            } else {
474                Err(Error::TooMuchInputData)
475            };
476        }
477
478        if i == input.len() {
479            return Err(Error::NotEnoughInputData);
480        }
481
482        i = match input[i].into() {
483            Command::Escape => i + 1,
484            Command::Literal(count) => {
485                if input.len() < i + count as usize {
486                    return Err(Error::NotEnoughInputData);
487                }
488
489                if count as usize > remaining_output {
490                    return Err(Error::TooMuchOutputData);
491                }
492
493                output.extend(&input[i + 1..(i + 1 + (count as usize))]);
494                remaining_output -= count as usize;
495                i + count as usize + 1
496            }
497            Command::Repeat(count) => {
498                if input.len() < i + 1 {
499                    return Err(Error::NotEnoughInputData);
500                }
501
502                if count as usize > remaining_output {
503                    return Err(Error::TooMuchOutputData);
504                }
505
506                output.extend(iter::repeat_n(input[i + 1], count as usize));
507                remaining_output -= count as usize;
508                i + 2
509            }
510        }
511    }
512}
513
514/// Unpack all data from `buffer` into a newly allocated vector
515pub fn unpack_buf(buffer: &[u8]) -> io::Result<Vec<u8>> {
516    unpack(io::Cursor::new(buffer))
517}
518
519/// Unpack all data from `reader` into a newly allocated vector
520pub fn unpack<R: io::Read>(mut reader: R) -> io::Result<Vec<u8>> {
521    let mut output = Vec::new();
522    let mut buf = [0u8];
523    loop {
524        let command = match reader.read_exact(&mut buf) {
525            Ok(()) => buf[0].into(),
526            Err(e) if e.kind() == ErrorKind::UnexpectedEof => return Ok(output),
527            Err(e) => return Err(e)?,
528        };
529
530        match command {
531            Command::Escape => {
532                reader.read_exact(&mut buf)?;
533                output.push(buf[0]);
534            }
535            Command::Literal(count) => {
536                let mut buffer = vec![0u8; count as usize];
537                reader.read_exact(&mut buffer)?;
538                output.append(&mut buffer);
539            }
540            Command::Repeat(count) => {
541                reader.read_exact(&mut buf)?;
542                output.reserve(count as usize);
543                for _ in 0..count {
544                    output.push(buf[0]);
545                }
546            }
547        }
548    }
549}
550
551/// Extension for [`std::io::Read`]ers to unpack _PackBits_ data
552pub trait PackBitsReaderExt {
553    /// Unpack PackBit data into the buffer, returning the number of bytes written to the buffer
554    fn read_packbits(&mut self, target: &mut [u8]) -> io::Result<usize>;
555    fn read_packbits_words(&mut self, target: &mut [u8]) -> io::Result<usize>;
556}
557
558impl<T: io::Read> PackBitsReaderExt for T {
559    fn read_packbits(&mut self, target: &mut [u8]) -> io::Result<usize> {
560        let mut op = Operation::default();
561        for (idx, byte) in target.iter_mut().enumerate() {
562            match op.advance(self) {
563                Err(OperationError::InsufficientInput(_)) => {
564                    // TODO: We've read a command that can't be completed, this should be
565                    // communicated to users
566                    return Ok(idx);
567                }
568                Err(OperationError::UnexpectedEof) => return Ok(idx),
569                Err(other) => return Err(other)?,
570                Ok((value, next)) => {
571                    *byte = value;
572                    op = next;
573                }
574            }
575        }
576
577        Ok(target.len())
578    }
579
580    fn read_packbits_words(&mut self, target: &mut [u8]) -> io::Result<usize> {
581        let mut op = Operation16::default();
582        for (idx, [byte1, byte2]) in target.iter_mut().array_chunks().enumerate() {
583            match op.advance(self) {
584                Err(OperationError::InsufficientInput(_)) => {
585                    // TODO: We've read a command that can't be completed, this should be
586                    // communicated to users
587                    return Ok(idx * 2);
588                }
589                Err(OperationError::UnexpectedEof) => return Ok(idx * 2),
590                Err(other) => return Err(other)?,
591                Ok((value, next)) => {
592                    *byte1 = (value >> 8) as u8;
593                    *byte2 = (value & 0xFF) as u8;
594                    op = next;
595                }
596            }
597        }
598
599        Ok(target.len())
600    }
601}
602
603#[cfg(test)]
604mod test {
605    use crate::{Error, unpack_buf};
606
607    use super::{unpack, unpack_exact};
608
609    #[test]
610    fn canonical_example() {
611        let input = b"\xFE\xAA\x02\x80\x00\x2A\xFD\xAA\x03\x80\x00\x2A\x22\xF7\xAA";
612        let unpacked = b"\xAA\xAA\xAA\x80\x00\x2A\xAA\xAA\xAA\xAA\x80\x00\x2A\x22\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA";
613
614        assert_eq!(unpack(input.as_slice()).unwrap(), unpacked);
615    }
616
617    #[test]
618    fn test_simple_buffer_expansion() {
619        let input = b"\xFE\xAA\x02\x80\x00\x2A\xFD\xAA\x03\x80\x00\x2A\x22\xF7\xAA";
620        let expectation = b"\xAA\xAA\xAA\x80\x00\x2A\xAA\xAA\xAA\xAA\x80\x00\x2A\x22\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA";
621        let result = unpack_buf(input).unwrap();
622        assert_eq!(expectation.to_vec(), result);
623
624        let result = unpack_exact(input, 24);
625        assert_eq!(expectation.to_vec(), result.unwrap());
626    }
627
628    //#[test]
629    //fn test_clean_maximum_output() {
630    //let input = b"\xFE\xAA\x02\x80\x00\x2A\xFD\xAA\x03\x80\x00\x2A\x22\xF7\xAA\xF7\xAA";
631    //let expectation = b"\xAA\xAA\xAA\x80\x00\x2A\xAA\xAA\xAA\xAA\x80\x00\x2A\x22\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA";
632
633    //let result = unpack_until(input, 24);
634    //assert_eq!((expectation.to_vec(), 15), result.unwrap());
635
636    //let input = b"";
637    //let result = unpack_until(input, 0);
638    //assert_eq!((Vec::<u8>::new(), 0), result.unwrap());
639    //}
640
641    #[test]
642    fn test_too_much_output() {
643        let input = b"\xFE\xAA\x02\x80\x00\x2A\xFD\xAA\x03\x80\x00\x2A\x22\xF7\xAA";
644
645        let result = unpack_exact(input, 20);
646        assert!(result.is_err_and(|e| matches!(e, Error::TooMuchOutputData)));
647    }
648
649    #[test]
650    fn test_not_enough_input() {
651        let input = b"\xFE\xAA\x02\x80\x00\x2A\xFD\xAA\x03\x80\x00\x2A\x22\xF7\xAA";
652
653        let result = unpack_exact(input, 26);
654        assert!(result.is_err_and(|e| matches!(e, Error::NotEnoughInputData)));
655
656        let input = b"";
657        let result = unpack_exact(input, 1);
658        assert!(result.is_err_and(|e| matches!(e, Error::NotEnoughInputData)));
659    }
660
661    mod operation {
662        use crate::{Command, Operation, OperationError};
663        use std::io;
664
665        #[test]
666        fn read_literal() {
667            let mut reader = io::Cursor::new(b"\x01\xAB\xBC");
668            assert!(matches!(
669                Operation::default().advance(&mut reader),
670                Ok((0xab, Operation::Literal(1)))
671            ));
672        }
673
674        #[test]
675        fn read_repeat() {
676            let mut reader = io::Cursor::new(b"\xFF\xAB");
677            assert!(matches!(
678                Operation::default().advance(&mut reader),
679                Ok((0xab, Operation::Repeat(0xab, 1)))
680            ));
681        }
682
683        #[test]
684        fn read_escape() {
685            let mut reader = io::Cursor::new(b"\x80\xAB");
686            assert!(matches!(
687                Operation::default().advance(&mut reader),
688                Ok((0xAB, Operation::Repeat(_, 0) | Operation::Literal(0)))
689            ));
690        }
691
692        #[test]
693        fn read_partial_literal() {
694            let mut reader = io::Cursor::new(b"\x01");
695            assert!(matches!(
696                Operation::default().advance(&mut reader),
697                Err(OperationError::InsufficientInput(Command::Literal(2)))
698            ));
699        }
700
701        #[test]
702        fn read_partial_literal_to_completion() {
703            let mut reader = io::Cursor::new(b"\xAB");
704            assert!(matches!(
705                Command::Literal(2).execute(&mut reader),
706                Ok((0xab, Operation::Literal(1)))
707            ));
708        }
709
710        #[test]
711        fn read_partial_repeat() {
712            let mut reader = io::Cursor::new(b"\xFF");
713            assert!(matches!(
714                Operation::default().advance(&mut reader),
715                Err(OperationError::InsufficientInput(Command::Repeat(2)))
716            ));
717        }
718
719        #[test]
720        fn read_partial_repeat_to_completion() {
721            let mut reader = io::Cursor::new(b"\xAB");
722            assert!(matches!(
723                Command::Repeat(2).execute(&mut reader),
724                Ok((0xab, Operation::Repeat(0xab, 1)))
725            ));
726        }
727
728        #[test]
729        fn read_partial_escape() {
730            let mut reader = io::Cursor::new(b"\x80");
731            assert!(matches!(
732                Operation::default().advance(&mut reader),
733                Err(OperationError::InsufficientInput(Command::Escape))
734            ));
735        }
736
737        #[test]
738        fn read_partial_escape_to_completion() {
739            let mut reader = io::Cursor::new(b"\x80");
740            assert!(matches!(
741                Command::Escape.execute(&mut reader),
742                Ok((0x80, Operation::Literal(0) | Operation::Repeat(_, 0)))
743            ));
744        }
745    }
746}