1pub mod ascii85 {
25 use crate::error::DecodeError;
28
29 pub fn encode(input: &[u8]) -> Vec<u8> {
38 if input.is_empty() {
39 return Vec::new();
40 }
41
42 let estimated = (input.len() / 4 + 1) * 5 + input.len() / 30 + 4;
44 let mut output = Vec::with_capacity(estimated);
45 let mut line_length = 0usize;
46 let mut pos = 0usize;
47
48 while pos + 4 <= input.len() {
50 let val =
51 u32::from_be_bytes([input[pos], input[pos + 1], input[pos + 2], input[pos + 3]]);
52 pos += 4;
53
54 if val == 0 {
55 output.push(b'z');
57 line_length += 1;
58 } else {
59 let mut v = val as u64;
60 let mut chars = [0u8; 5];
61 for c in chars.iter_mut().rev() {
62 *c = (v % 85) as u8 + 33;
63 v /= 85;
64 }
65 output.extend_from_slice(&chars);
66 line_length += 5;
67 }
68
69 if line_length >= 75 {
70 output.extend_from_slice(b"\r\n");
71 line_length = 0;
72 }
73 }
74
75 if pos < input.len() {
77 let count = input.len() - pos;
78 let mut val = 0u32;
79 for k in 0..count {
80 val |= u32::from(input[pos + k]) << (8 * (3 - k));
81 }
82 let mut v = val as u64;
83 let mut chars = [0u8; 5];
84 for i in (0..5usize).rev() {
87 if i <= count {
88 chars[i] = (v % 85) as u8 + 33;
89 }
90 v /= 85;
91 }
92 output.extend_from_slice(&chars[..count + 1]);
93 }
94
95 output.extend_from_slice(b"~>");
96 output
97 }
98
99 pub fn decode(input: &[u8]) -> Result<Vec<u8>, DecodeError> {
107 let mut output = Vec::with_capacity(input.len() * 4 / 5);
108 let mut group = [0u8; 5];
109 let mut count = 0usize;
110
111 let mut i = 0;
112 while i < input.len() {
113 let b = input[i];
114 i += 1;
115
116 if b == b' ' || b == b'\t' || b == b'\n' || b == b'\r' || b == b'\x0C' {
118 continue;
119 }
120
121 if b == b'~' {
123 if i < input.len() && input[i] == b'>' {
124 break; }
126 break; }
128
129 if b == b'z' {
131 if count != 0 {
132 return Err(DecodeError::InvalidInput(
133 "ASCII85: 'z' inside a group".into(),
134 ));
135 }
136 output.extend_from_slice(&[0, 0, 0, 0]);
137 continue;
138 }
139
140 if !(b'!'..=b'u').contains(&b) {
142 return Err(DecodeError::InvalidInput(format!(
143 "ASCII85: invalid character 0x{b:02X}"
144 )));
145 }
146
147 group[count] = b - b'!';
148 count += 1;
149
150 if count == 5 {
151 let value = u64::from(group[0]) * 85 * 85 * 85 * 85
152 + u64::from(group[1]) * 85 * 85 * 85
153 + u64::from(group[2]) * 85 * 85
154 + u64::from(group[3]) * 85
155 + u64::from(group[4]);
156
157 if value > u64::from(u32::MAX) {
158 return Err(DecodeError::InvalidInput(
159 "ASCII85: group value exceeds 2^32-1".into(),
160 ));
161 }
162
163 let value = value as u32;
164 output.push((value >> 24) as u8);
165 output.push((value >> 16) as u8);
166 output.push((value >> 8) as u8);
167 output.push(value as u8);
168 count = 0;
169 }
170 }
171
172 if count > 0 {
174 if count == 1 {
175 return Err(DecodeError::InvalidInput(
176 "ASCII85: single trailing character is invalid".into(),
177 ));
178 }
179
180 for slot in group.iter_mut().skip(count) {
182 *slot = 84; }
184
185 let value = u64::from(group[0]) * 85 * 85 * 85 * 85
186 + u64::from(group[1]) * 85 * 85 * 85
187 + u64::from(group[2]) * 85 * 85
188 + u64::from(group[3]) * 85
189 + u64::from(group[4]);
190
191 if value > u64::from(u32::MAX) {
192 return Err(DecodeError::InvalidInput(
193 "ASCII85: padded group value exceeds 2^32-1".into(),
194 ));
195 }
196
197 let value = value as u32;
198 let bytes = value.to_be_bytes();
199 output.extend_from_slice(&bytes[..count - 1]);
200 }
201
202 Ok(output)
203 }
204
205 #[cfg(test)]
206 mod tests {
207 use super::*;
208
209 #[test]
212 fn test_encode_empty() {
213 assert!(encode(&[]).is_empty());
214 }
215
216 #[test]
217 fn test_encode_basic() {
218 assert_eq!(encode(b"Man "), b"9jqo^~>");
219 }
220
221 #[test]
222 fn test_encode_all_zeros() {
223 assert_eq!(encode(&[0, 0, 0, 0]), b"z~>");
224 }
225
226 #[test]
227 fn test_encode_partial_group() {
228 let result = encode(b"a");
229 assert!(result.ends_with(b"~>"));
230 assert_eq!(result.len(), 4); }
232
233 #[test]
234 fn test_encode_decode_roundtrip() {
235 let original = b"Hello, World! This is a test of ASCII85.";
236 let decoded = decode(&encode(original)).unwrap();
237 assert_eq!(decoded, original);
238 }
239
240 #[test]
241 fn test_encode_decode_roundtrip_all_bytes() {
242 let original: Vec<u8> = (0u8..=255).collect();
243 assert_eq!(decode(&encode(&original)).unwrap(), original);
244 }
245
246 #[test]
247 fn test_encode_line_break_at_75() {
248 let input = vec![0xABu8; 80];
249 let encoded = encode(&input);
250 assert!(encoded.windows(2).any(|w| w == b"\r\n"));
251 }
252
253 #[test]
256 fn test_decode_basic() {
257 assert_eq!(decode(b"9jqo^~>").unwrap(), b"Man ");
258 }
259
260 #[test]
261 fn test_decode_z_shortcut() {
262 assert_eq!(decode(b"z~>").unwrap(), vec![0, 0, 0, 0]);
263 }
264
265 #[test]
266 fn test_decode_z_shortcut_multiple() {
267 assert_eq!(decode(b"zz~>").unwrap(), vec![0u8; 8]);
268 }
269
270 #[test]
271 fn test_decode_whitespace_ignored() {
272 assert_eq!(decode(b"9 jqo ^\n~>").unwrap(), b"Man ");
273 }
274
275 #[test]
276 fn test_decode_empty() {
277 assert!(decode(b"~>").unwrap().is_empty());
278 }
279
280 #[test]
281 fn test_decode_partial_group() {
282 let result = decode(b"9jqo^BlbD~>").unwrap();
283 assert_eq!(&result[..4], b"Man ");
284 assert_eq!(result.len(), 7);
285 }
286
287 #[test]
288 fn test_decode_single_trailing_char_invalid() {
289 assert!(decode(b"A~>").is_err());
290 }
291
292 #[test]
293 fn test_decode_invalid_char() {
294 assert!(decode(b"9jqo^{~>").is_err());
295 }
296
297 #[test]
298 fn test_decode_z_inside_group_error() {
299 assert!(decode(b"Az~>").is_err());
300 }
301
302 #[test]
303 fn test_decode_no_eod_marker() {
304 assert_eq!(decode(b"9jqo^").unwrap(), b"Man ");
305 }
306
307 #[test]
308 fn test_decode_known_string() {
309 assert_eq!(decode(b"87cURDe~>").unwrap(), b"Hello");
310 }
311 }
312}
313
314pub mod ascii_hex {
319 use crate::error::DecodeError;
325
326 pub fn decode(input: &[u8]) -> Result<Vec<u8>, DecodeError> {
333 let mut output = Vec::with_capacity(input.len() / 2);
334 let mut high_nibble: Option<u8> = None;
335
336 for &b in input {
337 if b == b'>' {
338 break;
339 }
340 if b == b' ' || b == b'\t' || b == b'\n' || b == b'\r' || b == b'\x0C' {
341 continue;
342 }
343
344 let nibble = hex_nibble(b)?;
345 match high_nibble.take() {
346 None => high_nibble = Some(nibble),
347 Some(high) => output.push((high << 4) | nibble),
348 }
349 }
350
351 if let Some(high) = high_nibble {
353 output.push(high << 4);
354 }
355
356 Ok(output)
357 }
358
359 fn hex_nibble(b: u8) -> Result<u8, crate::error::DecodeError> {
360 match b {
361 b'0'..=b'9' => Ok(b - b'0'),
362 b'a'..=b'f' => Ok(b - b'a' + 10),
363 b'A'..=b'F' => Ok(b - b'A' + 10),
364 _ => Err(crate::error::DecodeError::InvalidInput(format!(
365 "ASCIIHex: invalid hex character 0x{b:02X}"
366 ))),
367 }
368 }
369
370 #[cfg(test)]
371 mod tests {
372 use super::*;
373
374 #[test]
375 fn test_decode_basic() {
376 assert_eq!(decode(b"48656C6C6F>").unwrap(), b"Hello");
377 }
378
379 #[test]
380 fn test_decode_lowercase() {
381 assert_eq!(decode(b"48656c6c6f>").unwrap(), b"Hello");
382 }
383
384 #[test]
385 fn test_decode_whitespace_ignored() {
386 assert_eq!(decode(b"48 65 6C\n6C 6F>").unwrap(), b"Hello");
387 }
388
389 #[test]
390 fn test_decode_odd_nibble() {
391 assert_eq!(decode(b"A>").unwrap(), vec![0xA0]);
392 }
393
394 #[test]
395 fn test_decode_empty() {
396 assert!(decode(b">").unwrap().is_empty());
397 }
398
399 #[test]
400 fn test_decode_no_eod_marker() {
401 assert_eq!(decode(b"4865").unwrap(), b"He");
402 }
403
404 #[test]
405 fn test_decode_invalid_char() {
406 assert!(decode(b"4G>").is_err());
407 }
408
409 #[test]
410 fn test_decode_all_zeros() {
411 assert_eq!(decode(b"0000>").unwrap(), vec![0, 0]);
412 }
413
414 #[test]
415 fn test_decode_all_ff() {
416 assert_eq!(decode(b"FFFF>").unwrap(), vec![0xFF, 0xFF]);
417 }
418
419 #[test]
425 fn test_parser_hex_decode_empty() {
426 assert!(decode(b"").unwrap().is_empty());
427 }
428
429 #[test]
431 fn test_parser_hex_decode_empty_content() {
432 assert!(decode(b">").unwrap().is_empty());
433 }
434
435 #[test]
437 fn test_parser_hex_decode_only_whitespace() {
438 assert!(decode(b"\t \r\n>").unwrap().is_empty());
439 }
440
441 #[test]
443 fn test_parser_hex_decode_regular() {
444 assert_eq!(decode(b"12Ac>zzz").unwrap(), vec![0x12, 0xAC]);
445 }
446
447 #[test]
449 fn test_parser_hex_decode_skip_whitespace() {
450 assert_eq!(
451 decode(b"12 Ac\t02\r\nBF>zzz>").unwrap(),
452 vec![0x12, 0xAC, 0x02, 0xBF]
453 );
454 }
455
456 #[test]
458 fn test_parser_hex_decode_non_multiple() {
459 assert_eq!(decode(b"12A>zzz").unwrap(), vec![0x12, 0xA0]);
460 }
461
462 #[test]
464 fn test_parser_hex_decode_no_ending_mark() {
465 assert_eq!(
466 decode(b"12AcED3c3456").unwrap(),
467 vec![0x12, 0xAC, 0xED, 0x3C, 0x34, 0x56]
468 );
469 }
470 }
471}
472
473pub mod run_length {
478 use crate::error::DecodeError;
485 use crate::scanline::ScanlineDecoder;
486
487 pub fn decode(input: &[u8]) -> Result<Vec<u8>, DecodeError> {
497 let mut output = Vec::new();
498 let mut i = 0;
499
500 while i < input.len() {
501 let length = input[i];
502 i += 1;
503
504 if length == 128 {
505 break; }
507
508 if length <= 127 {
509 let count = usize::from(length) + 1;
510 if i + count > input.len() {
511 return Err(DecodeError::InvalidInput(
512 "RunLength: literal run extends past end of input".into(),
513 ));
514 }
515 output.extend_from_slice(&input[i..i + count]);
516 i += count;
517 } else {
518 if i >= input.len() {
519 return Err(DecodeError::InvalidInput(
520 "RunLength: repeat run missing data byte".into(),
521 ));
522 }
523 let count = 257 - usize::from(length);
524 let byte = input[i];
525 i += 1;
526 output.resize(output.len() + count, byte);
527 }
528 }
529
530 Ok(output)
531 }
532
533 pub fn encode(input: &[u8]) -> Vec<u8> {
545 if input.is_empty() {
546 return vec![];
547 }
548 if input.len() == 1 {
549 return vec![0, input[0], 128];
550 }
551
552 let estimated = input.len().div_ceil(3) * 4 + 1;
554 let mut result = vec![0u8; estimated];
555 let mut wpos = 0usize;
556
557 let mut run_start = 0usize;
558 let mut run_end = 1usize;
559 let mut x = input[run_start];
560 let mut y = input[run_end];
561
562 while run_end < input.len() {
563 let max_len = 128usize.min(input.len() - run_start);
564
565 while x == y && run_end - run_start < max_len - 1 {
566 run_end += 1;
567 y = input[run_end];
568 }
569
570 if x == y {
571 run_end += 1;
572 if run_end < input.len() {
573 y = input[run_end];
574 }
575 }
576
577 if run_end - run_start > 1 {
578 result[wpos] = (257 - (run_end - run_start)) as u8;
579 result[wpos + 1] = x;
580 wpos += 2;
581 x = y;
582 run_start = run_end;
583 run_end += 1;
584 if run_end < input.len() {
585 y = input[run_end];
586 }
587 continue;
588 }
589
590 while x != y && run_end <= run_start + max_len {
591 result[wpos + (run_end - run_start)] = x;
592 x = y;
593 run_end += 1;
594 if run_end == input.len() {
595 if run_end <= run_start + max_len {
596 result[wpos + (run_end - run_start)] = x;
597 run_end += 1;
598 }
599 break;
600 }
601 y = input[run_end];
602 }
603 result[wpos] = (run_end - run_start - 2) as u8;
604 wpos += run_end - run_start;
605 run_start = run_end - 1;
606 }
607
608 if run_start < input.len() {
609 result[wpos] = 0;
610 result[wpos + 1] = x;
611 wpos += 2;
612 }
613
614 result[wpos] = 128; result.truncate(wpos + 1);
616 result
617 }
618
619 #[derive(Clone, Copy)]
625 enum RunOp {
626 Literal { remaining: usize },
627 Repeat { remaining: usize, byte: u8 },
628 Eod,
629 Init,
630 }
631
632 pub struct RunLengthScanlineDecoder {
639 src: Vec<u8>,
640 width: u32,
641 height: u32,
642 comps: u8,
643 bpc: u8,
644 row_stride: usize,
645 scanline: Vec<u8>,
646 src_offset: usize,
647 op: RunOp,
648 lines_decoded: usize,
649 }
650
651 pub fn create_decoder(
658 src: &[u8],
659 width: u32,
660 height: u32,
661 comps: u8,
662 bpc: u8,
663 ) -> Result<RunLengthScanlineDecoder, DecodeError> {
664 let row_stride = (width as usize * comps as usize * bpc as usize).div_ceil(8);
665 let decoder = RunLengthScanlineDecoder {
666 src: src.to_vec(),
667 width,
668 height,
669 comps,
670 bpc,
671 row_stride,
672 scanline: vec![0u8; row_stride],
673 src_offset: 0,
674 op: RunOp::Init,
675 lines_decoded: 0,
676 };
677 if !decoder.check_dest_size() {
678 return Err(DecodeError::InvalidInput(
679 "RunLength: compressed data too small for image dimensions".into(),
680 ));
681 }
682 Ok(decoder)
683 }
684
685 impl RunLengthScanlineDecoder {
686 fn check_dest_size(&self) -> bool {
689 let mut i = 0usize;
690 let mut dest: u64 = 0;
691 while i < self.src.len() {
692 let b = self.src[i];
693 if b < 128 {
694 dest += b as u64 + 1;
695 i += b as usize + 2;
696 } else if b > 128 {
697 dest += 257 - b as u64;
698 i += 2;
699 } else {
700 break; }
702 }
703 let required =
704 self.width as u64 * self.comps as u64 * self.bpc as u64 * self.height as u64;
705 dest * 8 >= required
706 }
707
708 fn read_next_op(&mut self) {
709 if self.src_offset >= self.src.len() {
710 self.op = RunOp::Eod;
711 return;
712 }
713 let b = self.src[self.src_offset];
714 self.src_offset += 1;
715 self.op = if b < 128 {
716 RunOp::Literal {
717 remaining: b as usize + 1,
718 }
719 } else if b > 128 {
720 let data_byte = if self.src_offset < self.src.len() {
721 self.src[self.src_offset]
722 } else {
723 0
724 };
725 RunOp::Repeat {
726 remaining: 257 - b as usize,
727 byte: data_byte,
728 }
729 } else {
730 RunOp::Eod
731 };
732 }
733
734 fn fill_scanline(&mut self) -> bool {
736 if matches!(self.op, RunOp::Init) {
737 self.read_next_op();
738 }
739 if matches!(self.op, RunOp::Eod) {
740 return false;
741 }
742
743 self.scanline.fill(0);
744 let mut col = 0usize;
745
746 loop {
747 let space = self.row_stride - col;
748 if space == 0 {
749 break;
750 }
751
752 match self.op {
753 RunOp::Literal { remaining } => {
754 let src_left = self.src.len().saturating_sub(self.src_offset);
755 let copy = remaining.min(space).min(src_left);
756 let src_end = self.src_offset + copy;
757 self.scanline[col..col + copy]
758 .copy_from_slice(&self.src[self.src_offset..src_end]);
759 col += copy;
760 self.src_offset += copy;
761 let new_remaining = remaining - copy;
762 if new_remaining == 0 {
763 self.read_next_op();
764 } else {
765 self.op = RunOp::Literal {
766 remaining: new_remaining,
767 };
768 break;
769 }
770 }
771 RunOp::Repeat { remaining, byte } => {
772 let copy = remaining.min(space);
773 self.scanline[col..col + copy].fill(byte);
774 col += copy;
775 let new_remaining = remaining - copy;
776 if new_remaining == 0 {
777 self.src_offset += 1;
778 self.read_next_op();
779 } else {
780 self.op = RunOp::Repeat {
781 remaining: new_remaining,
782 byte,
783 };
784 break;
785 }
786 }
787 RunOp::Eod | RunOp::Init => break,
788 }
789
790 if matches!(self.op, RunOp::Eod) {
791 break;
792 }
793 }
794
795 true
796 }
797 }
798
799 impl ScanlineDecoder for RunLengthScanlineDecoder {
800 fn width(&self) -> u32 {
801 self.width
802 }
803 fn height(&self) -> u32 {
804 self.height
805 }
806 fn comps_count(&self) -> u8 {
807 self.comps
808 }
809 fn bpc(&self) -> u8 {
810 self.bpc
811 }
812 fn row_stride(&self) -> usize {
813 self.row_stride
814 }
815
816 fn decode_scanline(&mut self) -> Result<Option<&[u8]>, DecodeError> {
817 if self.lines_decoded >= self.height as usize {
818 return Ok(None);
819 }
820 if !self.fill_scanline() {
821 return Ok(None);
822 }
823 self.lines_decoded += 1;
824 Ok(Some(&self.scanline))
825 }
826
827 fn reset(&mut self) -> Result<(), DecodeError> {
828 self.scanline.fill(0);
829 self.src_offset = 0;
830 self.op = RunOp::Init;
831 self.lines_decoded = 0;
832 Ok(())
833 }
834
835 fn current_line(&self) -> Option<usize> {
836 if self.lines_decoded == 0 {
837 None
838 } else {
839 Some(self.lines_decoded - 1)
840 }
841 }
842 }
843
844 #[cfg(test)]
845 mod tests {
846 use super::*;
847
848 #[test]
851 fn test_decode_literal_run() {
852 assert_eq!(decode(&[2, b'A', b'B', b'C', 128]).unwrap(), b"ABC");
853 }
854
855 #[test]
856 fn test_decode_repeat_run() {
857 assert_eq!(decode(&[253, b'X', 128]).unwrap(), b"XXXX");
858 }
859
860 #[test]
861 fn test_decode_mixed_runs() {
862 assert_eq!(decode(&[1, b'A', b'B', 254, b'Z', 128]).unwrap(), b"ABZZZ");
863 }
864
865 #[test]
866 fn test_decode_eod_marker() {
867 assert!(decode(&[128]).unwrap().is_empty());
868 }
869
870 #[test]
871 fn test_decode_empty_input() {
872 assert!(decode(&[]).unwrap().is_empty());
873 }
874
875 #[test]
876 fn test_decode_truncated_literal() {
877 assert!(decode(&[1, b'A']).is_err());
878 }
879
880 #[test]
881 fn test_decode_truncated_repeat() {
882 assert!(decode(&[255]).is_err());
883 }
884
885 #[test]
886 fn test_decode_single_literal() {
887 assert_eq!(decode(&[0, b'Q', 128]).unwrap(), b"Q");
888 }
889
890 #[test]
891 fn test_decode_max_repeat() {
892 let result = decode(&[129, b'Y', 128]).unwrap();
893 assert_eq!(result.len(), 128);
894 assert!(result.iter().all(|&b| b == b'Y'));
895 }
896
897 #[test]
900 fn test_encode_empty() {
901 assert!(encode(&[]).is_empty());
902 }
903
904 #[test]
905 fn test_encode_single_byte() {
906 assert_eq!(encode(&[b'A']), &[0, b'A', 128]);
907 }
908
909 #[test]
910 fn test_encode_eod_terminator() {
911 assert_eq!(*encode(b"Hello").last().unwrap(), 128);
912 }
913
914 #[test]
915 fn test_encode_decode_roundtrip_literal() {
916 let original = b"ABCDEFGH";
917 assert_eq!(decode(&encode(original)).unwrap(), original);
918 }
919
920 #[test]
921 fn test_encode_decode_roundtrip_repeated() {
922 let original = vec![b'X'; 64];
923 let encoded = encode(&original);
924 assert!(encoded.len() < original.len());
925 assert_eq!(decode(&encoded).unwrap(), original);
926 }
927
928 #[test]
929 fn test_encode_decode_roundtrip_all_bytes() {
930 let original: Vec<u8> = (0u8..=255).collect();
931 assert_eq!(decode(&encode(&original)).unwrap(), original);
932 }
933
934 #[test]
935 fn test_encode_max_repeat_128() {
936 let original = vec![b'Z'; 128];
937 assert_eq!(decode(&encode(&original)).unwrap(), original);
938 }
939
940 fn make_rl_image(rows: &[&[u8]]) -> Vec<u8> {
943 let mut encoded = Vec::new();
944 for row in rows {
945 for chunk in row.chunks(128) {
946 encoded.push((chunk.len() - 1) as u8);
947 encoded.extend_from_slice(chunk);
948 }
949 }
950 encoded.push(128);
951 encoded
952 }
953
954 #[test]
955 fn test_rl_scanline_basic() {
956 let src = make_rl_image(&[&[1u8, 2, 3], &[4u8, 5, 6]]);
957 let mut dec = create_decoder(&src, 3, 2, 1, 8).unwrap();
958
959 assert_eq!(dec.width(), 3);
960 assert_eq!(dec.height(), 2);
961 assert_eq!(dec.comps_count(), 1);
962 assert_eq!(dec.bpc(), 8);
963 assert_eq!(dec.row_stride(), 3);
964
965 assert_eq!(dec.decode_scanline().unwrap().unwrap(), &[1, 2, 3]);
966 assert_eq!(dec.current_line(), Some(0));
967 assert_eq!(dec.decode_scanline().unwrap().unwrap(), &[4, 5, 6]);
968 assert_eq!(dec.current_line(), Some(1));
969 assert!(dec.decode_scanline().unwrap().is_none());
970 }
971
972 #[test]
973 fn test_rl_scanline_repeat_run() {
974 let src = [253u8, b'A', 128];
975 let mut dec = create_decoder(&src, 4, 1, 1, 8).unwrap();
976 assert_eq!(
977 dec.decode_scanline().unwrap().unwrap(),
978 &[b'A', b'A', b'A', b'A']
979 );
980 assert!(dec.decode_scanline().unwrap().is_none());
981 }
982
983 #[test]
984 fn test_rl_scanline_reset() {
985 let src = make_rl_image(&[&[1u8, 2, 3, 4], &[1u8, 2, 3, 4]]);
986 let mut dec = create_decoder(&src, 4, 2, 1, 8).unwrap();
987 let first = dec.decode_scanline().unwrap().unwrap().to_vec();
988 dec.reset().unwrap();
989 assert_eq!(dec.current_line(), None);
990 assert_eq!(dec.decode_scanline().unwrap().unwrap(), first);
991 }
992
993 #[test]
994 fn test_rl_scanline_current_line_before_read() {
995 let src = make_rl_image(&[&[0u8, 0, 0]]);
996 assert_eq!(
997 create_decoder(&src, 3, 1, 1, 8).unwrap().current_line(),
998 None
999 );
1000 }
1001
1002 #[test]
1003 fn test_rl_scanline_too_small_returns_error() {
1004 let src = [0u8, 42, 128];
1005 assert!(create_decoder(&src, 2, 2, 1, 8).is_err());
1006 }
1007
1008 #[test]
1009 fn test_rl_scanline_run_spanning_rows() {
1010 let src = [251u8, b'X', 128]; let mut dec = create_decoder(&src, 3, 2, 1, 8).unwrap();
1012 assert_eq!(dec.decode_scanline().unwrap().unwrap(), &[b'X', b'X', b'X']);
1013 assert_eq!(dec.decode_scanline().unwrap().unwrap(), &[b'X', b'X', b'X']);
1014 assert!(dec.decode_scanline().unwrap().is_none());
1015 }
1016 }
1017}