1use crate::check::Check;
14use crate::error::{Error, Result};
15use crate::io::{Reader, Writer};
16
17pub const TAG_BINARY: u8 = 0x00;
19pub const TAG_GRAYSCALE: u8 = 0x01;
21pub const TAG_SPLIT: u8 = 0x02;
23pub const TAG_ATTACHED: u8 = 0x03;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
29pub enum EncodeMode {
30 #[default]
32 Auto,
33 Binary,
35 Grayscale,
37 Split,
39 Attached,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub struct Run {
57 pub length: u32,
59 pub value: u8,
61}
62
63impl Run {
64 pub fn new(length: u32, value: u8) -> Self {
66 Run { length, value }
67 }
68}
69
70#[derive(Debug, Clone, PartialEq, Eq)]
72pub struct DecodedLayer {
73 pub pixels: Vec<u8>,
75 pub tag: Option<u8>,
77}
78
79impl DecodedLayer {
80 pub fn empty(total_pixels: u32) -> DecodedLayer {
83 DecodedLayer {
84 pixels: vec![0u8; total_pixels as usize],
85 tag: None,
86 }
87 }
88
89 pub fn is_empty(&self) -> bool {
91 self.tag.is_none()
92 }
93
94 pub fn is_binary(&self) -> bool {
96 self.pixels.iter().all(|p| *p == 0 || *p == 255)
97 }
98}
99
100pub fn threshold(pixel: u8) -> u8 {
102 if pixel >= 128 {
103 255
104 } else {
105 0
106 }
107}
108
109pub fn decode(data: &[u8], total_pixels: u32, strict: bool) -> Result<DecodedLayer> {
120 decode_counted(data, total_pixels, strict).map(|(layer, _)| layer)
121}
122
123pub fn decode_counted(
130 data: &[u8],
131 total_pixels: u32,
132 strict: bool,
133) -> Result<(DecodedLayer, usize)> {
134 let (tag, mut reader) = tag_and_stream(data)?;
135 let mut pixels = vec![0u8; total_pixels as usize];
136 read(
137 tag,
138 Sink::Mask(&mut pixels),
139 &mut reader,
140 total_pixels,
141 strict,
142 )?;
143 Ok((
144 DecodedLayer {
145 pixels,
146 tag: Some(tag),
147 },
148 1 + reader.pos(),
149 ))
150}
151
152fn tag_and_stream(data: &[u8]) -> Result<(u8, Reader<'_>)> {
157 let Some((&tag, stream)) = data.split_first() else {
158 return Err(Error::new(
159 Check::ReeTag,
160 "layer mask data is empty: the empty-layer form carries no bytes",
161 ));
162 };
163 match tag {
164 TAG_BINARY | TAG_GRAYSCALE | TAG_SPLIT | TAG_ATTACHED => {}
165 other => {
166 return Err(Error::new(
167 Check::ReeTag,
168 format!("unknown layer encoding tag 0x{other:02X}"),
169 ))
170 }
171 }
172 Ok((tag, Reader::checked(stream, Check::ReeVarint)))
173}
174
175fn read(
181 tag: u8,
182 sink: Sink<'_>,
183 reader: &mut Reader<'_>,
184 total_pixels: u32,
185 strict: bool,
186) -> Result<()> {
187 match tag {
188 TAG_BINARY => read_binary(sink, reader, total_pixels, strict),
189 TAG_GRAYSCALE => read_grayscale(sink, reader, total_pixels, strict),
190 TAG_SPLIT => read_split(sink, reader, total_pixels, strict),
191 TAG_ATTACHED => read_attached(sink, reader, total_pixels, strict),
192 _ => unreachable!("tag_and_stream accepts 0x00, 0x01, 0x02 and 0x03 only"),
194 }
195}
196
197fn read_run_count(reader: &mut Reader<'_>, total_pixels: u64) -> Result<u64> {
201 let bound = total_pixels + 1;
202 let run_count = reader.varint()?;
203 if run_count > bound {
204 return Err(Error::new(
205 Check::ReeRunLengths,
206 format!("run_count {run_count} exceeds total_pixels + 1 ({bound})"),
207 ));
208 }
209 Ok(run_count)
210}
211
212const PLANES: usize = 4;
214
215struct Planes<'a> {
223 planes: [&'a [u8]; PLANES],
224 at: [usize; PLANES],
225}
226
227impl<'a> Planes<'a> {
228 fn read(reader: &mut Reader<'a>, strict: bool) -> Result<Planes<'a>> {
233 let mut lengths = [0usize; PLANES];
234 for (plane, length) in lengths.iter_mut().enumerate() {
235 let value = reader.varint()?;
236 *length = usize::try_from(value).map_err(|_| {
237 Error::new(
238 Check::ReePlanes,
239 format!("plane {plane} length {value} does not fit in memory"),
240 )
241 })?;
242 }
243 if strict {
244 for plane in 1..PLANES {
247 if lengths[plane] > 0 && lengths[plane - 1] == 0 {
248 return Err(Error::new(
249 Check::ReePlanes,
250 format!(
251 "plane {plane} holds {} bytes after empty plane {}: the planes are \
252 not prefix-closed",
253 lengths[plane],
254 plane - 1
255 ),
256 ));
257 }
258 }
259 }
260 let mut planes = [&[][..]; PLANES];
261 for (plane, length) in planes.iter_mut().zip(lengths) {
262 *plane = reader.bytes(length)?;
263 }
264 Ok(Planes {
265 planes,
266 at: [0; PLANES],
267 })
268 }
269
270 fn empty() -> Planes<'a> {
275 Planes {
276 planes: [&[]; PLANES],
277 at: [0; PLANES],
278 }
279 }
280
281 fn rewind(&self) -> Planes<'a> {
287 Planes {
288 planes: self.planes,
289 at: [0; PLANES],
290 }
291 }
292
293 fn next(&mut self) -> Result<Option<u64>> {
298 if self.at[0] == self.planes[0].len() {
299 return Ok(None);
300 }
301 let mut value = 0u64;
302 for plane in 0..PLANES {
303 let Some(&byte) = self.planes[plane].get(self.at[plane]) else {
304 return Err(Error::new(
305 Check::ReeVarint,
306 format!("a varint continues into plane {plane}, which holds no more bytes"),
307 ));
308 };
309 self.at[plane] += 1;
310 value |= u64::from(byte & 0x7F) << (7 * plane);
311 if byte & 0x80 == 0 {
312 if plane > 0 && byte == 0 {
313 return Err(Error::new(
314 Check::ReeVarint,
315 "a varint crossing planes is not minimally encoded",
316 ));
317 }
318 return Ok(Some(value));
319 }
320 }
321 Err(Error::new(
322 Check::ReeVarint,
323 "a varint continues past plane 3, which is the last plane",
324 ))
325 }
326
327 fn varint(&mut self) -> Result<u64> {
329 self.next()?.ok_or_else(|| {
330 Error::new(
331 Check::ReeVarint,
332 "the planes hold fewer varints than the stream's count",
333 )
334 })
335 }
336
337 fn check_consumed(&self) -> Result<()> {
340 for plane in 0..PLANES {
341 let len = self.planes[plane].len();
342 if self.at[plane] != len {
343 return Err(Error::new(
344 Check::ReePlanes,
345 format!(
346 "plane {plane} holds {len} bytes, {} of which describe a varint",
347 self.at[plane]
348 ),
349 ));
350 }
351 }
352 Ok(())
353 }
354}
355
356enum Sink<'m> {
363 Mask(&'m mut [u8]),
365 Exposed(&'m mut dyn FnMut(u64, u64) -> Result<()>),
371 None,
373}
374
375impl Sink<'_> {
376 #[inline]
381 fn fill(&mut self, start: u64, end: u64, value: u8) -> Result<()> {
382 match self {
383 Sink::Mask(mask) => mask[start as usize..end as usize].fill(value),
384 Sink::Exposed(report) => {
385 if value != 0x00 && start < end {
386 report(start, end)?;
387 }
388 }
389 Sink::None => {}
390 }
391 Ok(())
392 }
393
394 #[inline]
397 fn set(&mut self, position: u64, value: u8) -> Result<()> {
398 match self {
399 Sink::Mask(mask) => mask[position as usize] = value,
400 Sink::Exposed(report) => {
401 if value != 0x00 {
402 report(position, position + 1)?;
403 }
404 }
405 Sink::None => {}
406 }
407 Ok(())
408 }
409}
410
411struct Runs<'a> {
420 lengths: LengthSource<'a>,
421 left: u64,
423 start: u64,
425 end: u64,
426 walked: u64,
428 total: u64,
429 kind: &'static str,
431 empty: bool,
433}
434
435impl<'a> Runs<'a> {
436 fn new(lengths: LengthSource<'a>, count: u64, total: u64, kind: &'static str) -> Runs<'a> {
437 Runs {
438 lengths,
439 left: count,
440 start: 0,
441 end: 0,
442 walked: 0,
443 total,
444 kind,
445 empty: false,
446 }
447 }
448
449 fn step(&mut self) -> Result<Option<u64>> {
456 if self.left == 0 {
457 return Ok(None);
458 }
459 self.left -= 1;
460 let end = if self.left == 0 {
462 self.total
463 } else {
464 let index = self.walked;
465 self.end
466 .checked_add(self.lengths.next(index)?)
467 .ok_or_else(|| {
468 Error::new(
469 Check::ReeEndPositions,
470 format!("{} run lengths overflow", self.kind),
471 )
472 })?
473 };
474 let (start, index) = (self.end, self.walked);
475 if end > self.total {
476 return Err(Error::new(
477 Check::ReeEndPositions,
478 format!(
479 "{} run {index} ends at {end}, past total_pixels {}",
480 self.kind, self.total
481 ),
482 ));
483 }
484 self.empty |= end == start;
485 self.start = start;
486 self.end = end;
487 self.walked = index + 1;
488 Ok(Some(index))
489 }
490
491 fn seek(&mut self, position: u64) -> Result<u64> {
497 while self.end <= position {
498 if self.step()?.is_none() {
499 return Err(Error::new(
500 Check::ReeEndPositions,
501 format!("{} holds no run covering pixel {position}", self.kind),
502 ));
503 }
504 }
505 Ok(self.walked.saturating_sub(1))
506 }
507
508 fn range(&self) -> (u64, u64) {
510 (self.start, self.end)
511 }
512
513 fn empty_run(&self) -> bool {
516 self.empty
517 }
518
519 fn check_consumed(&self) -> Result<()> {
522 self.lengths.check_consumed()
523 }
524}
525
526enum LengthSource<'a> {
534 Planes(Planes<'a>),
536 Parity(Parity<'a>),
538}
539
540impl LengthSource<'_> {
541 fn next(&mut self, index: u64) -> Result<u64> {
543 match self {
544 LengthSource::Planes(planes) => planes.varint(),
545 LengthSource::Parity(parity) => {
546 let length = parity.next(index)?;
547 u64::try_from(length).map_err(|_| {
548 Error::new(
549 Check::ReeEndPositions,
550 format!("attached REE run {index} has a negative length"),
551 )
552 })
553 }
554 }
555 }
556
557 fn check_consumed(&self) -> Result<()> {
559 match self {
560 LengthSource::Planes(planes) => planes.check_consumed(),
561 LengthSource::Parity(parity) => {
562 parity.streams[0].check_consumed()?;
563 parity.streams[1].check_consumed()
564 }
565 }
566 }
567}
568
569struct Parity<'a> {
578 streams: [Planes<'a>; 2],
579 last: [i64; 2],
582}
583
584impl<'a> Parity<'a> {
585 fn read(reader: &mut Reader<'a>, strict: bool) -> Result<Parity<'a>> {
587 Ok(Parity {
588 streams: [Planes::read(reader, strict)?, Planes::read(reader, strict)?],
589 last: [0; 2],
590 })
591 }
592
593 fn next(&mut self, index: u64) -> Result<i64> {
598 let parity = (index % 2) as usize;
599 let stored = self.streams[parity].varint()?;
600 if index < 2 {
601 let length = i64::try_from(stored).map_err(|_| {
602 Error::new(
603 Check::ReeEndPositions,
604 format!("attached REE run {index} is {stored} pixels long"),
605 )
606 })?;
607 self.last[parity] = length;
608 return Ok(length);
609 }
610 let length = self.last[parity]
611 .checked_add(unzigzag(stored))
612 .ok_or_else(|| {
613 Error::new(Check::ReeEndPositions, "attached REE run lengths overflow")
614 })?;
615 self.last[parity] = length;
616 Ok(length)
617 }
618}
619
620#[inline]
626fn zigzag(value: i64) -> u64 {
627 ((value as u64) << 1) ^ ((value >> 63) as u64)
628}
629
630#[inline]
632fn unzigzag(value: u64) -> i64 {
633 ((value >> 1) as i64) ^ -((value & 1) as i64)
634}
635
636struct Core<'a> {
642 first_value: u8,
643 count: u64,
644 total: u64,
645 planes: Planes<'a>,
646}
647
648impl<'a> Core<'a> {
649 fn read(reader: &mut Reader<'a>, total_pixels: u32, strict: bool) -> Result<Core<'a>> {
651 let total = u64::from(total_pixels);
652 let first_value = reader.u8()?;
653 if first_value != 0x00 && first_value != 0xFF {
654 return Err(Error::new(
655 Check::ReeFirstValue,
656 format!("binary REE first_value is 0x{first_value:02X}, not 0x00 or 0xFF"),
657 ));
658 }
659 let count = read_run_count(reader, total)?;
660 if count == 0 {
661 if strict {
662 return Err(Error::new(
663 Check::ReeNoRunCountZero,
664 "binary REE uses the non-canonical run_count == 0 form",
665 ));
666 }
667 return Ok(Core {
670 first_value: 0x00,
671 count: 1,
672 total,
673 planes: Planes::empty(),
674 });
675 }
676 Ok(Core {
677 first_value,
678 count,
679 total,
680 planes: Planes::read(reader, strict)?,
681 })
682 }
683
684 #[inline]
686 fn value(&self, index: u64) -> u8 {
687 if index % 2 == 0 {
688 self.first_value
689 } else {
690 255 - self.first_value
691 }
692 }
693
694 fn runs(&self) -> Runs<'a> {
696 Runs::new(
697 LengthSource::Planes(self.planes.rewind()),
698 self.count,
699 self.total,
700 "binary REE",
701 )
702 }
703
704 fn apply(&self, sink: &mut Sink<'_>, strict: bool) -> Result<()> {
708 let mut runs = self.runs();
709 while let Some(index) = runs.step()? {
710 let (start, end) = runs.range();
711 sink.fill(start, end, self.value(index))?;
712 }
713 if strict {
714 if runs.empty_run() {
715 return Err(Error::new(
716 Check::ReeRunLengths,
717 "binary REE stores an empty run",
718 ));
719 }
720 runs.check_consumed()?;
721 }
722 Ok(())
723 }
724}
725
726fn read_binary(
728 mut sink: Sink<'_>,
729 reader: &mut Reader<'_>,
730 total_pixels: u32,
731 strict: bool,
732) -> Result<()> {
733 Core::read(reader, total_pixels, strict)?.apply(&mut sink, strict)
734}
735
736fn read_grayscale(
739 mut sink: Sink<'_>,
740 reader: &mut Reader<'_>,
741 total_pixels: u32,
742 strict: bool,
743) -> Result<()> {
744 let total = u64::from(total_pixels);
745 let run_count = read_run_count(reader, total)?;
746 if run_count == 0 {
747 if strict {
748 return Err(Error::new(
749 Check::ReeNoRunCountZero,
750 "grayscale REE uses the non-canonical run_count == 0 form",
751 ));
752 }
753 return sink.fill(0, total, 0x00);
756 }
757
758 let values = reader.bytes(run_count as usize)?;
760 let mut runs = Runs::new(
761 LengthSource::Planes(Planes::read(reader, strict)?),
762 run_count,
763 total,
764 "grayscale REE",
765 );
766 let mut previous: Option<u8> = None;
767 while let Some(index) = runs.step()? {
768 let (start, end) = runs.range();
769 let value = values[index as usize];
770 if strict && previous == Some(value) {
771 return Err(Error::new(
772 Check::ReeGrayscaleRuns,
773 format!("grayscale REE repeats value 0x{value:02X} in adjacent runs"),
774 ));
775 }
776 sink.fill(start, end, value)?;
777 previous = Some(value);
778 }
779 if strict {
780 if runs.empty_run() {
781 return Err(Error::new(
782 Check::ReeGrayscaleRuns,
783 "grayscale REE stores a zero-length run",
784 ));
785 }
786 runs.check_consumed()?;
787 if values.iter().all(|value| *value == 0x00 || *value == 0xFF) {
791 return Err(Error::new(
792 Check::ReeGrayscaleAllBinary,
793 "grayscale REE holds only 0x00/0xFF pixels; such a layer must use tag 0x00",
794 ));
795 }
796 }
797 Ok(())
798}
799
800fn walk_positions(
806 planes: &mut Planes<'_>,
807 count: u64,
808 total: u64,
809 mut f: impl FnMut(u64, usize) -> Result<()>,
810) -> Result<()> {
811 let mut position = 0u64;
812 for i in 0..count {
813 let delta = planes.varint()?;
814 position = position.checked_add(delta).ok_or_else(|| {
815 Error::new(Check::ReeSplitPositions, "split overlay positions overflow")
816 })?;
817 if i > 0 && delta == 0 {
818 return Err(Error::new(
819 Check::ReeSplitPositions,
820 format!("split overlay position {position} repeats its predecessor"),
821 ));
822 }
823 if position >= total {
824 return Err(Error::new(
825 Check::ReeSplitPositions,
826 format!("split overlay position {position} is not below total_pixels {total}"),
827 ));
828 }
829 f(position, i as usize)?;
830 }
831 Ok(())
832}
833
834fn read_split(
837 mut sink: Sink<'_>,
838 reader: &mut Reader<'_>,
839 total_pixels: u32,
840 strict: bool,
841) -> Result<()> {
842 let total = u64::from(total_pixels);
843 let core = Core::read(reader, total_pixels, strict)?;
844 core.apply(&mut sink, strict)?;
847
848 let aa_count = reader.varint()?;
849 let bound = total + 1;
850 if aa_count > bound {
851 return Err(Error::new(
852 Check::ReeSplitPositions,
853 format!("aa_pixel_count {aa_count} exceeds total_pixels + 1 ({bound})"),
854 ));
855 }
856 let positions = Planes::read(reader, strict)?;
858 let values = reader.bytes(aa_count as usize)?;
859
860 if strict {
861 let mut checked = positions.rewind();
867 walk_positions(&mut checked, aa_count, total, |_, _| Ok(()))?;
868 checked.check_consumed()?;
869 let mut runs = core.runs();
874 walk_positions(&mut positions.rewind(), aa_count, total, |position, i| {
875 let value = values[i];
876 let binary = core.value(runs.seek(position)?);
877 if value == 0x00 || value == 0xFF || threshold(value) != binary {
878 return Err(Error::new(
879 Check::ReeSplitThreshold,
880 format!(
881 "split overlay pixel {position} holds 0x{value:02X} over binary \
882 0x{binary:02X}"
883 ),
884 ));
885 }
886 Ok(())
887 })?;
888 if aa_count == 0 {
893 return Err(Error::new(
894 Check::ReeSplitAllBinary,
895 "split REE holds only 0x00/0xFF pixels: it has no anti-aliasing to overlay, \
896 and such a layer must use tag 0x00",
897 ));
898 }
899 }
900 walk_positions(&mut positions.rewind(), aa_count, total, |position, i| {
904 sink.set(position, values[i])
905 })
906}
907
908struct AttachBits<'a> {
916 bytes: &'a [u8],
917}
918
919impl<'a> AttachBits<'a> {
920 fn read(reader: &mut Reader<'a>, runs: u64) -> Result<AttachBits<'a>> {
925 Ok(AttachBits {
926 bytes: reader.bytes(runs.div_ceil(4) as usize)?,
927 })
928 }
929
930 fn is_empty(&self) -> bool {
933 self.bytes.is_empty()
934 }
935
936 #[inline]
940 fn get(&self, index: u64, end: u64) -> bool {
941 self.bytes[(index / 4) as usize] & (1 << ((index % 4) * 2 + end)) != 0
942 }
943
944 fn padding_clear(&self, runs: u64) -> bool {
947 match runs % 4 {
948 0 => true,
949 used => {
950 let last = self.bytes[(runs / 4) as usize];
951 last & (!0u8 << (used * 2)) == 0
952 }
953 }
954 }
955}
956
957struct AttachValues<'a> {
963 planes: Planes<'a>,
964 index: u64,
966 previous: u8,
967}
968
969impl<'a> AttachValues<'a> {
970 fn read(reader: &mut Reader<'a>, strict: bool) -> Result<AttachValues<'a>> {
971 Ok(AttachValues {
972 planes: Planes::read(reader, strict)?,
973 index: 0,
974 previous: 0,
975 })
976 }
977
978 fn next_within(&mut self, count: u64) -> Result<u8> {
983 if self.index == count {
984 return Err(Error::new(
985 Check::ReeAttachCount,
986 format!(
987 "the attachment bits and escapes describe more overlay pixels than the {count} the stream stores values for"
988 ),
989 ));
990 }
991 let stored = self.planes.varint()?;
992 let value = if self.index == 0 {
993 u8::try_from(stored).map_err(|_| {
996 Error::new(
997 Check::ReeAttachCount,
998 format!("attached REE overlay value {stored} is not a byte"),
999 )
1000 })?
1001 } else {
1002 let sum = i64::from(self.previous) + unzigzag(stored);
1003 u8::try_from(sum).map_err(|_| {
1004 Error::new(
1005 Check::ReeAttachCount,
1006 format!("attached REE overlay value {sum} is not a byte"),
1007 )
1008 })?
1009 };
1010 self.index += 1;
1011 self.previous = value;
1012 Ok(value)
1013 }
1014}
1015
1016fn check_attached_value(value: u8, core_value: u8, position: u64) -> Result<()> {
1023 if value == 0x00 || value == 0xFF || threshold(value) != core_value {
1024 return Err(Error::new(
1025 Check::ReeAttachThreshold,
1026 format!(
1027 "attached REE overlay pixel {position} holds 0x{value:02X} over binary 0x{core_value:02X}"
1028 ),
1029 ));
1030 }
1031 Ok(())
1032}
1033
1034fn read_attached(
1038 mut sink: Sink<'_>,
1039 reader: &mut Reader<'_>,
1040 total_pixels: u32,
1041 strict: bool,
1042) -> Result<()> {
1043 let total = u64::from(total_pixels);
1044 let declared_value = reader.u8()?;
1045 if declared_value != 0x00 && declared_value != 0xFF {
1046 return Err(Error::new(
1047 Check::ReeFirstValue,
1048 format!("attached REE first_value is 0x{declared_value:02X}, not 0x00 or 0xFF"),
1049 ));
1050 }
1051 let run_count = read_run_count(reader, total)?;
1052 if run_count == 0 && strict {
1053 return Err(Error::new(
1054 Check::ReeNoRunCountZero,
1055 "attached REE uses the non-canonical run_count == 0 form",
1056 ));
1057 }
1058 let first_value = if run_count == 0 { 0x00 } else { declared_value };
1062 let mut runs = Runs::new(
1063 LengthSource::Parity(Parity::read(reader, strict)?),
1064 run_count.max(1),
1065 total,
1066 "attached REE",
1067 );
1068
1069 let aa_count = reader.varint()?;
1070 let bound = total + 1;
1071 if aa_count > bound {
1072 return Err(Error::new(
1073 Check::ReeAttachCount,
1074 format!("aa_pixel_count {aa_count} exceeds total_pixels + 1 ({bound})"),
1075 ));
1076 }
1077 let bits = AttachBits::read(reader, run_count)?;
1078 let escape_count = reader.varint()?;
1079 if escape_count > aa_count {
1080 return Err(Error::new(
1081 Check::ReeAttachCount,
1082 format!("escape_count {escape_count} exceeds aa_pixel_count {aa_count}"),
1083 ));
1084 }
1085 let mut escapes = Planes::read(reader, strict)?;
1086 let mut values = AttachValues::read(reader, strict)?;
1087
1088 let mut placed = 0u64;
1093 let mut previous_escape = 0u64;
1094 let mut escape_index = 0u64;
1095 let mut pending: Option<u64> = None;
1096
1097 while let Some(index) = runs.step()? {
1098 let (start, end) = runs.range();
1099 let core_value = if index % 2 == 0 {
1100 first_value
1101 } else {
1102 255 - first_value
1103 };
1104 sink.fill(start, end, core_value)?;
1105
1106 let empty = start == end;
1112 if !empty && !bits.is_empty() && bits.get(index, 0) {
1113 let value = values.next_within(aa_count)?;
1114 if strict {
1115 check_attached_value(value, core_value, start)?;
1116 }
1117 sink.set(start, value)?;
1118 placed += 1;
1119 }
1120
1121 loop {
1122 let position = match pending {
1123 Some(position) => position,
1124 None => {
1125 if escape_index == escape_count {
1126 break;
1127 }
1128 let delta = escapes.varint()?;
1129 if escape_index > 0 && delta == 0 {
1130 return Err(Error::new(
1131 Check::ReeAttachPositions,
1132 format!("attached REE escape {escape_index} repeats its predecessor"),
1133 ));
1134 }
1135 let position = previous_escape.checked_add(delta).ok_or_else(|| {
1136 Error::new(
1137 Check::ReeAttachPositions,
1138 "attached REE escape positions overflow",
1139 )
1140 })?;
1141 if position >= total {
1142 return Err(Error::new(
1143 Check::ReeAttachPositions,
1144 format!(
1145 "attached REE escape {position} is not below total_pixels {total}"
1146 ),
1147 ));
1148 }
1149 previous_escape = position;
1150 escape_index += 1;
1151 pending = Some(position);
1152 continue;
1153 }
1154 };
1155 if position >= end {
1156 break;
1157 }
1158 if position == start || position + 1 == end {
1159 return Err(Error::new(
1160 Check::ReeAttachPositions,
1161 format!(
1162 "attached REE escape {position} is not strictly inside the core run [{start}, {end}) it attaches to"
1163 ),
1164 ));
1165 }
1166 let value = values.next_within(aa_count)?;
1167 if strict {
1168 check_attached_value(value, core_value, position)?;
1169 }
1170 sink.set(position, value)?;
1171 placed += 1;
1172 pending = None;
1173 }
1174
1175 if !empty && !bits.is_empty() && bits.get(index, 1) {
1176 if strict && end - start == 1 {
1177 return Err(Error::new(
1178 Check::ReeAttachBits,
1179 format!("attached REE run {index} holds one pixel and sets both of its bits"),
1180 ));
1181 }
1182 let value = values.next_within(aa_count)?;
1186 if strict {
1187 check_attached_value(value, core_value, end - 1)?;
1188 }
1189 sink.set(end - 1, value)?;
1190 placed += 1;
1191 }
1192 }
1193
1194 if let Some(position) = pending {
1195 return Err(Error::new(
1196 Check::ReeAttachPositions,
1197 format!("attached REE escape {position} sits past the last core run"),
1198 ));
1199 }
1200 if placed != aa_count {
1201 return Err(Error::new(
1202 Check::ReeAttachCount,
1203 format!(
1204 "the attachment bits and escapes describe {placed} overlay pixels, aa_pixel_count says {aa_count}"
1205 ),
1206 ));
1207 }
1208 if strict {
1209 if runs.empty_run() {
1210 return Err(Error::new(
1211 Check::ReeRunLengths,
1212 "attached REE stores an empty run",
1213 ));
1214 }
1215 runs.check_consumed()?;
1216 escapes.check_consumed()?;
1217 values.planes.check_consumed()?;
1218 if !bits.padding_clear(run_count) {
1219 return Err(Error::new(
1220 Check::ReeAttachBits,
1221 "attached REE sets attachment bits past the last run",
1222 ));
1223 }
1224 }
1225 Ok(())
1226}
1227
1228fn check_mask(pixels: &[u8], total_pixels: u32) -> Result<()> {
1230 if pixels.len() != total_pixels as usize {
1231 return Err(Error::new(
1232 Check::ReeDataSize,
1233 format!(
1234 "mask holds {} pixels, total_pixels is {total_pixels}",
1235 pixels.len()
1236 ),
1237 ));
1238 }
1239 Ok(())
1240}
1241
1242fn require_pixels(pixels: &[u8]) -> Result<()> {
1244 if pixels.is_empty() {
1245 return Err(Error::new(
1246 Check::ReeDataSize,
1247 "a zero-pixel layer has no encodable stream: it is the empty-layer form",
1248 ));
1249 }
1250 Ok(())
1251}
1252
1253fn check_runs(runs: &[Run], total_pixels: u32) -> Result<()> {
1261 let mut covered = 0u64;
1262 let mut previous: Option<u8> = None;
1263 for run in runs {
1264 if run.length == 0 {
1265 return Err(Error::new(
1266 Check::ReeRunLengths,
1267 "run length 0: a run covers at least one pixel",
1268 ));
1269 }
1270 if previous == Some(run.value) {
1271 return Err(Error::new(
1272 Check::ReeGrayscaleRuns,
1273 format!(
1274 "adjacent runs both carry 0x{:02X}: they are a single run",
1275 run.value
1276 ),
1277 ));
1278 }
1279 covered += u64::from(run.length);
1280 previous = Some(run.value);
1281 }
1282 if covered != u64::from(total_pixels) {
1283 return Err(Error::new(
1284 Check::ReeDataSize,
1285 format!("runs cover {covered} pixels, total_pixels is {total_pixels}"),
1286 ));
1287 }
1288 Ok(())
1289}
1290
1291#[derive(Clone, Copy)]
1299enum RunSource<'a> {
1300 Pixels(&'a [u8]),
1302 Runs(&'a [Run]),
1304}
1305
1306impl RunSource<'_> {
1307 fn walk<F>(self, map: impl Fn(u8) -> u8 + Copy, mut f: F) -> Result<()>
1310 where
1311 F: FnMut(u64, u8) -> Result<()>,
1312 {
1313 match self {
1314 RunSource::Pixels(pixels) => {
1315 let mut pixels = pixels.iter().copied();
1316 let Some(first) = pixels.next() else {
1317 return Ok(());
1318 };
1319 let mut value = map(first);
1320 let mut length = 1u64;
1321 for pixel in pixels {
1322 let mapped = map(pixel);
1323 if mapped == value {
1324 length += 1;
1325 continue;
1326 }
1327 f(length, value)?;
1328 value = mapped;
1329 length = 1;
1330 }
1331 f(length, value)
1332 }
1333 RunSource::Runs(runs) => {
1334 let mut pending: Option<(u64, u8)> = None;
1335 for run in runs {
1336 let value = map(run.value);
1337 match pending {
1338 Some((length, previous)) if previous == value => {
1339 pending = Some((length + u64::from(run.length), value));
1340 }
1341 Some((length, previous)) => {
1342 f(length, previous)?;
1343 pending = Some((u64::from(run.length), value));
1344 }
1345 None => pending = Some((u64::from(run.length), value)),
1346 }
1347 }
1348 match pending {
1349 Some((length, value)) => f(length, value),
1350 None => Ok(()),
1351 }
1352 }
1353 }
1354 }
1355
1356 fn is_all_black(self) -> bool {
1359 match self {
1360 RunSource::Pixels(pixels) => pixels.iter().all(|pixel| *pixel == 0),
1361 RunSource::Runs(runs) => runs.iter().all(|run| run.value == 0),
1362 }
1363 }
1364
1365 fn is_binary(self) -> bool {
1367 match self {
1368 RunSource::Pixels(pixels) => pixels.iter().all(|pixel| *pixel == 0 || *pixel == 255),
1369 RunSource::Runs(runs) => runs.iter().all(|run| run.value == 0 || run.value == 255),
1370 }
1371 }
1372}
1373
1374#[derive(Debug, Default, Clone, Copy)]
1376struct PlaneSizes([u64; PLANES]);
1377
1378impl PlaneSizes {
1379 fn add(&mut self, value: u64) {
1385 let len = crate::varint::encoded_len(value).min(PLANES);
1386 for size in &mut self.0[..len] {
1387 *size += 1;
1388 }
1389 }
1390
1391 fn write(&self, writer: &mut Writer) {
1393 for size in self.0 {
1394 writer.varint(size);
1395 }
1396 }
1397}
1398
1399fn write_plane_byte(writer: &mut Writer, value: u64, plane: usize) -> Result<()> {
1405 let shifted = value >> (7 * plane);
1406 if plane > 0 && shifted == 0 {
1407 return Ok(());
1409 }
1410 let more = shifted >= 0x80;
1411 if more && plane + 1 == PLANES {
1412 return Err(Error::new(
1413 Check::ReePlanes,
1414 format!("the value {value} needs more than {PLANES} significance planes"),
1415 ));
1416 }
1417 writer.u8((shifted & 0x7F) as u8 | if more { 0x80 } else { 0 });
1418 Ok(())
1419}
1420
1421fn write_planes(
1429 writer: &mut Writer,
1430 sizes: PlaneSizes,
1431 mut walk: impl FnMut(&mut Writer, usize) -> Result<()>,
1432) -> Result<()> {
1433 sizes.write(writer);
1434 for plane in 0..PLANES {
1435 walk(writer, plane)?;
1436 }
1437 Ok(())
1438}
1439
1440fn write_binary_stream(
1444 writer: &mut Writer,
1445 source: RunSource<'_>,
1446 map: impl Fn(u8) -> u8 + Copy,
1447) -> Result<()> {
1448 let mut first_value: Option<u8> = None;
1450 let mut last: Option<u8> = None;
1451 let mut run_count = 0u64;
1452 let mut sizes = PlaneSizes::default();
1453 let mut pending: Option<u64> = None;
1456 source.walk(map, |length, value| {
1457 match last {
1458 None => {
1459 if value != 0x00 && value != 0xFF {
1460 return Err(Error::new(
1461 Check::ReeFirstValue,
1462 format!("binary REE first_value is 0x{value:02X}, not 0x00 or 0xFF"),
1463 ));
1464 }
1465 first_value = Some(value);
1466 }
1467 Some(previous) if value != 255 - previous => {
1468 return Err(Error::new(
1469 Check::ReeFirstValue,
1470 format!("binary REE cannot hold pixel 0x{value:02X}"),
1471 ));
1472 }
1473 Some(_) => {}
1474 }
1475 last = Some(value);
1476 run_count += 1;
1477 if let Some(previous) = pending.replace(length) {
1478 sizes.add(previous);
1479 }
1480 Ok(())
1481 })?;
1482 let Some(first_value) = first_value else {
1483 return Err(Error::new(
1484 Check::ReeDataSize,
1485 "a binary stream needs at least one pixel",
1486 ));
1487 };
1488
1489 writer.u8(first_value);
1490 writer.varint(run_count);
1491 write_planes(writer, sizes, |writer, plane| {
1494 let mut remaining = run_count;
1495 source.walk(map, |length, _| {
1496 remaining -= 1;
1497 if remaining > 0 {
1498 write_plane_byte(writer, length, plane)?;
1499 }
1500 Ok(())
1501 })
1502 })
1503}
1504
1505fn write_grayscale_stream(writer: &mut Writer, source: RunSource<'_>) -> Result<()> {
1508 let mut run_count = 0u64;
1509 let mut sizes = PlaneSizes::default();
1510 let mut pending: Option<u64> = None;
1511 source.walk(
1512 |value| value,
1513 |length, _| {
1514 run_count += 1;
1515 if let Some(previous) = pending.replace(length) {
1516 sizes.add(previous);
1517 }
1518 Ok(())
1519 },
1520 )?;
1521 writer.varint(run_count);
1522
1523 source.walk(
1527 |value| value,
1528 |_, value| {
1529 writer.u8(value);
1530 Ok(())
1531 },
1532 )?;
1533
1534 write_planes(writer, sizes, |writer, plane| {
1536 let mut remaining = run_count;
1537 source.walk(
1538 |value| value,
1539 |length, _| {
1540 remaining -= 1;
1541 if remaining > 0 {
1542 write_plane_byte(writer, length, plane)?;
1543 }
1544 Ok(())
1545 },
1546 )
1547 })
1548}
1549
1550fn write_split_stream(writer: &mut Writer, source: RunSource<'_>) -> Result<()> {
1558 write_binary_stream(writer, source, threshold)?;
1559
1560 let mut count = 0u64;
1563 let mut sizes = PlaneSizes::default();
1564 let mut start = 0u64;
1565 let mut previous = 0u64;
1566 source.walk(
1567 |value| value,
1568 |length, value| {
1569 if value != 0x00 && value != 0xFF {
1570 count += length;
1571 sizes.add(start - previous);
1572 for _ in 1..length {
1573 sizes.add(1);
1574 }
1575 previous = start + length - 1;
1576 }
1577 start += length;
1578 Ok(())
1579 },
1580 )?;
1581 writer.varint(count);
1582
1583 write_planes(writer, sizes, |writer, plane| {
1586 let mut start = 0u64;
1587 let mut previous = 0u64;
1588 source.walk(
1589 |value| value,
1590 |length, value| {
1591 if value != 0x00 && value != 0xFF {
1592 write_plane_byte(writer, start - previous, plane)?;
1593 for _ in 1..length {
1594 write_plane_byte(writer, 1, plane)?;
1595 }
1596 previous = start + length - 1;
1597 }
1598 start += length;
1599 Ok(())
1600 },
1601 )
1602 })?;
1603
1604 source.walk(
1606 |value| value,
1607 |length, value| {
1608 if value != 0x00 && value != 0xFF {
1609 for _ in 0..length {
1610 writer.u8(value);
1611 }
1612 }
1613 Ok(())
1614 },
1615 )
1616}
1617
1618#[inline]
1620fn is_aa(value: u8) -> bool {
1621 value != 0x00 && value != 0xFF
1622}
1623
1624struct StoredLengths {
1632 last: [u64; 2],
1634 index: u64,
1635}
1636
1637impl StoredLengths {
1638 fn new() -> StoredLengths {
1639 StoredLengths {
1640 last: [0; 2],
1641 index: 0,
1642 }
1643 }
1644
1645 fn next(&mut self, length: u64) -> (u64, usize) {
1648 let parity = (self.index % 2) as usize;
1649 let value = if self.index < 2 {
1650 length
1651 } else {
1652 zigzag(length as i64 - self.last[parity] as i64)
1653 };
1654 self.last[parity] = length;
1655 self.index += 1;
1656 (value, parity)
1657 }
1658}
1659
1660fn walk_overlay(
1673 source: RunSource<'_>,
1674 mut run: impl FnMut(u64, bool, bool) -> Result<()>,
1675 mut escape: impl FnMut(u64, u64) -> Result<()>,
1676) -> Result<()> {
1677 let mut index = 0u64;
1678 let mut at = 0u64;
1679 let mut start = 0u64;
1680 let mut mapped: Option<u8> = None;
1681 let mut first_aa = false;
1682 let mut pending: Option<u64> = None;
1683 let mut previous_escape = 0u64;
1684
1685 source.walk(
1686 |value| value,
1687 |length, value| {
1688 let binary = threshold(value);
1689 if mapped != Some(binary) {
1690 if mapped.is_some() {
1691 run(index, first_aa, pending.is_some())?;
1692 index += 1;
1693 }
1694 mapped = Some(binary);
1695 start = at;
1696 first_aa = is_aa(value);
1697 pending = None;
1698 }
1699 if is_aa(value) {
1700 for position in at..at + length {
1701 if position == start && first_aa {
1702 continue;
1704 }
1705 if let Some(previous) = pending.take() {
1706 escape(previous, previous - previous_escape)?;
1707 previous_escape = previous;
1708 }
1709 pending = Some(position);
1710 }
1711 } else if let Some(previous) = pending.take() {
1712 escape(previous, previous - previous_escape)?;
1715 previous_escape = previous;
1716 }
1717 at += length;
1718 Ok(())
1719 },
1720 )?;
1721 if mapped.is_some() {
1722 run(index, first_aa, pending.is_some())?;
1723 }
1724 Ok(())
1725}
1726
1727fn write_attached_stream(writer: &mut Writer, source: RunSource<'_>) -> Result<()> {
1731 let mut first_value: Option<u8> = None;
1735 let mut run_count = 0u64;
1736 let mut pending: Option<u64> = None;
1737 let mut stored = StoredLengths::new();
1738 let mut sizes = [PlaneSizes::default(); 2];
1739 let mut last: Option<u8> = None;
1740 source.walk(threshold, |length, value| {
1741 match last {
1742 None => {
1743 if value != 0x00 && value != 0xFF {
1744 return Err(Error::new(
1745 Check::ReeFirstValue,
1746 format!("attached REE first_value is 0x{value:02X}, not 0x00 or 0xFF"),
1747 ));
1748 }
1749 first_value = Some(value);
1750 }
1751 Some(previous) if value != 255 - previous => {
1752 return Err(Error::new(
1753 Check::ReeFirstValue,
1754 format!("attached REE cannot hold pixel 0x{value:02X}"),
1755 ));
1756 }
1757 Some(_) => {}
1758 }
1759 last = Some(value);
1760 if let Some(previous) = pending.replace(length) {
1761 let (value, parity) = stored.next(previous);
1762 sizes[parity].add(value);
1763 }
1764 run_count += 1;
1765 Ok(())
1766 })?;
1767 let Some(first_value) = first_value else {
1768 return Err(Error::new(
1769 Check::ReeDataSize,
1770 "an attached stream needs at least one pixel",
1771 ));
1772 };
1773
1774 let mut bits: Vec<u8> = Vec::new();
1778 let mut escape_sizes = PlaneSizes::default();
1779 let mut escape_count = 0u64;
1780 let mut value_sizes = PlaneSizes::default();
1781 let mut value_count = 0u64;
1782 let mut previous_value = 0u8;
1783 walk_overlay(
1784 source,
1785 |index, first, last| {
1786 let byte = (index / 4) as usize;
1787 if bits.len() <= byte {
1788 bits.resize(byte + 1, 0);
1789 }
1790 if first {
1791 bits[byte] |= 1 << ((index % 4) * 2);
1792 }
1793 if last {
1794 bits[byte] |= 2 << ((index % 4) * 2);
1795 }
1796 Ok(())
1797 },
1798 |_, delta| {
1799 escape_sizes.add(delta);
1800 escape_count += 1;
1801 Ok(())
1802 },
1803 )?;
1804 source.walk(
1805 |value| value,
1806 |length, value| {
1807 if is_aa(value) {
1808 for _ in 0..length {
1809 let stored = if value_count == 0 {
1810 u64::from(value)
1811 } else {
1812 zigzag(i64::from(value) - i64::from(previous_value))
1813 };
1814 value_sizes.add(stored);
1815 value_count += 1;
1816 previous_value = value;
1817 }
1818 }
1819 Ok(())
1820 },
1821 )?;
1822 bits.resize(run_count.div_ceil(4) as usize, 0);
1823
1824 writer.u8(first_value);
1827 writer.varint(run_count);
1828 for (parity, size) in sizes.iter().enumerate() {
1829 size.write(writer);
1830 for plane in 0..PLANES {
1831 let mut replay = StoredLengths::new();
1832 let mut pending: Option<u64> = None;
1833 source.walk(threshold, |length, _| {
1834 if let Some(previous) = pending.replace(length) {
1835 let (value, at) = replay.next(previous);
1836 if at == parity {
1837 write_plane_byte(writer, value, plane)?;
1838 }
1839 }
1840 Ok(())
1841 })?;
1842 }
1843 }
1844 writer.varint(value_count);
1845 writer.bytes(&bits);
1846 writer.varint(escape_count);
1847 escape_sizes.write(writer);
1848 for plane in 0..PLANES {
1849 walk_overlay(
1850 source,
1851 |_, _, _| Ok(()),
1852 |_, delta| write_plane_byte(writer, delta, plane),
1853 )?;
1854 }
1855 value_sizes.write(writer);
1856 for plane in 0..PLANES {
1857 let mut index = 0u64;
1858 let mut previous = 0u8;
1859 source.walk(
1860 |value| value,
1861 |length, value| {
1862 if is_aa(value) {
1863 for _ in 0..length {
1864 let stored = if index == 0 {
1865 u64::from(value)
1866 } else {
1867 zigzag(i64::from(value) - i64::from(previous))
1868 };
1869 write_plane_byte(writer, stored, plane)?;
1870 index += 1;
1871 previous = value;
1872 }
1873 }
1874 Ok(())
1875 },
1876 )?;
1877 }
1878 Ok(())
1879}
1880
1881pub fn encode(pixels: &[u8], total_pixels: u32, mode: EncodeMode) -> Result<Option<(u8, Vec<u8>)>> {
1894 check_mask(pixels, total_pixels)?;
1895 encode_source(RunSource::Pixels(pixels), mode)
1896}
1897
1898pub fn encode_runs(
1909 runs: &[Run],
1910 total_pixels: u32,
1911 mode: EncodeMode,
1912) -> Result<Option<(u8, Vec<u8>)>> {
1913 check_runs(runs, total_pixels)?;
1914 encode_source(RunSource::Runs(runs), mode)
1915}
1916
1917fn encode_source(source: RunSource<'_>, mode: EncodeMode) -> Result<Option<(u8, Vec<u8>)>> {
1921 if source.is_all_black() {
1922 return Ok(None);
1923 }
1924 let encoded = match mode {
1925 EncodeMode::Binary => (TAG_BINARY, encode_binary_source(source)?),
1926 EncodeMode::Grayscale => (TAG_GRAYSCALE, encode_grayscale_source(source)?),
1927 EncodeMode::Split => (TAG_SPLIT, encode_split_source(source)?),
1928 EncodeMode::Attached => (TAG_ATTACHED, encode_attached_source(source)?),
1929 EncodeMode::Auto => {
1930 if source.is_binary() {
1931 (TAG_BINARY, encode_binary_source(source)?)
1932 } else {
1933 let grayscale = encode_grayscale_source(source)?;
1936 let split = encode_split_source(source)?;
1937 if split.len() < grayscale.len() {
1938 (TAG_SPLIT, split)
1939 } else {
1940 (TAG_GRAYSCALE, grayscale)
1941 }
1942 }
1943 }
1944 };
1945 Ok(Some(encoded))
1946}
1947
1948pub fn encode_binary(pixels: &[u8], total_pixels: u32) -> Result<Vec<u8>> {
1950 check_mask(pixels, total_pixels)?;
1951 require_pixels(pixels)?;
1952 encode_binary_source(RunSource::Pixels(pixels))
1953}
1954
1955fn encode_binary_source(source: RunSource<'_>) -> Result<Vec<u8>> {
1957 let mut writer = Writer::new();
1958 writer.u8(TAG_BINARY);
1959 write_binary_stream(&mut writer, source, |pixel| pixel)?;
1960 Ok(writer.into_vec())
1961}
1962
1963pub fn encode_grayscale(pixels: &[u8], total_pixels: u32) -> Result<Vec<u8>> {
1965 check_mask(pixels, total_pixels)?;
1966 require_pixels(pixels)?;
1967 encode_grayscale_source(RunSource::Pixels(pixels))
1968}
1969
1970fn encode_grayscale_source(source: RunSource<'_>) -> Result<Vec<u8>> {
1972 let mut writer = Writer::new();
1973 writer.u8(TAG_GRAYSCALE);
1974 write_grayscale_stream(&mut writer, source)?;
1975 Ok(writer.into_vec())
1976}
1977
1978pub fn encode_split(pixels: &[u8], total_pixels: u32) -> Result<Vec<u8>> {
1980 check_mask(pixels, total_pixels)?;
1981 require_pixels(pixels)?;
1982 encode_split_source(RunSource::Pixels(pixels))
1983}
1984
1985fn encode_split_source(source: RunSource<'_>) -> Result<Vec<u8>> {
1987 let mut writer = Writer::new();
1988 writer.u8(TAG_SPLIT);
1989 write_split_stream(&mut writer, source)?;
1990 Ok(writer.into_vec())
1991}
1992
1993pub fn encode_attached(pixels: &[u8], total_pixels: u32) -> Result<Vec<u8>> {
1995 check_mask(pixels, total_pixels)?;
1996 require_pixels(pixels)?;
1997 encode_attached_source(RunSource::Pixels(pixels))
1998}
1999
2000fn encode_attached_source(source: RunSource<'_>) -> Result<Vec<u8>> {
2002 let mut writer = Writer::new();
2003 writer.u8(TAG_ATTACHED);
2004 write_attached_stream(&mut writer, source)?;
2005 Ok(writer.into_vec())
2006}
2007
2008pub fn validate_stream(data: &[u8], total_pixels: u32, strict: bool) -> Result<usize> {
2018 let (tag, mut reader) = tag_and_stream(data)?;
2019 read(tag, Sink::None, &mut reader, total_pixels, strict)?;
2020 Ok(1 + reader.pos())
2021}
2022
2023pub(crate) fn exposed_ranges(
2033 data: &[u8],
2034 total_pixels: u32,
2035 report: impl FnMut(u64, u64) -> Result<()>,
2036) -> Result<()> {
2037 let (tag, mut reader) = tag_and_stream(data)?;
2038 let mut report = report;
2039 read(
2040 tag,
2041 Sink::Exposed(&mut report),
2042 &mut reader,
2043 total_pixels,
2044 true,
2045 )
2046}
2047
2048#[cfg(test)]
2049mod tests {
2050 use super::*;
2051
2052 const LAYER_BINARY: &str = "0000030201000064c801";
2059 const LAYER_GRAYSCALE: &str = "0105008000ff000400000064146464";
2060 const LAYER_SPLIT: &str = "02000504000000641e14321e1e000000640101010101010101010101010101010101010101010101010101010101c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8";
2061 const TOTAL: u32 = 64 * 48;
2063
2064 fn mask(runs: &[(u8, usize)]) -> Vec<u8> {
2066 let mut pixels = Vec::new();
2067 for (value, length) in runs {
2068 pixels.extend(std::iter::repeat_n(*value, *length));
2069 }
2070 pixels
2071 }
2072
2073 fn runs(pixels: &[u8]) -> Vec<(u8, usize)> {
2075 let mut runs: Vec<(u8, usize)> = Vec::new();
2076 for &pixel in pixels {
2077 if let Some(last) = runs.last_mut() {
2078 if last.0 == pixel {
2079 last.1 += 1;
2080 continue;
2081 }
2082 }
2083 runs.push((pixel, 1));
2084 }
2085 runs
2086 }
2087
2088 fn bytes(hex: &str) -> Vec<u8> {
2089 hex::decode(hex).unwrap()
2090 }
2091
2092 fn runs_of(pixels: &[u8]) -> Vec<Run> {
2094 runs(pixels)
2095 .into_iter()
2096 .map(|(value, length)| Run::new(length as u32, value))
2097 .collect()
2098 }
2099
2100 fn run_list(spec: &[(u8, usize)]) -> Vec<Run> {
2102 spec.iter()
2103 .map(|(value, length)| Run::new(*length as u32, *value))
2104 .collect()
2105 }
2106
2107 const MODES: [EncodeMode; 5] = [
2109 EncodeMode::Auto,
2110 EncodeMode::Binary,
2111 EncodeMode::Grayscale,
2112 EncodeMode::Split,
2113 EncodeMode::Attached,
2114 ];
2115
2116 type CorpusCase = (&'static str, Vec<(u8, usize)>, u8, EncodeMode);
2119
2120 fn corpus_cases() -> [CorpusCase; 3] {
2124 [
2125 (
2126 LAYER_BINARY,
2127 vec![(0, 100), (255, 200), (0, 2772)],
2128 TAG_BINARY,
2129 EncodeMode::Binary,
2130 ),
2131 (
2132 LAYER_GRAYSCALE,
2133 vec![(0, 100), (128, 20), (0, 100), (255, 100), (0, 2752)],
2134 TAG_GRAYSCALE,
2135 EncodeMode::Grayscale,
2136 ),
2137 (
2138 LAYER_SPLIT,
2139 vec![(0, 100), (200, 30), (0, 20), (255, 50), (0, 2872)],
2140 TAG_SPLIT,
2141 EncodeMode::Split,
2142 ),
2143 ]
2144 }
2145
2146 fn assert_run_path_matches(pixels: &[u8], runs: &[Run], total: u32, mode: EncodeMode) {
2149 match (encode(pixels, total, mode), encode_runs(runs, total, mode)) {
2150 (Ok(pixel_path), Ok(run_path)) => assert_eq!(pixel_path, run_path, "mode {mode:?}"),
2151 (Err(pixel_path), Err(run_path)) => {
2152 assert_eq!(pixel_path.check(), run_path.check(), "mode {mode:?}")
2153 }
2154 (pixel_path, run_path) => {
2155 panic!("{mode:?}: pixel path {pixel_path:?}, run path {run_path:?}")
2156 }
2157 }
2158 }
2159
2160 fn check_of(data: &[u8], total: u32, strict: bool) -> Check {
2161 decode(data, total, strict).unwrap_err().check()
2162 }
2163
2164 #[test]
2165 fn spec_varint_examples() {
2166 assert_eq!(crate::varint::to_vec(0), vec![0x00]);
2168 assert_eq!(crate::varint::to_vec(128), vec![0x80, 0x01]);
2169 assert_eq!(crate::varint::encoded_len(127), 1);
2170 assert_eq!(crate::varint::encoded_len(128), 2);
2171 assert_eq!(crate::varint::encoded_len(16_383), 2);
2172 assert_eq!(crate::varint::encoded_len(16_384), 3);
2173 assert_eq!(crate::varint::encoded_len(2_097_151), 3);
2174 assert_eq!(crate::varint::encoded_len(268_435_455), 4);
2175 assert_eq!(
2176 crate::varint::to_vec(1920 * 1080),
2177 vec![0x80, 0xC8, 0x7E],
2178 "2 073 600 is 3 bytes"
2179 );
2180 assert_eq!(crate::varint::encoded_len(11_520 * 6_480), 4);
2181 let twelve_k = crate::varint::to_vec(11_520 * 6_480);
2182 let mut reader = Reader::new(&twelve_k);
2183 assert_eq!(reader.varint().unwrap(), 11_520 * 6_480);
2184 assert!(reader.is_empty());
2185 }
2186
2187 #[test]
2188 fn binary_layer_of_the_corpus_round_trips() {
2189 let data = bytes(LAYER_BINARY);
2190 let expected = mask(&[(0, 100), (255, 200), (0, 2772)]);
2191 for strict in [false, true] {
2192 let layer = decode(&data, TOTAL, strict).unwrap();
2193 assert_eq!(layer.tag, Some(TAG_BINARY));
2194 assert_eq!(layer.pixels, expected);
2195 assert!(layer.is_binary());
2196 }
2197 assert_eq!(encode_binary(&expected, TOTAL).unwrap(), data);
2198 assert_eq!(
2199 encode(&expected, TOTAL, EncodeMode::Auto).unwrap(),
2200 Some((TAG_BINARY, data))
2201 );
2202 }
2203
2204 #[test]
2205 fn grayscale_layer_of_the_corpus_round_trips() {
2206 let data = bytes(LAYER_GRAYSCALE);
2207 let expected = mask(&[(0, 100), (128, 20), (0, 100), (255, 100), (0, 2752)]);
2208 for strict in [false, true] {
2209 let layer = decode(&data, TOTAL, strict).unwrap();
2210 assert_eq!(layer.tag, Some(TAG_GRAYSCALE));
2211 assert_eq!(layer.pixels, expected);
2212 }
2213 assert_eq!(encode_grayscale(&expected, TOTAL).unwrap(), data);
2214 assert_eq!(
2216 encode(&expected, TOTAL, EncodeMode::Auto).unwrap(),
2217 Some((TAG_GRAYSCALE, data))
2218 );
2219 }
2220
2221 #[test]
2222 fn split_layer_of_the_corpus_round_trips() {
2223 let data = bytes(LAYER_SPLIT);
2224 assert_eq!(data.len(), 76, "the corpus split stream is 76 bytes");
2225 let expected = mask(&[(0, 100), (200, 30), (0, 20), (255, 50), (0, 2872)]);
2227 for strict in [false, true] {
2228 let layer = decode(&data, TOTAL, strict).unwrap();
2229 assert_eq!(layer.tag, Some(TAG_SPLIT));
2230 assert_eq!(layer.pixels, expected);
2231 }
2232 assert_eq!(data[16], 0x64, "the first position is 100");
2237 assert!(data[17..46].iter().all(|b| *b == 0x01));
2238 assert!(data[46..].iter().all(|b| *b == 0xC8));
2239 assert_eq!(encode_split(&expected, TOTAL).unwrap(), data);
2240 assert_eq!(
2241 encode(&expected, TOTAL, EncodeMode::Split).unwrap(),
2242 Some((TAG_SPLIT, data))
2243 );
2244 }
2245
2246 #[test]
2247 fn all_black_is_the_empty_layer_form() {
2248 assert_eq!(encode(&[0u8; 16], 16, EncodeMode::Auto).unwrap(), None);
2249 assert_eq!(encode(&[0u8; 16], 16, EncodeMode::Binary).unwrap(), None);
2250 assert_eq!(encode(&[0u8; 16], 16, EncodeMode::Split).unwrap(), None);
2251 assert!(DecodedLayer::empty(16).is_empty());
2252 assert_eq!(encode(&[], 0, EncodeMode::Auto).unwrap(), None);
2255 assert_eq!(
2256 encode_binary(&[], 0).unwrap_err().check(),
2257 Check::ReeDataSize
2258 );
2259 assert_eq!(
2260 encode_grayscale(&[], 0).unwrap_err().check(),
2261 Check::ReeDataSize
2262 );
2263 assert_eq!(
2264 encode_split(&[], 0).unwrap_err().check(),
2265 Check::ReeDataSize
2266 );
2267 }
2268
2269 #[test]
2270 fn all_white_is_one_run() {
2271 let (tag, data) = encode(&[255u8; 16], 16, EncodeMode::Auto).unwrap().unwrap();
2272 assert_eq!(tag, TAG_BINARY);
2273 assert_eq!(data, vec![TAG_BINARY, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00]);
2276 assert_eq!(decode(&data, 16, true).unwrap().pixels, vec![255u8; 16]);
2277 }
2278
2279 #[test]
2280 fn auto_picks_the_smaller_stream_and_breaks_ties_towards_grayscale() {
2281 let tie = [0xFF, 0x00, 0x01, 0x00, 0x01, 0x00];
2284 assert_eq!(encode_grayscale(&tie, 6).unwrap().len(), 17);
2285 assert_eq!(encode_split(&tie, 6).unwrap().len(), 17);
2286 assert_eq!(
2287 encode(&tie, 6, EncodeMode::Auto).unwrap().unwrap().0,
2288 TAG_GRAYSCALE
2289 );
2290
2291 let alternating: Vec<u8> = (0..200).map(|i| if i % 2 == 0 { 0 } else { 10 }).collect();
2295 let grayscale = encode_grayscale(&alternating, 200).unwrap();
2296 let split = encode_split(&alternating, 200).unwrap();
2297 assert!(split.len() < grayscale.len(), "{split:?} {grayscale:?}");
2298 let (tag, data) = encode(&alternating, 200, EncodeMode::Auto)
2299 .unwrap()
2300 .unwrap();
2301 assert_eq!(tag, TAG_SPLIT);
2302 assert_eq!(data, split);
2303 assert_eq!(decode(&data, 200, false).unwrap().pixels, alternating);
2304
2305 let ramp = [0u8, 64, 128, 192, 255];
2309 let grayscale = encode_grayscale(&ramp, 5).unwrap();
2310 assert!(grayscale.len() < encode_split(&ramp, 5).unwrap().len());
2311 let (tag, data) = encode(&ramp, 5, EncodeMode::Auto).unwrap().unwrap();
2312 assert_eq!(tag, TAG_GRAYSCALE);
2313 assert_eq!(decode(&data, 5, false).unwrap().pixels, ramp);
2314 }
2315
2316 #[test]
2317 fn binary_stripes_round_trip_all_modes() {
2318 let pixels = mask(&[(0, 3), (255, 2), (0, 4), (255, 1)]);
2319 let data = encode_binary(&pixels, 10).unwrap();
2320 assert_eq!(
2323 data,
2324 vec![TAG_BINARY, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 3, 2, 4]
2325 );
2326 for strict in [false, true] {
2327 assert_eq!(decode(&data, 10, strict).unwrap().pixels, pixels);
2328 }
2329 assert_eq!(runs(&pixels).len(), 4);
2330 }
2331
2332 #[test]
2333 fn encode_rejects_a_mask_of_the_wrong_size() {
2334 assert_eq!(
2335 encode(&[0u8; 4], 5, EncodeMode::Auto).unwrap_err().check(),
2336 Check::ReeDataSize
2337 );
2338 assert_eq!(
2339 encode_binary(&[0u8; 4], 5).unwrap_err().check(),
2340 Check::ReeDataSize
2341 );
2342 assert_eq!(
2343 encode_grayscale(&[0u8; 4], 5).unwrap_err().check(),
2344 Check::ReeDataSize
2345 );
2346 assert_eq!(
2347 encode_split(&[0u8; 4], 5).unwrap_err().check(),
2348 Check::ReeDataSize
2349 );
2350 }
2351
2352 #[test]
2353 fn binary_mode_refuses_a_non_binary_mask() {
2354 let pixels = [0u8, 7, 255, 0];
2355 assert_eq!(
2356 encode(&pixels, 4, EncodeMode::Binary).unwrap_err().check(),
2357 Check::ReeFirstValue
2358 );
2359 assert_eq!(
2360 encode_binary(&pixels, 4).unwrap_err().check(),
2361 Check::ReeFirstValue
2362 );
2363 assert_eq!(
2365 encode_binary(&[7u8, 0], 2).unwrap_err().check(),
2366 Check::ReeFirstValue
2367 );
2368 }
2369
2370 fn attached_mask() -> Vec<u8> {
2374 mask(&[
2375 (0x00, 2), (0x80, 1), (0xFF, 2),
2378 (0x40, 1), (0xFF, 2), (0x90, 1), (0x00, 2),
2382 (0x10, 1), (0x00, 1),
2384 ])
2385 }
2386
2387 #[test]
2388 fn attached_round_trips_every_placement() {
2389 let pixels = attached_mask();
2390 let total = pixels.len() as u32;
2391 let (tag, data) = encode(&pixels, total, EncodeMode::Attached)
2392 .unwrap()
2393 .expect("a mask with overlay pixels has a stream");
2394 assert_eq!(tag, TAG_ATTACHED);
2395 assert_eq!(decode(&data, total, true).unwrap().pixels, pixels);
2396 assert_eq!(
2397 validate_stream(&data, total, true),
2398 Ok(data.len()),
2399 "the stream must use exactly its bytes"
2400 );
2401 assert_eq!(
2403 encode_runs(&runs_of(&pixels), total, EncodeMode::Attached),
2404 Ok(Some((TAG_ATTACHED, data)))
2405 );
2406 }
2407
2408 #[test]
2409 fn attached_pins_the_smallest_overlay_stream() {
2410 let data: Vec<u8> = vec![
2415 TAG_ATTACHED,
2416 0x00, 0x04, 0x02,
2419 0x00,
2420 0x00,
2421 0x00,
2422 0x01,
2423 0x00, 0x01,
2425 0x00,
2426 0x00,
2427 0x00,
2428 0x01, 0x02, 0x14, 0x00, 0x00,
2433 0x00,
2434 0x00,
2435 0x00, 0x02,
2437 0x01,
2438 0x00,
2439 0x00,
2440 0x80,
2441 0x7F,
2442 0x01, ];
2444 let pixels = vec![0x00, 0x80, 0x40, 0xFF];
2445 assert_eq!(decode(&data, 4, true).unwrap().pixels, pixels);
2446 assert_eq!(
2447 encode(&pixels, 4, EncodeMode::Attached).unwrap(),
2448 Some((TAG_ATTACHED, data.clone()))
2449 );
2450 assert_eq!(validate_stream(&data, 4, true), Ok(data.len()));
2451 }
2452
2453 #[test]
2454 fn attached_accepts_an_all_binary_layer() {
2455 let pixels = mask(&[(0x00, 5), (0xFF, 7), (0x00, 3)]);
2458 let (tag, data) = encode(&pixels, 15, EncodeMode::Attached).unwrap().unwrap();
2459 assert_eq!(tag, TAG_ATTACHED);
2460 assert_eq!(
2461 decode(&data, 15, true).unwrap().pixels,
2462 pixels,
2463 "strict mode accepts it: unlike split, an empty overlay is not a defect here"
2464 );
2465 assert_eq!(
2468 encode(&pixels, 15, EncodeMode::Binary).unwrap().unwrap().0,
2469 TAG_BINARY
2470 );
2471 }
2472
2473 #[test]
2474 fn attached_rejects_broken_overlays() {
2475 let base: Vec<u8> = vec![
2477 TAG_ATTACHED,
2478 0x00,
2479 0x04,
2480 0x02,
2481 0x00,
2482 0x00,
2483 0x00,
2484 0x01,
2485 0x00,
2486 0x01,
2487 0x00,
2488 0x00,
2489 0x00,
2490 0x01,
2491 0x02,
2492 0x14,
2493 0x00,
2494 0x00,
2495 0x00,
2496 0x00,
2497 0x00,
2498 0x02,
2499 0x01,
2500 0x00,
2501 0x00,
2502 0x80,
2503 0x7F,
2504 0x01,
2505 ];
2506 assert_eq!(
2507 decode(&base, 4, true).unwrap().pixels,
2508 vec![0, 0x80, 0x40, 0xFF]
2509 );
2510
2511 let both_ends: Vec<u8> = vec![
2515 TAG_ATTACHED,
2516 0x00,
2517 0x04,
2518 0x02,
2519 0x00,
2520 0x00,
2521 0x00,
2522 0x01,
2523 0x00,
2524 0x01,
2525 0x00,
2526 0x00,
2527 0x00,
2528 0x01,
2529 0x03, 0x1c, 0x00,
2532 0x00,
2533 0x00,
2534 0x00,
2535 0x00, 0x03,
2537 0x01,
2538 0x00,
2539 0x00,
2540 0x80,
2541 0x7F,
2542 0x00, 0x01,
2544 ];
2545 assert_eq!(check_of(&both_ends, 4, true), Check::ReeAttachBits);
2546 assert_eq!(
2547 decode(&both_ends, 4, false).unwrap().pixels,
2548 vec![0x00, 0x40, 0x40, 0xFF],
2549 "the second bit's value is the one the pixel ends up with"
2550 );
2551
2552 let mut binary_value = base.clone();
2555 binary_value[25] = 0x00;
2557 binary_value[26] = 0x00;
2558 assert_eq!(check_of(&binary_value, 4, true), Check::ReeAttachThreshold);
2559 assert!(decode(&binary_value, 4, false).is_ok());
2560
2561 let mut wrong_side = base.clone();
2563 wrong_side[25] = 0x40;
2564 assert_eq!(check_of(&wrong_side, 4, true), Check::ReeAttachThreshold);
2565
2566 let mut not_inside = vec![
2569 TAG_ATTACHED,
2570 0x00,
2571 0x04,
2572 0x02,
2573 0x00,
2574 0x00,
2575 0x00,
2576 0x01,
2577 0x00,
2578 0x01,
2579 0x00,
2580 0x00,
2581 0x00,
2582 0x01,
2583 0x02,
2584 0x14,
2585 0x01, 0x01,
2587 0x00,
2588 0x00,
2589 0x00,
2590 0x01, 0x02,
2592 0x01,
2593 0x00,
2594 0x00,
2595 0x80,
2596 0x7F,
2597 0x01,
2598 ];
2599 assert_eq!(check_of(¬_inside, 4, false), Check::ReeAttachPositions);
2600 assert_eq!(check_of(¬_inside, 4, true), Check::ReeAttachPositions);
2601
2602 not_inside[21] = 0x09; assert_eq!(check_of(¬_inside, 4, false), Check::ReeAttachPositions);
2606
2607 let mut short_values = base.clone();
2610 short_values[14] = 0x03;
2611 assert_eq!(check_of(&short_values, 4, false), Check::ReeAttachCount);
2612
2613 let mut long_values = base.clone();
2615 long_values[14] = 0x01;
2616 assert_eq!(check_of(&long_values, 4, false), Check::ReeAttachCount);
2617 }
2618
2619 #[test]
2620 fn attached_ignores_a_bit_on_an_empty_run() {
2621 let data: Vec<u8> = vec![
2627 TAG_ATTACHED,
2628 0x00,
2629 0x02, 0x01,
2631 0x00,
2632 0x00,
2633 0x00,
2634 0x03, 0x00,
2636 0x00,
2637 0x00,
2638 0x00, 0x01, 0x04, 0x00, 0x00,
2643 0x00,
2644 0x00,
2645 0x00, 0x01,
2647 0x00,
2648 0x00,
2649 0x00,
2650 0x40, ];
2652 assert_eq!(check_of(&data, 3, false), Check::ReeAttachCount);
2656 assert_eq!(check_of(&data, 3, true), Check::ReeAttachCount);
2657 }
2658
2659 #[test]
2660 fn attached_padding_bits_are_strict_only() {
2661 let pixels = mask(&[(0xFF, 4)]);
2664 let (_, data) = encode(&pixels, 4, EncodeMode::Attached).unwrap().unwrap();
2665 let mut padded = data.clone();
2666 let last = padded.len() - 1 - 4 - 4 - 1; padded[last] = 0x04;
2668 assert_eq!(check_of(&padded, 4, true), Check::ReeAttachBits);
2669 assert!(decode(&padded, 4, false).is_ok());
2670 }
2671
2672 #[test]
2673 fn attached_run_count_zero_is_loose_only() {
2674 let data: Vec<u8> = vec![
2679 TAG_ATTACHED,
2680 0x00,
2681 0x00, 0x00,
2683 0x00,
2684 0x00,
2685 0x00,
2686 0x00,
2687 0x00,
2688 0x00,
2689 0x00, 0x00, 0x00, 0x00,
2693 0x00,
2694 0x00,
2695 0x00, 0x00,
2697 0x00,
2698 0x00,
2699 0x00, ];
2701 assert_eq!(decode(&data, 4, false).unwrap().pixels, vec![0u8; 4]);
2702 assert_eq!(check_of(&data, 4, true), Check::ReeNoRunCountZero);
2703 }
2704
2705 #[test]
2706 fn unknown_or_missing_tags_are_rejected() {
2707 assert_eq!(check_of(&[], 4, false), Check::ReeTag);
2708 assert_eq!(check_of(&[0x04, 0x00], 4, false), Check::ReeTag);
2709 assert_eq!(check_of(&[0xFF, 0x00], 4, true), Check::ReeTag);
2710 assert_eq!(check_of(&[TAG_BINARY], 4, false), Check::ReeVarint);
2711 assert_eq!(check_of(&[TAG_GRAYSCALE], 4, false), Check::ReeVarint);
2712 assert_eq!(check_of(&[TAG_ATTACHED], 4, false), Check::ReeVarint);
2713 assert_eq!(
2714 check_of(&[TAG_SPLIT, TAG_BINARY, 0x01], 4, false),
2715 Check::ReeVarint
2716 );
2717 }
2718
2719 #[test]
2720 fn binary_first_value_must_be_black_or_white() {
2721 assert_eq!(
2722 check_of(&[TAG_BINARY, 0x7F, 0x01], 4, false),
2723 Check::ReeFirstValue
2724 );
2725 assert_eq!(
2726 check_of(&[TAG_BINARY, 0x01, 0x01], 4, true),
2727 Check::ReeFirstValue
2728 );
2729 }
2730
2731 #[test]
2732 fn run_count_zero_is_loose_only() {
2733 let binary = [TAG_BINARY, 0x00, 0x00];
2735 assert_eq!(decode(&binary, 4, false).unwrap().pixels, vec![0u8; 4]);
2736 assert_eq!(check_of(&binary, 4, true), Check::ReeNoRunCountZero);
2737 assert_eq!(validate_stream(&binary, 4, false), Ok(binary.len()));
2739 assert_eq!(
2740 validate_stream(&binary, 4, true).unwrap_err().check(),
2741 Check::ReeNoRunCountZero
2742 );
2743
2744 let grayscale = [TAG_GRAYSCALE, 0x00];
2746 assert_eq!(decode(&grayscale, 4, false).unwrap().pixels, vec![0u8; 4]);
2747 assert_eq!(check_of(&grayscale, 4, true), Check::ReeNoRunCountZero);
2748
2749 assert_eq!(encode(&[0u8; 4], 4, EncodeMode::Binary).unwrap(), None);
2751 }
2752
2753 #[test]
2754 fn binary_run_lengths_split_loose_from_strict() {
2755 let empty_first = [TAG_BINARY, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02];
2758 assert_eq!(
2759 decode(&empty_first, 4, false).unwrap().pixels,
2760 vec![255, 255, 0, 0]
2761 );
2762 assert_eq!(check_of(&empty_first, 4, true), Check::ReeRunLengths);
2763
2764 let implicit_empty = [TAG_BINARY, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x04];
2767 assert_eq!(
2768 decode(&implicit_empty, 4, false).unwrap().pixels,
2769 vec![0, 0, 0, 0]
2770 );
2771 assert_eq!(check_of(&implicit_empty, 4, true), Check::ReeRunLengths);
2772
2773 let overshoot = [TAG_BINARY, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x05];
2776 assert_eq!(check_of(&overshoot, 4, false), Check::ReeEndPositions);
2777 assert_eq!(check_of(&overshoot, 4, true), Check::ReeEndPositions);
2778
2779 let too_many = [TAG_BINARY, 0x00, 0x06];
2781 assert_eq!(check_of(&too_many, 4, false), Check::ReeRunLengths);
2782 assert_eq!(
2783 check_of(&[TAG_GRAYSCALE, 0x06], 4, false),
2784 Check::ReeRunLengths
2785 );
2786
2787 let canonical = [TAG_BINARY, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x02];
2789 for strict in [false, true] {
2790 assert_eq!(
2791 decode(&canonical, 4, strict).unwrap().pixels,
2792 vec![0, 0, 255, 255]
2793 );
2794 }
2795 }
2796
2797 #[test]
2798 fn grayscale_run_rules_split_loose_from_strict() {
2799 let repeated = [
2802 TAG_GRAYSCALE,
2803 0x02,
2804 0x00,
2805 0x00,
2806 0x01,
2807 0x00,
2808 0x00,
2809 0x00,
2810 0x02,
2811 ];
2812 assert_eq!(
2813 decode(&repeated, 4, false).unwrap().pixels,
2814 vec![0, 0, 0, 0]
2815 );
2816 assert_eq!(check_of(&repeated, 4, true), Check::ReeGrayscaleRuns);
2817
2818 let empty_run = [
2821 TAG_GRAYSCALE,
2822 0x02,
2823 0x00,
2824 0x05,
2825 0x01,
2826 0x00,
2827 0x00,
2828 0x00,
2829 0x00,
2830 ];
2831 assert_eq!(
2832 decode(&empty_run, 4, false).unwrap().pixels,
2833 vec![5, 5, 5, 5]
2834 );
2835 assert_eq!(check_of(&empty_run, 4, true), Check::ReeGrayscaleRuns);
2836
2837 let implicit_empty = [
2840 TAG_GRAYSCALE,
2841 0x02,
2842 0x00,
2843 0x05,
2844 0x01,
2845 0x00,
2846 0x00,
2847 0x00,
2848 0x04,
2849 ];
2850 assert_eq!(
2851 decode(&implicit_empty, 4, false).unwrap().pixels,
2852 vec![0, 0, 0, 0]
2853 );
2854 assert_eq!(check_of(&implicit_empty, 4, true), Check::ReeGrayscaleRuns);
2855
2856 let past = [
2858 TAG_GRAYSCALE,
2859 0x02,
2860 0x00,
2861 0x05,
2862 0x01,
2863 0x00,
2864 0x00,
2865 0x00,
2866 0x05,
2867 ];
2868 assert_eq!(check_of(&past, 4, false), Check::ReeEndPositions);
2869 assert_eq!(check_of(&past, 4, true), Check::ReeEndPositions);
2870
2871 let binary_values = [
2873 TAG_GRAYSCALE,
2874 0x02,
2875 0x00,
2876 0xFF,
2877 0x01,
2878 0x00,
2879 0x00,
2880 0x00,
2881 0x02,
2882 ];
2883 assert_eq!(
2884 decode(&binary_values, 4, false).unwrap().pixels,
2885 vec![0, 0, 255, 255]
2886 );
2887 assert_eq!(
2888 check_of(&binary_values, 4, true),
2889 Check::ReeGrayscaleAllBinary
2890 );
2891
2892 let one_run = [TAG_GRAYSCALE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
2895 assert_eq!(decode(&one_run, 4, false).unwrap().pixels, vec![0u8; 4]);
2896 assert_eq!(check_of(&one_run, 4, true), Check::ReeGrayscaleAllBinary);
2897
2898 assert_eq!(
2900 validate_stream(&bytes(LAYER_GRAYSCALE), TOTAL, true),
2901 Ok(LAYER_GRAYSCALE.len() / 2)
2902 );
2903 }
2904
2905 const SPLIT_TOTAL: u32 = 8;
2907 const SPLIT_CANONICAL: [u8; 18] = [
2908 TAG_SPLIT, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, 0x01, 0xC8, 0xC8, ];
2913
2914 #[test]
2915 fn split_overlay_positions_are_delta_encoded() {
2916 let expected = [0, 0, 0, 0, 200, 200, 0, 0];
2917 for strict in [false, true] {
2918 assert_eq!(
2919 decode(&SPLIT_CANONICAL, SPLIT_TOTAL, strict)
2920 .unwrap()
2921 .pixels,
2922 expected
2923 );
2924 }
2925 assert_eq!(
2926 encode_split(&expected, SPLIT_TOTAL).unwrap(),
2927 SPLIT_CANONICAL
2928 );
2929 assert_eq!(&SPLIT_CANONICAL[14..16], &[0x04, 0x01]);
2931 }
2932
2933 #[test]
2934 fn split_overlay_rules_are_enforced() {
2935 let repeated = [
2938 TAG_SPLIT, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x00, 0x00,
2939 0x00, 0x04, 0x00, 0xC8, 0xC8,
2940 ];
2941 assert_eq!(
2942 check_of(&repeated, SPLIT_TOTAL, false),
2943 Check::ReeSplitPositions
2944 );
2945 assert_eq!(
2946 check_of(&repeated, SPLIT_TOTAL, true),
2947 Check::ReeSplitPositions
2948 );
2949
2950 let out_of_range = [
2951 TAG_SPLIT, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x00, 0x00,
2952 0x00, 0x08, 0x01, 0xC8, 0xC8,
2953 ];
2954 assert_eq!(
2955 check_of(&out_of_range, SPLIT_TOTAL, false),
2956 Check::ReeSplitPositions
2957 );
2958
2959 let too_many = [TAG_SPLIT, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06];
2962 assert_eq!(check_of(&too_many, 4, false), Check::ReeSplitPositions);
2963
2964 let short_values = [
2966 TAG_SPLIT, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04,
2967 ];
2968 assert_eq!(
2969 check_of(&short_values, SPLIT_TOTAL, false),
2970 Check::ReeVarint
2971 );
2972
2973 let wrong_threshold = [
2976 TAG_SPLIT, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x00, 0x00,
2977 0x00, 0x04, 0x01, 0x64, 0xC8,
2978 ];
2979 assert!(decode(&wrong_threshold, SPLIT_TOTAL, false).is_ok());
2980 assert_eq!(
2981 check_of(&wrong_threshold, SPLIT_TOTAL, true),
2982 Check::ReeSplitThreshold
2983 );
2984
2985 let white_overlay = [
2986 TAG_SPLIT, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x00, 0x00,
2987 0x00, 0x04, 0x01, 0xFF, 0xC8,
2988 ];
2989 assert_eq!(
2990 check_of(&white_overlay, SPLIT_TOTAL, true),
2991 Check::ReeSplitThreshold
2992 );
2993
2994 let no_overlay = [
3000 TAG_SPLIT, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
3001 ];
3002 let expected = mask(&[(0, 4), (255, 4)]);
3003 assert_eq!(
3004 decode(&no_overlay, SPLIT_TOTAL, false).unwrap().pixels,
3005 expected
3006 );
3007 assert_eq!(
3008 check_of(&no_overlay, SPLIT_TOTAL, true),
3009 Check::ReeSplitAllBinary
3010 );
3011 assert_eq!(encode_split(&expected, SPLIT_TOTAL).unwrap(), no_overlay);
3012
3013 let non_canonical_core = [TAG_SPLIT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
3015 assert_eq!(
3016 check_of(&non_canonical_core, SPLIT_TOTAL, true),
3017 Check::ReeNoRunCountZero
3018 );
3019 assert!(decode(&non_canonical_core, SPLIT_TOTAL, false).is_ok());
3020 }
3021
3022 fn planes(sizes: [u8; PLANES], bytes: &[u8]) -> Vec<u8> {
3025 let mut out = sizes.to_vec();
3026 out.extend_from_slice(bytes);
3027 out
3028 }
3029
3030 #[test]
3031 fn varint_bytes_are_laid_out_in_significance_planes() {
3032 let pixels = mask(&[(0, 100), (255, 300), (0, 3)]);
3036 let data = encode_binary(&pixels, 403).unwrap();
3037 let mut expected = vec![TAG_BINARY, 0x00, 0x03];
3038 expected.extend(planes([2, 1, 0, 0], &[100, 0xAC, 0x02]));
3039 assert_eq!(data, expected);
3040 assert_eq!(decode(&data, 403, true).unwrap().pixels, pixels);
3041
3042 let wide = mask(&[(0, 128), (255, 128)]);
3045 let data = encode_binary(&wide, 256).unwrap();
3046 let mut expected = vec![TAG_BINARY, 0x00, 0x02];
3047 expected.extend(planes([1, 1, 0, 0], &[0x80, 0x01]));
3048 assert_eq!(data, expected);
3049 assert_eq!(decode(&data, 256, true).unwrap().pixels, wide);
3050 }
3051
3052 #[test]
3053 fn planes_must_be_prefix_closed_and_exactly_used() {
3054 let not_prefix_closed = [TAG_BINARY, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x01];
3057 assert!(decode(¬_prefix_closed, 4, false).is_ok());
3058 assert_eq!(
3059 check_of(¬_prefix_closed, 4, true),
3060 Check::ReePlanes,
3061 "a non-empty plane may not follow an empty one"
3062 );
3063
3064 let leftover = [TAG_BINARY, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02];
3067 assert_eq!(
3068 decode(&leftover, 4, false).unwrap().pixels,
3069 vec![0, 0, 255, 255]
3070 );
3071 assert_eq!(check_of(&leftover, 4, true), Check::ReePlanes);
3072
3073 let too_many_planes = [
3075 TAG_BINARY, 0x00, 0x02, 0x01, 0x01, 0x01, 0x01, 0x80, 0x80, 0x80, 0x80,
3076 ];
3077 assert_eq!(check_of(&too_many_planes, 4, false), Check::ReeVarint);
3078
3079 let overlong = [TAG_BINARY, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x80, 0x00];
3082 assert_eq!(check_of(&overlong, 4, false), Check::ReeVarint);
3083
3084 let short = [TAG_BINARY, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00];
3087 assert_eq!(check_of(&short, 4, false), Check::ReeVarint);
3088
3089 let truncated = [TAG_BINARY, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00];
3092 assert_eq!(check_of(&truncated, 4, false), Check::ReeVarint);
3093 }
3094
3095 #[test]
3096 fn a_length_needing_a_fifth_plane_is_refused() {
3097 let total = (1u64 << 28) + 1;
3101 let runs = [Run::new(1 << 28, 0), Run::new(1, 255)];
3102 assert_eq!(
3103 encode_runs(&runs, total as u32, EncodeMode::Binary)
3104 .unwrap_err()
3105 .check(),
3106 Check::ReePlanes
3107 );
3108 assert_eq!(
3109 encode_runs(&runs, total as u32, EncodeMode::Grayscale)
3110 .unwrap_err()
3111 .check(),
3112 Check::ReePlanes
3113 );
3114
3115 let fits = [Run::new((1 << 28) - 1, 255), Run::new(1, 0)];
3118 let (_, data) = encode_runs(&fits, 1 << 28, EncodeMode::Binary)
3119 .unwrap()
3120 .unwrap();
3121 assert_eq!(data.len(), 2 + 1 + 4 + 4, "four plane bytes, one per plane");
3122 assert_eq!(&data[7..11], &[0xFF, 0xFF, 0xFF, 0x7F]);
3123 }
3124
3125 #[test]
3126 fn a_single_run_stream_carries_the_four_plane_lengths() {
3127 let one_run = [TAG_BINARY, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00];
3131 assert_eq!(validate_stream(&one_run, 7, true), Ok(one_run.len()));
3132 for strict in [false, true] {
3133 assert_eq!(decode(&one_run, 7, strict).unwrap().pixels, vec![255u8; 7]);
3134 }
3135
3136 let headerless = [TAG_BINARY, 0xFF, 0x01];
3139 assert_eq!(check_of(&headerless, 7, false), Check::ReeVarint);
3140
3141 let grayscale = [TAG_GRAYSCALE, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00];
3143 assert_eq!(validate_stream(&grayscale, 7, true), Ok(grayscale.len()));
3144 assert_eq!(decode(&grayscale, 7, true).unwrap().pixels, vec![0x80u8; 7]);
3145 assert_eq!(
3146 check_of(&[TAG_GRAYSCALE, 0x01, 0x80], 7, false),
3147 Check::ReeVarint
3148 );
3149
3150 let split = [
3154 TAG_SPLIT, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ];
3160 assert_eq!(validate_stream(&split, 7, true), Ok(split.len()));
3161 assert_eq!(decode(&split, 7, true).unwrap().pixels, vec![0x80u8; 7]);
3162
3163 let split = [
3167 TAG_SPLIT, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3168 ];
3169 assert_eq!(validate_stream(&split, 7, false), Ok(split.len()));
3170 assert_eq!(decode(&split, 7, false).unwrap().pixels, vec![0u8; 7]);
3171 assert_eq!(check_of(&split, 7, true), Check::ReeSplitAllBinary);
3172 }
3173
3174 #[test]
3175 fn a_split_over_an_all_binary_mask_is_strict_only() {
3176 let empty_overlay = [
3181 TAG_SPLIT, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
3182 ];
3183 let expected = mask(&[(0, 4), (255, 4)]);
3184 assert_eq!(
3185 decode(&empty_overlay, SPLIT_TOTAL, false).unwrap().pixels,
3186 expected
3187 );
3188 assert_eq!(
3189 check_of(&empty_overlay, SPLIT_TOTAL, true),
3190 Check::ReeSplitAllBinary
3191 );
3192 assert_eq!(
3193 validate_stream(&empty_overlay, SPLIT_TOTAL, true)
3194 .unwrap_err()
3195 .check(),
3196 Check::ReeSplitAllBinary
3197 );
3198
3199 let binary = encode_binary(&expected, SPLIT_TOTAL).unwrap();
3202 assert_eq!(
3203 validate_stream(&binary, SPLIT_TOTAL, true),
3204 Ok(binary.len())
3205 );
3206
3207 let grayscale = encode_grayscale(&expected, SPLIT_TOTAL).unwrap();
3210 assert_eq!(
3211 check_of(&grayscale, SPLIT_TOTAL, true),
3212 Check::ReeGrayscaleAllBinary
3213 );
3214
3215 let zero_overlay = [
3219 TAG_SPLIT, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00,
3220 0x04, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, ];
3225 assert_eq!(
3226 check_of(&zero_overlay, SPLIT_TOTAL, true),
3227 Check::ReeSplitThreshold
3228 );
3229 }
3230
3231 #[test]
3232 fn validate_stream_matches_decode() {
3233 assert_eq!(
3234 validate_stream(&bytes(LAYER_BINARY), TOTAL, true),
3235 Ok(LAYER_BINARY.len() / 2)
3236 );
3237 assert_eq!(
3238 validate_stream(&bytes(LAYER_SPLIT), TOTAL, true),
3239 Ok(LAYER_SPLIT.len() / 2)
3240 );
3241 assert_eq!(
3242 validate_stream(&[], TOTAL, false),
3243 Err(Error::new(
3244 Check::ReeTag,
3245 "layer mask data is empty: the empty-layer form carries no bytes"
3246 ))
3247 );
3248 }
3249
3250 fn covered(ranges: &[(u64, u64)], total: usize) -> Vec<bool> {
3252 let mut pixels = vec![false; total];
3253 for &(start, end) in ranges {
3254 for pixel in &mut pixels[start as usize..end as usize] {
3255 *pixel = true;
3256 }
3257 }
3258 pixels
3259 }
3260
3261 fn every_small_mask(total: usize, mut f: impl FnMut(&[u8])) {
3264 const ALPHABET: [u8; 5] = [0x00, 0x01, 0x7F, 0x80, 0xFF];
3265 let mut pixels = vec![0u8; total];
3266 for index in 0..ALPHABET.len().pow(total as u32) {
3267 let mut rest = index;
3268 for pixel in pixels.iter_mut() {
3269 *pixel = ALPHABET[rest % ALPHABET.len()];
3270 rest /= ALPHABET.len();
3271 }
3272 f(&pixels);
3273 }
3274 }
3275
3276 #[test]
3277 fn the_exposed_walk_matches_the_mask_it_decodes_to() {
3278 let mut compared = 0usize;
3279 for total in 1usize..=5 {
3280 every_small_mask(total, |pixels| {
3281 for mode in MODES {
3282 let Ok(Some((_, data))) = encode(pixels, total as u32, mode) else {
3283 continue;
3284 };
3285 let decoded = decode(&data, total as u32, true);
3291 let mut ranges: Vec<(u64, u64)> = Vec::new();
3292 let walked = exposed_ranges(&data, total as u32, |start, end| {
3293 ranges.push((start, end));
3294 Ok(())
3295 });
3296 match (decoded, walked) {
3297 (Ok(mask), Ok(())) => {
3298 assert_eq!(
3302 covered(&ranges, total),
3303 mask.pixels.iter().map(|p| *p != 0).collect::<Vec<_>>(),
3304 "{pixels:?} as {mode:?}"
3305 );
3306 }
3307 (Err(decoded), Err(walked)) => {
3308 assert_eq!(decoded.check(), walked.check(), "{pixels:?} as {mode:?}")
3309 }
3310 (decoded, walked) => {
3311 panic!("{pixels:?} as {mode:?}: {decoded:?} but {walked:?}")
3312 }
3313 }
3314 compared += 1;
3315 }
3316 });
3317 }
3318
3319 for hex in [LAYER_BINARY, LAYER_GRAYSCALE, LAYER_SPLIT] {
3323 let data = bytes(hex);
3324 for at in 0..data.len() {
3325 for byte in [0x00, 0x01, 0x7F, 0x80, 0xFF, 0x02] {
3326 for stream in [data[..at].to_vec(), {
3327 let mut changed = data.clone();
3328 changed[at] = byte;
3329 changed
3330 }] {
3331 let decoded = decode(&stream, TOTAL, true).is_ok();
3332 let walked = exposed_ranges(&stream, TOTAL, |_, _| Ok(())).is_ok();
3333 assert_eq!(
3334 decoded, walked,
3335 "{hex} with byte {at} set to 0x{byte:02X}: decoded {decoded}, \
3336 walked {walked}"
3337 );
3338 compared += 1;
3339 }
3340 }
3341 }
3342 }
3343 println!("{compared} streams compared");
3344 }
3345
3346 #[test]
3347 fn run_path_encodes_the_corpus_masks_byte_for_byte() {
3348 for (hex, spec, tag, chosen) in corpus_cases() {
3349 let pixels = mask(&spec);
3350 let runs = run_list(&spec);
3351 assert_eq!(
3352 encode_runs(&runs, TOTAL, chosen).unwrap(),
3353 Some((tag, bytes(hex))),
3354 "the corpus stream is what the run path must produce"
3355 );
3356 for mode in MODES {
3357 assert_run_path_matches(&pixels, &runs, TOTAL, mode);
3358 }
3359 }
3360 }
3361
3362 fn large_mask() -> Vec<u8> {
3365 const W: usize = 1920;
3366 const H: usize = 1080;
3367 const MARGIN: usize = 480;
3368 const RAMP: usize = 64;
3369 let mut pixels = vec![0u8; W * H];
3370 for row in 0..H {
3371 let line = &mut pixels[row * W..(row + 1) * W];
3372 for offset in 0..RAMP {
3373 line[MARGIN + offset] = (offset * 4) as u8;
3374 line[W - MARGIN - RAMP + offset] = 255 - (offset * 4) as u8;
3375 }
3376 line[MARGIN + RAMP..W - MARGIN - RAMP].fill(255);
3377 }
3378 pixels
3379 }
3380
3381 #[test]
3382 fn run_path_matches_the_pixel_path_on_a_large_anti_aliased_mask() {
3383 let pixels = large_mask();
3384 let runs = runs_of(&pixels);
3385 let total = pixels.len() as u32;
3386 assert_eq!(total, 1920 * 1080);
3387 assert!(
3388 pixels.iter().any(|pixel| *pixel != 0x00 && *pixel != 0xFF),
3389 "the mask must exercise the split overlay"
3390 );
3391 for mode in MODES {
3392 assert_run_path_matches(&pixels, &runs, total, mode);
3393 }
3394 }
3395
3396 #[test]
3397 fn run_path_matches_the_pixel_path_over_every_small_mask() {
3398 const ALPHABET: [u8; 5] = [0x00, 0x01, 0x7F, 0x80, 0xFF];
3404 let mut pixels = [0u8; 5];
3405 let mut counter = 0usize;
3406 while counter < ALPHABET.len().pow(pixels.len() as u32) {
3407 let mut rest = counter;
3408 for pixel in &mut pixels {
3409 *pixel = ALPHABET[rest % ALPHABET.len()];
3410 rest /= ALPHABET.len();
3411 }
3412 counter += 1;
3413 let runs = runs_of(&pixels);
3414 for mode in MODES {
3415 assert_run_path_matches(&pixels, &runs, 5, mode);
3416 }
3417 }
3418 }
3419
3420 #[test]
3421 fn split_core_merges_runs_that_threshold_alike() {
3422 let pixels = [90u8, 100, 90, 255, 255];
3426 let runs = runs_of(&pixels);
3427 assert_eq!(runs.len(), 4, "the mask's own runs do not merge");
3428 assert_eq!(runs[0], Run::new(1, 90));
3429 assert_eq!(runs[1], Run::new(1, 100));
3430 assert_run_path_matches(&pixels, &runs, 5, EncodeMode::Split);
3431 let (tag, data) = encode_runs(&runs, 5, EncodeMode::Split).unwrap().unwrap();
3434 assert_eq!(tag, TAG_SPLIT);
3435 assert_eq!(
3436 &data[..9],
3437 &[TAG_SPLIT, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x03, 0x03]
3438 );
3439 assert_eq!(decode(&data, 5, true).unwrap().pixels, pixels);
3440 }
3441
3442 #[test]
3443 fn run_path_rejects_non_canonical_runs() {
3444 assert_eq!(
3446 encode_runs(&[Run::new(0, 0), Run::new(4, 255)], 4, EncodeMode::Auto)
3447 .unwrap_err()
3448 .check(),
3449 Check::ReeRunLengths
3450 );
3451 assert_eq!(
3452 encode_runs(
3453 &[Run::new(4, 255), Run::new(0, 0)],
3454 4,
3455 EncodeMode::Grayscale
3456 )
3457 .unwrap_err()
3458 .check(),
3459 Check::ReeRunLengths
3460 );
3461
3462 for mode in MODES {
3464 assert_eq!(
3465 encode_runs(&[Run::new(2, 0), Run::new(2, 0)], 4, mode)
3466 .unwrap_err()
3467 .check(),
3468 Check::ReeGrayscaleRuns,
3469 "mode {mode:?}"
3470 );
3471 }
3472 assert_eq!(
3473 encode_runs(
3474 &[Run::new(1, 200), Run::new(1, 200), Run::new(2, 0)],
3475 4,
3476 EncodeMode::Split
3477 )
3478 .unwrap_err()
3479 .check(),
3480 Check::ReeGrayscaleRuns
3481 );
3482
3483 for runs in [
3485 vec![Run::new(2, 0), Run::new(1, 255)],
3486 vec![Run::new(5, 255)],
3487 vec![],
3488 ] {
3489 assert_eq!(
3490 encode_runs(&runs, 4, EncodeMode::Auto).unwrap_err().check(),
3491 Check::ReeDataSize
3492 );
3493 }
3494
3495 assert_eq!(encode_runs(&[], 0, EncodeMode::Auto).unwrap(), None);
3498 assert_eq!(
3499 encode_runs(&[Run::new(4, 0)], 4, EncodeMode::Auto).unwrap(),
3500 None
3501 );
3502 assert_eq!(
3503 encode_runs(&[Run::new(1, 0), Run::new(3, 0)], 4, EncodeMode::Auto)
3504 .unwrap_err()
3505 .check(),
3506 Check::ReeGrayscaleRuns
3507 );
3508
3509 assert_eq!(
3511 encode_runs(&[Run::new(1, 0), Run::new(3, 7)], 4, EncodeMode::Binary)
3512 .unwrap_err()
3513 .check(),
3514 Check::ReeFirstValue
3515 );
3516 assert_eq!(
3517 encode_runs(&[Run::new(4, 7)], 4, EncodeMode::Binary)
3518 .unwrap_err()
3519 .check(),
3520 Check::ReeFirstValue
3521 );
3522 }
3523}