use crate::check::Check;
use crate::error::{Error, Result};
use crate::io::{Reader, Writer};
pub const TAG_BINARY: u8 = 0x00;
pub const TAG_GRAYSCALE: u8 = 0x01;
pub const TAG_SPLIT: u8 = 0x02;
pub const TAG_ATTACHED: u8 = 0x03;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum EncodeMode {
#[default]
Auto,
Binary,
Grayscale,
Split,
Attached,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Run {
pub length: u32,
pub value: u8,
}
impl Run {
pub fn new(length: u32, value: u8) -> Self {
Run { length, value }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DecodedLayer {
pub pixels: Vec<u8>,
pub tag: Option<u8>,
}
impl DecodedLayer {
pub fn empty(total_pixels: u32) -> DecodedLayer {
DecodedLayer {
pixels: vec![0u8; total_pixels as usize],
tag: None,
}
}
pub fn is_empty(&self) -> bool {
self.tag.is_none()
}
pub fn is_binary(&self) -> bool {
self.pixels.iter().all(|p| *p == 0 || *p == 255)
}
}
pub fn threshold(pixel: u8) -> u8 {
if pixel >= 128 {
255
} else {
0
}
}
pub fn decode(data: &[u8], total_pixels: u32, strict: bool) -> Result<DecodedLayer> {
decode_counted(data, total_pixels, strict).map(|(layer, _)| layer)
}
pub fn decode_counted(
data: &[u8],
total_pixels: u32,
strict: bool,
) -> Result<(DecodedLayer, usize)> {
let (tag, mut reader) = tag_and_stream(data)?;
let mut pixels = vec![0u8; total_pixels as usize];
read(
tag,
Sink::Mask(&mut pixels),
&mut reader,
total_pixels,
strict,
)?;
Ok((
DecodedLayer {
pixels,
tag: Some(tag),
},
1 + reader.pos(),
))
}
fn tag_and_stream(data: &[u8]) -> Result<(u8, Reader<'_>)> {
let Some((&tag, stream)) = data.split_first() else {
return Err(Error::new(
Check::ReeTag,
"layer mask data is empty: the empty-layer form carries no bytes",
));
};
match tag {
TAG_BINARY | TAG_GRAYSCALE | TAG_SPLIT | TAG_ATTACHED => {}
other => {
return Err(Error::new(
Check::ReeTag,
format!("unknown layer encoding tag 0x{other:02X}"),
))
}
}
Ok((tag, Reader::checked(stream, Check::ReeVarint)))
}
fn read(
tag: u8,
sink: Sink<'_>,
reader: &mut Reader<'_>,
total_pixels: u32,
strict: bool,
) -> Result<()> {
match tag {
TAG_BINARY => read_binary(sink, reader, total_pixels, strict),
TAG_GRAYSCALE => read_grayscale(sink, reader, total_pixels, strict),
TAG_SPLIT => read_split(sink, reader, total_pixels, strict),
TAG_ATTACHED => read_attached(sink, reader, total_pixels, strict),
_ => unreachable!("tag_and_stream accepts 0x00, 0x01, 0x02 and 0x03 only"),
}
}
fn read_run_count(reader: &mut Reader<'_>, total_pixels: u64) -> Result<u64> {
let bound = total_pixels + 1;
let run_count = reader.varint()?;
if run_count > bound {
return Err(Error::new(
Check::ReeRunLengths,
format!("run_count {run_count} exceeds total_pixels + 1 ({bound})"),
));
}
Ok(run_count)
}
const PLANES: usize = 4;
struct Planes<'a> {
planes: [&'a [u8]; PLANES],
at: [usize; PLANES],
}
impl<'a> Planes<'a> {
fn read(reader: &mut Reader<'a>, strict: bool) -> Result<Planes<'a>> {
let mut lengths = [0usize; PLANES];
for (plane, length) in lengths.iter_mut().enumerate() {
let value = reader.varint()?;
*length = usize::try_from(value).map_err(|_| {
Error::new(
Check::ReePlanes,
format!("plane {plane} length {value} does not fit in memory"),
)
})?;
}
if strict {
for plane in 1..PLANES {
if lengths[plane] > 0 && lengths[plane - 1] == 0 {
return Err(Error::new(
Check::ReePlanes,
format!(
"plane {plane} holds {} bytes after empty plane {}: the planes are \
not prefix-closed",
lengths[plane],
plane - 1
),
));
}
}
}
let mut planes = [&[][..]; PLANES];
for (plane, length) in planes.iter_mut().zip(lengths) {
*plane = reader.bytes(length)?;
}
Ok(Planes {
planes,
at: [0; PLANES],
})
}
fn empty() -> Planes<'a> {
Planes {
planes: [&[]; PLANES],
at: [0; PLANES],
}
}
fn rewind(&self) -> Planes<'a> {
Planes {
planes: self.planes,
at: [0; PLANES],
}
}
fn next(&mut self) -> Result<Option<u64>> {
if self.at[0] == self.planes[0].len() {
return Ok(None);
}
let mut value = 0u64;
for plane in 0..PLANES {
let Some(&byte) = self.planes[plane].get(self.at[plane]) else {
return Err(Error::new(
Check::ReeVarint,
format!("a varint continues into plane {plane}, which holds no more bytes"),
));
};
self.at[plane] += 1;
value |= u64::from(byte & 0x7F) << (7 * plane);
if byte & 0x80 == 0 {
if plane > 0 && byte == 0 {
return Err(Error::new(
Check::ReeVarint,
"a varint crossing planes is not minimally encoded",
));
}
return Ok(Some(value));
}
}
Err(Error::new(
Check::ReeVarint,
"a varint continues past plane 3, which is the last plane",
))
}
fn varint(&mut self) -> Result<u64> {
self.next()?.ok_or_else(|| {
Error::new(
Check::ReeVarint,
"the planes hold fewer varints than the stream's count",
)
})
}
fn check_consumed(&self) -> Result<()> {
for plane in 0..PLANES {
let len = self.planes[plane].len();
if self.at[plane] != len {
return Err(Error::new(
Check::ReePlanes,
format!(
"plane {plane} holds {len} bytes, {} of which describe a varint",
self.at[plane]
),
));
}
}
Ok(())
}
}
enum Sink<'m> {
Mask(&'m mut [u8]),
Exposed(&'m mut dyn FnMut(u64, u64) -> Result<()>),
None,
}
impl Sink<'_> {
#[inline]
fn fill(&mut self, start: u64, end: u64, value: u8) -> Result<()> {
match self {
Sink::Mask(mask) => mask[start as usize..end as usize].fill(value),
Sink::Exposed(report) => {
if value != 0x00 && start < end {
report(start, end)?;
}
}
Sink::None => {}
}
Ok(())
}
#[inline]
fn set(&mut self, position: u64, value: u8) -> Result<()> {
match self {
Sink::Mask(mask) => mask[position as usize] = value,
Sink::Exposed(report) => {
if value != 0x00 {
report(position, position + 1)?;
}
}
Sink::None => {}
}
Ok(())
}
}
struct Runs<'a> {
lengths: LengthSource<'a>,
left: u64,
start: u64,
end: u64,
walked: u64,
total: u64,
kind: &'static str,
empty: bool,
}
impl<'a> Runs<'a> {
fn new(lengths: LengthSource<'a>, count: u64, total: u64, kind: &'static str) -> Runs<'a> {
Runs {
lengths,
left: count,
start: 0,
end: 0,
walked: 0,
total,
kind,
empty: false,
}
}
fn step(&mut self) -> Result<Option<u64>> {
if self.left == 0 {
return Ok(None);
}
self.left -= 1;
let end = if self.left == 0 {
self.total
} else {
let index = self.walked;
self.end
.checked_add(self.lengths.next(index)?)
.ok_or_else(|| {
Error::new(
Check::ReeEndPositions,
format!("{} run lengths overflow", self.kind),
)
})?
};
let (start, index) = (self.end, self.walked);
if end > self.total {
return Err(Error::new(
Check::ReeEndPositions,
format!(
"{} run {index} ends at {end}, past total_pixels {}",
self.kind, self.total
),
));
}
self.empty |= end == start;
self.start = start;
self.end = end;
self.walked = index + 1;
Ok(Some(index))
}
fn seek(&mut self, position: u64) -> Result<u64> {
while self.end <= position {
if self.step()?.is_none() {
return Err(Error::new(
Check::ReeEndPositions,
format!("{} holds no run covering pixel {position}", self.kind),
));
}
}
Ok(self.walked.saturating_sub(1))
}
fn range(&self) -> (u64, u64) {
(self.start, self.end)
}
fn empty_run(&self) -> bool {
self.empty
}
fn check_consumed(&self) -> Result<()> {
self.lengths.check_consumed()
}
}
enum LengthSource<'a> {
Planes(Planes<'a>),
Parity(Parity<'a>),
}
impl LengthSource<'_> {
fn next(&mut self, index: u64) -> Result<u64> {
match self {
LengthSource::Planes(planes) => planes.varint(),
LengthSource::Parity(parity) => {
let length = parity.next(index)?;
u64::try_from(length).map_err(|_| {
Error::new(
Check::ReeEndPositions,
format!("attached REE run {index} has a negative length"),
)
})
}
}
}
fn check_consumed(&self) -> Result<()> {
match self {
LengthSource::Planes(planes) => planes.check_consumed(),
LengthSource::Parity(parity) => {
parity.streams[0].check_consumed()?;
parity.streams[1].check_consumed()
}
}
}
}
struct Parity<'a> {
streams: [Planes<'a>; 2],
last: [i64; 2],
}
impl<'a> Parity<'a> {
fn read(reader: &mut Reader<'a>, strict: bool) -> Result<Parity<'a>> {
Ok(Parity {
streams: [Planes::read(reader, strict)?, Planes::read(reader, strict)?],
last: [0; 2],
})
}
fn next(&mut self, index: u64) -> Result<i64> {
let parity = (index % 2) as usize;
let stored = self.streams[parity].varint()?;
if index < 2 {
let length = i64::try_from(stored).map_err(|_| {
Error::new(
Check::ReeEndPositions,
format!("attached REE run {index} is {stored} pixels long"),
)
})?;
self.last[parity] = length;
return Ok(length);
}
let length = self.last[parity]
.checked_add(unzigzag(stored))
.ok_or_else(|| {
Error::new(Check::ReeEndPositions, "attached REE run lengths overflow")
})?;
self.last[parity] = length;
Ok(length)
}
}
#[inline]
fn zigzag(value: i64) -> u64 {
((value as u64) << 1) ^ ((value >> 63) as u64)
}
#[inline]
fn unzigzag(value: u64) -> i64 {
((value >> 1) as i64) ^ -((value & 1) as i64)
}
struct Core<'a> {
first_value: u8,
count: u64,
total: u64,
planes: Planes<'a>,
}
impl<'a> Core<'a> {
fn read(reader: &mut Reader<'a>, total_pixels: u32, strict: bool) -> Result<Core<'a>> {
let total = u64::from(total_pixels);
let first_value = reader.u8()?;
if first_value != 0x00 && first_value != 0xFF {
return Err(Error::new(
Check::ReeFirstValue,
format!("binary REE first_value is 0x{first_value:02X}, not 0x00 or 0xFF"),
));
}
let count = read_run_count(reader, total)?;
if count == 0 {
if strict {
return Err(Error::new(
Check::ReeNoRunCountZero,
"binary REE uses the non-canonical run_count == 0 form",
));
}
return Ok(Core {
first_value: 0x00,
count: 1,
total,
planes: Planes::empty(),
});
}
Ok(Core {
first_value,
count,
total,
planes: Planes::read(reader, strict)?,
})
}
#[inline]
fn value(&self, index: u64) -> u8 {
if index % 2 == 0 {
self.first_value
} else {
255 - self.first_value
}
}
fn runs(&self) -> Runs<'a> {
Runs::new(
LengthSource::Planes(self.planes.rewind()),
self.count,
self.total,
"binary REE",
)
}
fn apply(&self, sink: &mut Sink<'_>, strict: bool) -> Result<()> {
let mut runs = self.runs();
while let Some(index) = runs.step()? {
let (start, end) = runs.range();
sink.fill(start, end, self.value(index))?;
}
if strict {
if runs.empty_run() {
return Err(Error::new(
Check::ReeRunLengths,
"binary REE stores an empty run",
));
}
runs.check_consumed()?;
}
Ok(())
}
}
fn read_binary(
mut sink: Sink<'_>,
reader: &mut Reader<'_>,
total_pixels: u32,
strict: bool,
) -> Result<()> {
Core::read(reader, total_pixels, strict)?.apply(&mut sink, strict)
}
fn read_grayscale(
mut sink: Sink<'_>,
reader: &mut Reader<'_>,
total_pixels: u32,
strict: bool,
) -> Result<()> {
let total = u64::from(total_pixels);
let run_count = read_run_count(reader, total)?;
if run_count == 0 {
if strict {
return Err(Error::new(
Check::ReeNoRunCountZero,
"grayscale REE uses the non-canonical run_count == 0 form",
));
}
return sink.fill(0, total, 0x00);
}
let values = reader.bytes(run_count as usize)?;
let mut runs = Runs::new(
LengthSource::Planes(Planes::read(reader, strict)?),
run_count,
total,
"grayscale REE",
);
let mut previous: Option<u8> = None;
while let Some(index) = runs.step()? {
let (start, end) = runs.range();
let value = values[index as usize];
if strict && previous == Some(value) {
return Err(Error::new(
Check::ReeGrayscaleRuns,
format!("grayscale REE repeats value 0x{value:02X} in adjacent runs"),
));
}
sink.fill(start, end, value)?;
previous = Some(value);
}
if strict {
if runs.empty_run() {
return Err(Error::new(
Check::ReeGrayscaleRuns,
"grayscale REE stores a zero-length run",
));
}
runs.check_consumed()?;
if values.iter().all(|value| *value == 0x00 || *value == 0xFF) {
return Err(Error::new(
Check::ReeGrayscaleAllBinary,
"grayscale REE holds only 0x00/0xFF pixels; such a layer must use tag 0x00",
));
}
}
Ok(())
}
fn walk_positions(
planes: &mut Planes<'_>,
count: u64,
total: u64,
mut f: impl FnMut(u64, usize) -> Result<()>,
) -> Result<()> {
let mut position = 0u64;
for i in 0..count {
let delta = planes.varint()?;
position = position.checked_add(delta).ok_or_else(|| {
Error::new(Check::ReeSplitPositions, "split overlay positions overflow")
})?;
if i > 0 && delta == 0 {
return Err(Error::new(
Check::ReeSplitPositions,
format!("split overlay position {position} repeats its predecessor"),
));
}
if position >= total {
return Err(Error::new(
Check::ReeSplitPositions,
format!("split overlay position {position} is not below total_pixels {total}"),
));
}
f(position, i as usize)?;
}
Ok(())
}
fn read_split(
mut sink: Sink<'_>,
reader: &mut Reader<'_>,
total_pixels: u32,
strict: bool,
) -> Result<()> {
let total = u64::from(total_pixels);
let core = Core::read(reader, total_pixels, strict)?;
core.apply(&mut sink, strict)?;
let aa_count = reader.varint()?;
let bound = total + 1;
if aa_count > bound {
return Err(Error::new(
Check::ReeSplitPositions,
format!("aa_pixel_count {aa_count} exceeds total_pixels + 1 ({bound})"),
));
}
let positions = Planes::read(reader, strict)?;
let values = reader.bytes(aa_count as usize)?;
if strict {
let mut checked = positions.rewind();
walk_positions(&mut checked, aa_count, total, |_, _| Ok(()))?;
checked.check_consumed()?;
let mut runs = core.runs();
walk_positions(&mut positions.rewind(), aa_count, total, |position, i| {
let value = values[i];
let binary = core.value(runs.seek(position)?);
if value == 0x00 || value == 0xFF || threshold(value) != binary {
return Err(Error::new(
Check::ReeSplitThreshold,
format!(
"split overlay pixel {position} holds 0x{value:02X} over binary \
0x{binary:02X}"
),
));
}
Ok(())
})?;
if aa_count == 0 {
return Err(Error::new(
Check::ReeSplitAllBinary,
"split REE holds only 0x00/0xFF pixels: it has no anti-aliasing to overlay, \
and such a layer must use tag 0x00",
));
}
}
walk_positions(&mut positions.rewind(), aa_count, total, |position, i| {
sink.set(position, values[i])
})
}
struct AttachBits<'a> {
bytes: &'a [u8],
}
impl<'a> AttachBits<'a> {
fn read(reader: &mut Reader<'a>, runs: u64) -> Result<AttachBits<'a>> {
Ok(AttachBits {
bytes: reader.bytes(runs.div_ceil(4) as usize)?,
})
}
fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
#[inline]
fn get(&self, index: u64, end: u64) -> bool {
self.bytes[(index / 4) as usize] & (1 << ((index % 4) * 2 + end)) != 0
}
fn padding_clear(&self, runs: u64) -> bool {
match runs % 4 {
0 => true,
used => {
let last = self.bytes[(runs / 4) as usize];
last & (!0u8 << (used * 2)) == 0
}
}
}
}
struct AttachValues<'a> {
planes: Planes<'a>,
index: u64,
previous: u8,
}
impl<'a> AttachValues<'a> {
fn read(reader: &mut Reader<'a>, strict: bool) -> Result<AttachValues<'a>> {
Ok(AttachValues {
planes: Planes::read(reader, strict)?,
index: 0,
previous: 0,
})
}
fn next_within(&mut self, count: u64) -> Result<u8> {
if self.index == count {
return Err(Error::new(
Check::ReeAttachCount,
format!(
"the attachment bits and escapes describe more overlay pixels than the {count} the stream stores values for"
),
));
}
let stored = self.planes.varint()?;
let value = if self.index == 0 {
u8::try_from(stored).map_err(|_| {
Error::new(
Check::ReeAttachCount,
format!("attached REE overlay value {stored} is not a byte"),
)
})?
} else {
let sum = i64::from(self.previous) + unzigzag(stored);
u8::try_from(sum).map_err(|_| {
Error::new(
Check::ReeAttachCount,
format!("attached REE overlay value {sum} is not a byte"),
)
})?
};
self.index += 1;
self.previous = value;
Ok(value)
}
}
fn check_attached_value(value: u8, core_value: u8, position: u64) -> Result<()> {
if value == 0x00 || value == 0xFF || threshold(value) != core_value {
return Err(Error::new(
Check::ReeAttachThreshold,
format!(
"attached REE overlay pixel {position} holds 0x{value:02X} over binary 0x{core_value:02X}"
),
));
}
Ok(())
}
fn read_attached(
mut sink: Sink<'_>,
reader: &mut Reader<'_>,
total_pixels: u32,
strict: bool,
) -> Result<()> {
let total = u64::from(total_pixels);
let declared_value = reader.u8()?;
if declared_value != 0x00 && declared_value != 0xFF {
return Err(Error::new(
Check::ReeFirstValue,
format!("attached REE first_value is 0x{declared_value:02X}, not 0x00 or 0xFF"),
));
}
let run_count = read_run_count(reader, total)?;
if run_count == 0 && strict {
return Err(Error::new(
Check::ReeNoRunCountZero,
"attached REE uses the non-canonical run_count == 0 form",
));
}
let first_value = if run_count == 0 { 0x00 } else { declared_value };
let mut runs = Runs::new(
LengthSource::Parity(Parity::read(reader, strict)?),
run_count.max(1),
total,
"attached REE",
);
let aa_count = reader.varint()?;
let bound = total + 1;
if aa_count > bound {
return Err(Error::new(
Check::ReeAttachCount,
format!("aa_pixel_count {aa_count} exceeds total_pixels + 1 ({bound})"),
));
}
let bits = AttachBits::read(reader, run_count)?;
let escape_count = reader.varint()?;
if escape_count > aa_count {
return Err(Error::new(
Check::ReeAttachCount,
format!("escape_count {escape_count} exceeds aa_pixel_count {aa_count}"),
));
}
let mut escapes = Planes::read(reader, strict)?;
let mut values = AttachValues::read(reader, strict)?;
let mut placed = 0u64;
let mut previous_escape = 0u64;
let mut escape_index = 0u64;
let mut pending: Option<u64> = None;
while let Some(index) = runs.step()? {
let (start, end) = runs.range();
let core_value = if index % 2 == 0 {
first_value
} else {
255 - first_value
};
sink.fill(start, end, core_value)?;
let empty = start == end;
if !empty && !bits.is_empty() && bits.get(index, 0) {
let value = values.next_within(aa_count)?;
if strict {
check_attached_value(value, core_value, start)?;
}
sink.set(start, value)?;
placed += 1;
}
loop {
let position = match pending {
Some(position) => position,
None => {
if escape_index == escape_count {
break;
}
let delta = escapes.varint()?;
if escape_index > 0 && delta == 0 {
return Err(Error::new(
Check::ReeAttachPositions,
format!("attached REE escape {escape_index} repeats its predecessor"),
));
}
let position = previous_escape.checked_add(delta).ok_or_else(|| {
Error::new(
Check::ReeAttachPositions,
"attached REE escape positions overflow",
)
})?;
if position >= total {
return Err(Error::new(
Check::ReeAttachPositions,
format!(
"attached REE escape {position} is not below total_pixels {total}"
),
));
}
previous_escape = position;
escape_index += 1;
pending = Some(position);
continue;
}
};
if position >= end {
break;
}
if position == start || position + 1 == end {
return Err(Error::new(
Check::ReeAttachPositions,
format!(
"attached REE escape {position} is not strictly inside the core run [{start}, {end}) it attaches to"
),
));
}
let value = values.next_within(aa_count)?;
if strict {
check_attached_value(value, core_value, position)?;
}
sink.set(position, value)?;
placed += 1;
pending = None;
}
if !empty && !bits.is_empty() && bits.get(index, 1) {
if strict && end - start == 1 {
return Err(Error::new(
Check::ReeAttachBits,
format!("attached REE run {index} holds one pixel and sets both of its bits"),
));
}
let value = values.next_within(aa_count)?;
if strict {
check_attached_value(value, core_value, end - 1)?;
}
sink.set(end - 1, value)?;
placed += 1;
}
}
if let Some(position) = pending {
return Err(Error::new(
Check::ReeAttachPositions,
format!("attached REE escape {position} sits past the last core run"),
));
}
if placed != aa_count {
return Err(Error::new(
Check::ReeAttachCount,
format!(
"the attachment bits and escapes describe {placed} overlay pixels, aa_pixel_count says {aa_count}"
),
));
}
if strict {
if runs.empty_run() {
return Err(Error::new(
Check::ReeRunLengths,
"attached REE stores an empty run",
));
}
runs.check_consumed()?;
escapes.check_consumed()?;
values.planes.check_consumed()?;
if !bits.padding_clear(run_count) {
return Err(Error::new(
Check::ReeAttachBits,
"attached REE sets attachment bits past the last run",
));
}
}
Ok(())
}
fn check_mask(pixels: &[u8], total_pixels: u32) -> Result<()> {
if pixels.len() != total_pixels as usize {
return Err(Error::new(
Check::ReeDataSize,
format!(
"mask holds {} pixels, total_pixels is {total_pixels}",
pixels.len()
),
));
}
Ok(())
}
fn require_pixels(pixels: &[u8]) -> Result<()> {
if pixels.is_empty() {
return Err(Error::new(
Check::ReeDataSize,
"a zero-pixel layer has no encodable stream: it is the empty-layer form",
));
}
Ok(())
}
fn check_runs(runs: &[Run], total_pixels: u32) -> Result<()> {
let mut covered = 0u64;
let mut previous: Option<u8> = None;
for run in runs {
if run.length == 0 {
return Err(Error::new(
Check::ReeRunLengths,
"run length 0: a run covers at least one pixel",
));
}
if previous == Some(run.value) {
return Err(Error::new(
Check::ReeGrayscaleRuns,
format!(
"adjacent runs both carry 0x{:02X}: they are a single run",
run.value
),
));
}
covered += u64::from(run.length);
previous = Some(run.value);
}
if covered != u64::from(total_pixels) {
return Err(Error::new(
Check::ReeDataSize,
format!("runs cover {covered} pixels, total_pixels is {total_pixels}"),
));
}
Ok(())
}
#[derive(Clone, Copy)]
enum RunSource<'a> {
Pixels(&'a [u8]),
Runs(&'a [Run]),
}
impl RunSource<'_> {
fn walk<F>(self, map: impl Fn(u8) -> u8 + Copy, mut f: F) -> Result<()>
where
F: FnMut(u64, u8) -> Result<()>,
{
match self {
RunSource::Pixels(pixels) => {
let mut pixels = pixels.iter().copied();
let Some(first) = pixels.next() else {
return Ok(());
};
let mut value = map(first);
let mut length = 1u64;
for pixel in pixels {
let mapped = map(pixel);
if mapped == value {
length += 1;
continue;
}
f(length, value)?;
value = mapped;
length = 1;
}
f(length, value)
}
RunSource::Runs(runs) => {
let mut pending: Option<(u64, u8)> = None;
for run in runs {
let value = map(run.value);
match pending {
Some((length, previous)) if previous == value => {
pending = Some((length + u64::from(run.length), value));
}
Some((length, previous)) => {
f(length, previous)?;
pending = Some((u64::from(run.length), value));
}
None => pending = Some((u64::from(run.length), value)),
}
}
match pending {
Some((length, value)) => f(length, value),
None => Ok(()),
}
}
}
}
fn is_all_black(self) -> bool {
match self {
RunSource::Pixels(pixels) => pixels.iter().all(|pixel| *pixel == 0),
RunSource::Runs(runs) => runs.iter().all(|run| run.value == 0),
}
}
fn is_binary(self) -> bool {
match self {
RunSource::Pixels(pixels) => pixels.iter().all(|pixel| *pixel == 0 || *pixel == 255),
RunSource::Runs(runs) => runs.iter().all(|run| run.value == 0 || run.value == 255),
}
}
}
#[derive(Debug, Default, Clone, Copy)]
struct PlaneSizes([u64; PLANES]);
impl PlaneSizes {
fn add(&mut self, value: u64) {
let len = crate::varint::encoded_len(value).min(PLANES);
for size in &mut self.0[..len] {
*size += 1;
}
}
fn write(&self, writer: &mut Writer) {
for size in self.0 {
writer.varint(size);
}
}
}
fn write_plane_byte(writer: &mut Writer, value: u64, plane: usize) -> Result<()> {
let shifted = value >> (7 * plane);
if plane > 0 && shifted == 0 {
return Ok(());
}
let more = shifted >= 0x80;
if more && plane + 1 == PLANES {
return Err(Error::new(
Check::ReePlanes,
format!("the value {value} needs more than {PLANES} significance planes"),
));
}
writer.u8((shifted & 0x7F) as u8 | if more { 0x80 } else { 0 });
Ok(())
}
fn write_planes(
writer: &mut Writer,
sizes: PlaneSizes,
mut walk: impl FnMut(&mut Writer, usize) -> Result<()>,
) -> Result<()> {
sizes.write(writer);
for plane in 0..PLANES {
walk(writer, plane)?;
}
Ok(())
}
fn write_binary_stream(
writer: &mut Writer,
source: RunSource<'_>,
map: impl Fn(u8) -> u8 + Copy,
) -> Result<()> {
let mut first_value: Option<u8> = None;
let mut last: Option<u8> = None;
let mut run_count = 0u64;
let mut sizes = PlaneSizes::default();
let mut pending: Option<u64> = None;
source.walk(map, |length, value| {
match last {
None => {
if value != 0x00 && value != 0xFF {
return Err(Error::new(
Check::ReeFirstValue,
format!("binary REE first_value is 0x{value:02X}, not 0x00 or 0xFF"),
));
}
first_value = Some(value);
}
Some(previous) if value != 255 - previous => {
return Err(Error::new(
Check::ReeFirstValue,
format!("binary REE cannot hold pixel 0x{value:02X}"),
));
}
Some(_) => {}
}
last = Some(value);
run_count += 1;
if let Some(previous) = pending.replace(length) {
sizes.add(previous);
}
Ok(())
})?;
let Some(first_value) = first_value else {
return Err(Error::new(
Check::ReeDataSize,
"a binary stream needs at least one pixel",
));
};
writer.u8(first_value);
writer.varint(run_count);
write_planes(writer, sizes, |writer, plane| {
let mut remaining = run_count;
source.walk(map, |length, _| {
remaining -= 1;
if remaining > 0 {
write_plane_byte(writer, length, plane)?;
}
Ok(())
})
})
}
fn write_grayscale_stream(writer: &mut Writer, source: RunSource<'_>) -> Result<()> {
let mut run_count = 0u64;
let mut sizes = PlaneSizes::default();
let mut pending: Option<u64> = None;
source.walk(
|value| value,
|length, _| {
run_count += 1;
if let Some(previous) = pending.replace(length) {
sizes.add(previous);
}
Ok(())
},
)?;
writer.varint(run_count);
source.walk(
|value| value,
|_, value| {
writer.u8(value);
Ok(())
},
)?;
write_planes(writer, sizes, |writer, plane| {
let mut remaining = run_count;
source.walk(
|value| value,
|length, _| {
remaining -= 1;
if remaining > 0 {
write_plane_byte(writer, length, plane)?;
}
Ok(())
},
)
})
}
fn write_split_stream(writer: &mut Writer, source: RunSource<'_>) -> Result<()> {
write_binary_stream(writer, source, threshold)?;
let mut count = 0u64;
let mut sizes = PlaneSizes::default();
let mut start = 0u64;
let mut previous = 0u64;
source.walk(
|value| value,
|length, value| {
if value != 0x00 && value != 0xFF {
count += length;
sizes.add(start - previous);
for _ in 1..length {
sizes.add(1);
}
previous = start + length - 1;
}
start += length;
Ok(())
},
)?;
writer.varint(count);
write_planes(writer, sizes, |writer, plane| {
let mut start = 0u64;
let mut previous = 0u64;
source.walk(
|value| value,
|length, value| {
if value != 0x00 && value != 0xFF {
write_plane_byte(writer, start - previous, plane)?;
for _ in 1..length {
write_plane_byte(writer, 1, plane)?;
}
previous = start + length - 1;
}
start += length;
Ok(())
},
)
})?;
source.walk(
|value| value,
|length, value| {
if value != 0x00 && value != 0xFF {
for _ in 0..length {
writer.u8(value);
}
}
Ok(())
},
)
}
#[inline]
fn is_aa(value: u8) -> bool {
value != 0x00 && value != 0xFF
}
struct StoredLengths {
last: [u64; 2],
index: u64,
}
impl StoredLengths {
fn new() -> StoredLengths {
StoredLengths {
last: [0; 2],
index: 0,
}
}
fn next(&mut self, length: u64) -> (u64, usize) {
let parity = (self.index % 2) as usize;
let value = if self.index < 2 {
length
} else {
zigzag(length as i64 - self.last[parity] as i64)
};
self.last[parity] = length;
self.index += 1;
(value, parity)
}
}
fn walk_overlay(
source: RunSource<'_>,
mut run: impl FnMut(u64, bool, bool) -> Result<()>,
mut escape: impl FnMut(u64, u64) -> Result<()>,
) -> Result<()> {
let mut index = 0u64;
let mut at = 0u64;
let mut start = 0u64;
let mut mapped: Option<u8> = None;
let mut first_aa = false;
let mut pending: Option<u64> = None;
let mut previous_escape = 0u64;
source.walk(
|value| value,
|length, value| {
let binary = threshold(value);
if mapped != Some(binary) {
if mapped.is_some() {
run(index, first_aa, pending.is_some())?;
index += 1;
}
mapped = Some(binary);
start = at;
first_aa = is_aa(value);
pending = None;
}
if is_aa(value) {
for position in at..at + length {
if position == start && first_aa {
continue;
}
if let Some(previous) = pending.take() {
escape(previous, previous - previous_escape)?;
previous_escape = previous;
}
pending = Some(position);
}
} else if let Some(previous) = pending.take() {
escape(previous, previous - previous_escape)?;
previous_escape = previous;
}
at += length;
Ok(())
},
)?;
if mapped.is_some() {
run(index, first_aa, pending.is_some())?;
}
Ok(())
}
fn write_attached_stream(writer: &mut Writer, source: RunSource<'_>) -> Result<()> {
let mut first_value: Option<u8> = None;
let mut run_count = 0u64;
let mut pending: Option<u64> = None;
let mut stored = StoredLengths::new();
let mut sizes = [PlaneSizes::default(); 2];
let mut last: Option<u8> = None;
source.walk(threshold, |length, value| {
match last {
None => {
if value != 0x00 && value != 0xFF {
return Err(Error::new(
Check::ReeFirstValue,
format!("attached REE first_value is 0x{value:02X}, not 0x00 or 0xFF"),
));
}
first_value = Some(value);
}
Some(previous) if value != 255 - previous => {
return Err(Error::new(
Check::ReeFirstValue,
format!("attached REE cannot hold pixel 0x{value:02X}"),
));
}
Some(_) => {}
}
last = Some(value);
if let Some(previous) = pending.replace(length) {
let (value, parity) = stored.next(previous);
sizes[parity].add(value);
}
run_count += 1;
Ok(())
})?;
let Some(first_value) = first_value else {
return Err(Error::new(
Check::ReeDataSize,
"an attached stream needs at least one pixel",
));
};
let mut bits: Vec<u8> = Vec::new();
let mut escape_sizes = PlaneSizes::default();
let mut escape_count = 0u64;
let mut value_sizes = PlaneSizes::default();
let mut value_count = 0u64;
let mut previous_value = 0u8;
walk_overlay(
source,
|index, first, last| {
let byte = (index / 4) as usize;
if bits.len() <= byte {
bits.resize(byte + 1, 0);
}
if first {
bits[byte] |= 1 << ((index % 4) * 2);
}
if last {
bits[byte] |= 2 << ((index % 4) * 2);
}
Ok(())
},
|_, delta| {
escape_sizes.add(delta);
escape_count += 1;
Ok(())
},
)?;
source.walk(
|value| value,
|length, value| {
if is_aa(value) {
for _ in 0..length {
let stored = if value_count == 0 {
u64::from(value)
} else {
zigzag(i64::from(value) - i64::from(previous_value))
};
value_sizes.add(stored);
value_count += 1;
previous_value = value;
}
}
Ok(())
},
)?;
bits.resize(run_count.div_ceil(4) as usize, 0);
writer.u8(first_value);
writer.varint(run_count);
for (parity, size) in sizes.iter().enumerate() {
size.write(writer);
for plane in 0..PLANES {
let mut replay = StoredLengths::new();
let mut pending: Option<u64> = None;
source.walk(threshold, |length, _| {
if let Some(previous) = pending.replace(length) {
let (value, at) = replay.next(previous);
if at == parity {
write_plane_byte(writer, value, plane)?;
}
}
Ok(())
})?;
}
}
writer.varint(value_count);
writer.bytes(&bits);
writer.varint(escape_count);
escape_sizes.write(writer);
for plane in 0..PLANES {
walk_overlay(
source,
|_, _, _| Ok(()),
|_, delta| write_plane_byte(writer, delta, plane),
)?;
}
value_sizes.write(writer);
for plane in 0..PLANES {
let mut index = 0u64;
let mut previous = 0u8;
source.walk(
|value| value,
|length, value| {
if is_aa(value) {
for _ in 0..length {
let stored = if index == 0 {
u64::from(value)
} else {
zigzag(i64::from(value) - i64::from(previous))
};
write_plane_byte(writer, stored, plane)?;
index += 1;
previous = value;
}
}
Ok(())
},
)?;
}
Ok(())
}
pub fn encode(pixels: &[u8], total_pixels: u32, mode: EncodeMode) -> Result<Option<(u8, Vec<u8>)>> {
check_mask(pixels, total_pixels)?;
encode_source(RunSource::Pixels(pixels), mode)
}
pub fn encode_runs(
runs: &[Run],
total_pixels: u32,
mode: EncodeMode,
) -> Result<Option<(u8, Vec<u8>)>> {
check_runs(runs, total_pixels)?;
encode_source(RunSource::Runs(runs), mode)
}
fn encode_source(source: RunSource<'_>, mode: EncodeMode) -> Result<Option<(u8, Vec<u8>)>> {
if source.is_all_black() {
return Ok(None);
}
let encoded = match mode {
EncodeMode::Binary => (TAG_BINARY, encode_binary_source(source)?),
EncodeMode::Grayscale => (TAG_GRAYSCALE, encode_grayscale_source(source)?),
EncodeMode::Split => (TAG_SPLIT, encode_split_source(source)?),
EncodeMode::Attached => (TAG_ATTACHED, encode_attached_source(source)?),
EncodeMode::Auto => {
if source.is_binary() {
(TAG_BINARY, encode_binary_source(source)?)
} else {
let grayscale = encode_grayscale_source(source)?;
let split = encode_split_source(source)?;
if split.len() < grayscale.len() {
(TAG_SPLIT, split)
} else {
(TAG_GRAYSCALE, grayscale)
}
}
}
};
Ok(Some(encoded))
}
pub fn encode_binary(pixels: &[u8], total_pixels: u32) -> Result<Vec<u8>> {
check_mask(pixels, total_pixels)?;
require_pixels(pixels)?;
encode_binary_source(RunSource::Pixels(pixels))
}
fn encode_binary_source(source: RunSource<'_>) -> Result<Vec<u8>> {
let mut writer = Writer::new();
writer.u8(TAG_BINARY);
write_binary_stream(&mut writer, source, |pixel| pixel)?;
Ok(writer.into_vec())
}
pub fn encode_grayscale(pixels: &[u8], total_pixels: u32) -> Result<Vec<u8>> {
check_mask(pixels, total_pixels)?;
require_pixels(pixels)?;
encode_grayscale_source(RunSource::Pixels(pixels))
}
fn encode_grayscale_source(source: RunSource<'_>) -> Result<Vec<u8>> {
let mut writer = Writer::new();
writer.u8(TAG_GRAYSCALE);
write_grayscale_stream(&mut writer, source)?;
Ok(writer.into_vec())
}
pub fn encode_split(pixels: &[u8], total_pixels: u32) -> Result<Vec<u8>> {
check_mask(pixels, total_pixels)?;
require_pixels(pixels)?;
encode_split_source(RunSource::Pixels(pixels))
}
fn encode_split_source(source: RunSource<'_>) -> Result<Vec<u8>> {
let mut writer = Writer::new();
writer.u8(TAG_SPLIT);
write_split_stream(&mut writer, source)?;
Ok(writer.into_vec())
}
pub fn encode_attached(pixels: &[u8], total_pixels: u32) -> Result<Vec<u8>> {
check_mask(pixels, total_pixels)?;
require_pixels(pixels)?;
encode_attached_source(RunSource::Pixels(pixels))
}
fn encode_attached_source(source: RunSource<'_>) -> Result<Vec<u8>> {
let mut writer = Writer::new();
writer.u8(TAG_ATTACHED);
write_attached_stream(&mut writer, source)?;
Ok(writer.into_vec())
}
pub fn validate_stream(data: &[u8], total_pixels: u32, strict: bool) -> Result<usize> {
let (tag, mut reader) = tag_and_stream(data)?;
read(tag, Sink::None, &mut reader, total_pixels, strict)?;
Ok(1 + reader.pos())
}
pub(crate) fn exposed_ranges(
data: &[u8],
total_pixels: u32,
report: impl FnMut(u64, u64) -> Result<()>,
) -> Result<()> {
let (tag, mut reader) = tag_and_stream(data)?;
let mut report = report;
read(
tag,
Sink::Exposed(&mut report),
&mut reader,
total_pixels,
true,
)
}
#[cfg(test)]
mod tests {
use super::*;
const LAYER_BINARY: &str = "0000030201000064c801";
const LAYER_GRAYSCALE: &str = "0105008000ff000400000064146464";
const LAYER_SPLIT: &str = "02000504000000641e14321e1e000000640101010101010101010101010101010101010101010101010101010101c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8";
const TOTAL: u32 = 64 * 48;
fn mask(runs: &[(u8, usize)]) -> Vec<u8> {
let mut pixels = Vec::new();
for (value, length) in runs {
pixels.extend(std::iter::repeat_n(*value, *length));
}
pixels
}
fn runs(pixels: &[u8]) -> Vec<(u8, usize)> {
let mut runs: Vec<(u8, usize)> = Vec::new();
for &pixel in pixels {
if let Some(last) = runs.last_mut() {
if last.0 == pixel {
last.1 += 1;
continue;
}
}
runs.push((pixel, 1));
}
runs
}
fn bytes(hex: &str) -> Vec<u8> {
hex::decode(hex).unwrap()
}
fn runs_of(pixels: &[u8]) -> Vec<Run> {
runs(pixels)
.into_iter()
.map(|(value, length)| Run::new(length as u32, value))
.collect()
}
fn run_list(spec: &[(u8, usize)]) -> Vec<Run> {
spec.iter()
.map(|(value, length)| Run::new(*length as u32, *value))
.collect()
}
const MODES: [EncodeMode; 5] = [
EncodeMode::Auto,
EncodeMode::Binary,
EncodeMode::Grayscale,
EncodeMode::Split,
EncodeMode::Attached,
];
type CorpusCase = (&'static str, Vec<(u8, usize)>, u8, EncodeMode);
fn corpus_cases() -> [CorpusCase; 3] {
[
(
LAYER_BINARY,
vec![(0, 100), (255, 200), (0, 2772)],
TAG_BINARY,
EncodeMode::Binary,
),
(
LAYER_GRAYSCALE,
vec![(0, 100), (128, 20), (0, 100), (255, 100), (0, 2752)],
TAG_GRAYSCALE,
EncodeMode::Grayscale,
),
(
LAYER_SPLIT,
vec![(0, 100), (200, 30), (0, 20), (255, 50), (0, 2872)],
TAG_SPLIT,
EncodeMode::Split,
),
]
}
fn assert_run_path_matches(pixels: &[u8], runs: &[Run], total: u32, mode: EncodeMode) {
match (encode(pixels, total, mode), encode_runs(runs, total, mode)) {
(Ok(pixel_path), Ok(run_path)) => assert_eq!(pixel_path, run_path, "mode {mode:?}"),
(Err(pixel_path), Err(run_path)) => {
assert_eq!(pixel_path.check(), run_path.check(), "mode {mode:?}")
}
(pixel_path, run_path) => {
panic!("{mode:?}: pixel path {pixel_path:?}, run path {run_path:?}")
}
}
}
fn check_of(data: &[u8], total: u32, strict: bool) -> Check {
decode(data, total, strict).unwrap_err().check()
}
#[test]
fn spec_varint_examples() {
assert_eq!(crate::varint::to_vec(0), vec![0x00]);
assert_eq!(crate::varint::to_vec(128), vec![0x80, 0x01]);
assert_eq!(crate::varint::encoded_len(127), 1);
assert_eq!(crate::varint::encoded_len(128), 2);
assert_eq!(crate::varint::encoded_len(16_383), 2);
assert_eq!(crate::varint::encoded_len(16_384), 3);
assert_eq!(crate::varint::encoded_len(2_097_151), 3);
assert_eq!(crate::varint::encoded_len(268_435_455), 4);
assert_eq!(
crate::varint::to_vec(1920 * 1080),
vec![0x80, 0xC8, 0x7E],
"2 073 600 is 3 bytes"
);
assert_eq!(crate::varint::encoded_len(11_520 * 6_480), 4);
let twelve_k = crate::varint::to_vec(11_520 * 6_480);
let mut reader = Reader::new(&twelve_k);
assert_eq!(reader.varint().unwrap(), 11_520 * 6_480);
assert!(reader.is_empty());
}
#[test]
fn binary_layer_of_the_corpus_round_trips() {
let data = bytes(LAYER_BINARY);
let expected = mask(&[(0, 100), (255, 200), (0, 2772)]);
for strict in [false, true] {
let layer = decode(&data, TOTAL, strict).unwrap();
assert_eq!(layer.tag, Some(TAG_BINARY));
assert_eq!(layer.pixels, expected);
assert!(layer.is_binary());
}
assert_eq!(encode_binary(&expected, TOTAL).unwrap(), data);
assert_eq!(
encode(&expected, TOTAL, EncodeMode::Auto).unwrap(),
Some((TAG_BINARY, data))
);
}
#[test]
fn grayscale_layer_of_the_corpus_round_trips() {
let data = bytes(LAYER_GRAYSCALE);
let expected = mask(&[(0, 100), (128, 20), (0, 100), (255, 100), (0, 2752)]);
for strict in [false, true] {
let layer = decode(&data, TOTAL, strict).unwrap();
assert_eq!(layer.tag, Some(TAG_GRAYSCALE));
assert_eq!(layer.pixels, expected);
}
assert_eq!(encode_grayscale(&expected, TOTAL).unwrap(), data);
assert_eq!(
encode(&expected, TOTAL, EncodeMode::Auto).unwrap(),
Some((TAG_GRAYSCALE, data))
);
}
#[test]
fn split_layer_of_the_corpus_round_trips() {
let data = bytes(LAYER_SPLIT);
assert_eq!(data.len(), 76, "the corpus split stream is 76 bytes");
let expected = mask(&[(0, 100), (200, 30), (0, 20), (255, 50), (0, 2872)]);
for strict in [false, true] {
let layer = decode(&data, TOTAL, strict).unwrap();
assert_eq!(layer.tag, Some(TAG_SPLIT));
assert_eq!(layer.pixels, expected);
}
assert_eq!(data[16], 0x64, "the first position is 100");
assert!(data[17..46].iter().all(|b| *b == 0x01));
assert!(data[46..].iter().all(|b| *b == 0xC8));
assert_eq!(encode_split(&expected, TOTAL).unwrap(), data);
assert_eq!(
encode(&expected, TOTAL, EncodeMode::Split).unwrap(),
Some((TAG_SPLIT, data))
);
}
#[test]
fn all_black_is_the_empty_layer_form() {
assert_eq!(encode(&[0u8; 16], 16, EncodeMode::Auto).unwrap(), None);
assert_eq!(encode(&[0u8; 16], 16, EncodeMode::Binary).unwrap(), None);
assert_eq!(encode(&[0u8; 16], 16, EncodeMode::Split).unwrap(), None);
assert!(DecodedLayer::empty(16).is_empty());
assert_eq!(encode(&[], 0, EncodeMode::Auto).unwrap(), None);
assert_eq!(
encode_binary(&[], 0).unwrap_err().check(),
Check::ReeDataSize
);
assert_eq!(
encode_grayscale(&[], 0).unwrap_err().check(),
Check::ReeDataSize
);
assert_eq!(
encode_split(&[], 0).unwrap_err().check(),
Check::ReeDataSize
);
}
#[test]
fn all_white_is_one_run() {
let (tag, data) = encode(&[255u8; 16], 16, EncodeMode::Auto).unwrap().unwrap();
assert_eq!(tag, TAG_BINARY);
assert_eq!(data, vec![TAG_BINARY, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00]);
assert_eq!(decode(&data, 16, true).unwrap().pixels, vec![255u8; 16]);
}
#[test]
fn auto_picks_the_smaller_stream_and_breaks_ties_towards_grayscale() {
let tie = [0xFF, 0x00, 0x01, 0x00, 0x01, 0x00];
assert_eq!(encode_grayscale(&tie, 6).unwrap().len(), 17);
assert_eq!(encode_split(&tie, 6).unwrap().len(), 17);
assert_eq!(
encode(&tie, 6, EncodeMode::Auto).unwrap().unwrap().0,
TAG_GRAYSCALE
);
let alternating: Vec<u8> = (0..200).map(|i| if i % 2 == 0 { 0 } else { 10 }).collect();
let grayscale = encode_grayscale(&alternating, 200).unwrap();
let split = encode_split(&alternating, 200).unwrap();
assert!(split.len() < grayscale.len(), "{split:?} {grayscale:?}");
let (tag, data) = encode(&alternating, 200, EncodeMode::Auto)
.unwrap()
.unwrap();
assert_eq!(tag, TAG_SPLIT);
assert_eq!(data, split);
assert_eq!(decode(&data, 200, false).unwrap().pixels, alternating);
let ramp = [0u8, 64, 128, 192, 255];
let grayscale = encode_grayscale(&ramp, 5).unwrap();
assert!(grayscale.len() < encode_split(&ramp, 5).unwrap().len());
let (tag, data) = encode(&ramp, 5, EncodeMode::Auto).unwrap().unwrap();
assert_eq!(tag, TAG_GRAYSCALE);
assert_eq!(decode(&data, 5, false).unwrap().pixels, ramp);
}
#[test]
fn binary_stripes_round_trip_all_modes() {
let pixels = mask(&[(0, 3), (255, 2), (0, 4), (255, 1)]);
let data = encode_binary(&pixels, 10).unwrap();
assert_eq!(
data,
vec![TAG_BINARY, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 3, 2, 4]
);
for strict in [false, true] {
assert_eq!(decode(&data, 10, strict).unwrap().pixels, pixels);
}
assert_eq!(runs(&pixels).len(), 4);
}
#[test]
fn encode_rejects_a_mask_of_the_wrong_size() {
assert_eq!(
encode(&[0u8; 4], 5, EncodeMode::Auto).unwrap_err().check(),
Check::ReeDataSize
);
assert_eq!(
encode_binary(&[0u8; 4], 5).unwrap_err().check(),
Check::ReeDataSize
);
assert_eq!(
encode_grayscale(&[0u8; 4], 5).unwrap_err().check(),
Check::ReeDataSize
);
assert_eq!(
encode_split(&[0u8; 4], 5).unwrap_err().check(),
Check::ReeDataSize
);
}
#[test]
fn binary_mode_refuses_a_non_binary_mask() {
let pixels = [0u8, 7, 255, 0];
assert_eq!(
encode(&pixels, 4, EncodeMode::Binary).unwrap_err().check(),
Check::ReeFirstValue
);
assert_eq!(
encode_binary(&pixels, 4).unwrap_err().check(),
Check::ReeFirstValue
);
assert_eq!(
encode_binary(&[7u8, 0], 2).unwrap_err().check(),
Check::ReeFirstValue
);
}
fn attached_mask() -> Vec<u8> {
mask(&[
(0x00, 2), (0x80, 1), (0xFF, 2),
(0x40, 1), (0xFF, 2), (0x90, 1), (0x00, 2),
(0x10, 1), (0x00, 1),
])
}
#[test]
fn attached_round_trips_every_placement() {
let pixels = attached_mask();
let total = pixels.len() as u32;
let (tag, data) = encode(&pixels, total, EncodeMode::Attached)
.unwrap()
.expect("a mask with overlay pixels has a stream");
assert_eq!(tag, TAG_ATTACHED);
assert_eq!(decode(&data, total, true).unwrap().pixels, pixels);
assert_eq!(
validate_stream(&data, total, true),
Ok(data.len()),
"the stream must use exactly its bytes"
);
assert_eq!(
encode_runs(&runs_of(&pixels), total, EncodeMode::Attached),
Ok(Some((TAG_ATTACHED, data)))
);
}
#[test]
fn attached_pins_the_smallest_overlay_stream() {
let data: Vec<u8> = vec![
TAG_ATTACHED,
0x00, 0x04, 0x02,
0x00,
0x00,
0x00,
0x01,
0x00, 0x01,
0x00,
0x00,
0x00,
0x01, 0x02, 0x14, 0x00, 0x00,
0x00,
0x00,
0x00, 0x02,
0x01,
0x00,
0x00,
0x80,
0x7F,
0x01, ];
let pixels = vec![0x00, 0x80, 0x40, 0xFF];
assert_eq!(decode(&data, 4, true).unwrap().pixels, pixels);
assert_eq!(
encode(&pixels, 4, EncodeMode::Attached).unwrap(),
Some((TAG_ATTACHED, data.clone()))
);
assert_eq!(validate_stream(&data, 4, true), Ok(data.len()));
}
#[test]
fn attached_accepts_an_all_binary_layer() {
let pixels = mask(&[(0x00, 5), (0xFF, 7), (0x00, 3)]);
let (tag, data) = encode(&pixels, 15, EncodeMode::Attached).unwrap().unwrap();
assert_eq!(tag, TAG_ATTACHED);
assert_eq!(
decode(&data, 15, true).unwrap().pixels,
pixels,
"strict mode accepts it: unlike split, an empty overlay is not a defect here"
);
assert_eq!(
encode(&pixels, 15, EncodeMode::Binary).unwrap().unwrap().0,
TAG_BINARY
);
}
#[test]
fn attached_rejects_broken_overlays() {
let base: Vec<u8> = vec![
TAG_ATTACHED,
0x00,
0x04,
0x02,
0x00,
0x00,
0x00,
0x01,
0x00,
0x01,
0x00,
0x00,
0x00,
0x01,
0x02,
0x14,
0x00,
0x00,
0x00,
0x00,
0x00,
0x02,
0x01,
0x00,
0x00,
0x80,
0x7F,
0x01,
];
assert_eq!(
decode(&base, 4, true).unwrap().pixels,
vec![0, 0x80, 0x40, 0xFF]
);
let both_ends: Vec<u8> = vec![
TAG_ATTACHED,
0x00,
0x04,
0x02,
0x00,
0x00,
0x00,
0x01,
0x00,
0x01,
0x00,
0x00,
0x00,
0x01,
0x03, 0x1c, 0x00,
0x00,
0x00,
0x00,
0x00, 0x03,
0x01,
0x00,
0x00,
0x80,
0x7F,
0x00, 0x01,
];
assert_eq!(check_of(&both_ends, 4, true), Check::ReeAttachBits);
assert_eq!(
decode(&both_ends, 4, false).unwrap().pixels,
vec![0x00, 0x40, 0x40, 0xFF],
"the second bit's value is the one the pixel ends up with"
);
let mut binary_value = base.clone();
binary_value[25] = 0x00;
binary_value[26] = 0x00;
assert_eq!(check_of(&binary_value, 4, true), Check::ReeAttachThreshold);
assert!(decode(&binary_value, 4, false).is_ok());
let mut wrong_side = base.clone();
wrong_side[25] = 0x40;
assert_eq!(check_of(&wrong_side, 4, true), Check::ReeAttachThreshold);
let mut not_inside = vec![
TAG_ATTACHED,
0x00,
0x04,
0x02,
0x00,
0x00,
0x00,
0x01,
0x00,
0x01,
0x00,
0x00,
0x00,
0x01,
0x02,
0x14,
0x01, 0x01,
0x00,
0x00,
0x00,
0x01, 0x02,
0x01,
0x00,
0x00,
0x80,
0x7F,
0x01,
];
assert_eq!(check_of(¬_inside, 4, false), Check::ReeAttachPositions);
assert_eq!(check_of(¬_inside, 4, true), Check::ReeAttachPositions);
not_inside[21] = 0x09; assert_eq!(check_of(¬_inside, 4, false), Check::ReeAttachPositions);
let mut short_values = base.clone();
short_values[14] = 0x03;
assert_eq!(check_of(&short_values, 4, false), Check::ReeAttachCount);
let mut long_values = base.clone();
long_values[14] = 0x01;
assert_eq!(check_of(&long_values, 4, false), Check::ReeAttachCount);
}
#[test]
fn attached_ignores_a_bit_on_an_empty_run() {
let data: Vec<u8> = vec![
TAG_ATTACHED,
0x00,
0x02, 0x01,
0x00,
0x00,
0x00,
0x03, 0x00,
0x00,
0x00,
0x00, 0x01, 0x04, 0x00, 0x00,
0x00,
0x00,
0x00, 0x01,
0x00,
0x00,
0x00,
0x40, ];
assert_eq!(check_of(&data, 3, false), Check::ReeAttachCount);
assert_eq!(check_of(&data, 3, true), Check::ReeAttachCount);
}
#[test]
fn attached_padding_bits_are_strict_only() {
let pixels = mask(&[(0xFF, 4)]);
let (_, data) = encode(&pixels, 4, EncodeMode::Attached).unwrap().unwrap();
let mut padded = data.clone();
let last = padded.len() - 1 - 4 - 4 - 1; padded[last] = 0x04;
assert_eq!(check_of(&padded, 4, true), Check::ReeAttachBits);
assert!(decode(&padded, 4, false).is_ok());
}
#[test]
fn attached_run_count_zero_is_loose_only() {
let data: Vec<u8> = vec![
TAG_ATTACHED,
0x00,
0x00, 0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00, 0x00, 0x00, 0x00,
0x00,
0x00,
0x00, 0x00,
0x00,
0x00,
0x00, ];
assert_eq!(decode(&data, 4, false).unwrap().pixels, vec![0u8; 4]);
assert_eq!(check_of(&data, 4, true), Check::ReeNoRunCountZero);
}
#[test]
fn unknown_or_missing_tags_are_rejected() {
assert_eq!(check_of(&[], 4, false), Check::ReeTag);
assert_eq!(check_of(&[0x04, 0x00], 4, false), Check::ReeTag);
assert_eq!(check_of(&[0xFF, 0x00], 4, true), Check::ReeTag);
assert_eq!(check_of(&[TAG_BINARY], 4, false), Check::ReeVarint);
assert_eq!(check_of(&[TAG_GRAYSCALE], 4, false), Check::ReeVarint);
assert_eq!(check_of(&[TAG_ATTACHED], 4, false), Check::ReeVarint);
assert_eq!(
check_of(&[TAG_SPLIT, TAG_BINARY, 0x01], 4, false),
Check::ReeVarint
);
}
#[test]
fn binary_first_value_must_be_black_or_white() {
assert_eq!(
check_of(&[TAG_BINARY, 0x7F, 0x01], 4, false),
Check::ReeFirstValue
);
assert_eq!(
check_of(&[TAG_BINARY, 0x01, 0x01], 4, true),
Check::ReeFirstValue
);
}
#[test]
fn run_count_zero_is_loose_only() {
let binary = [TAG_BINARY, 0x00, 0x00];
assert_eq!(decode(&binary, 4, false).unwrap().pixels, vec![0u8; 4]);
assert_eq!(check_of(&binary, 4, true), Check::ReeNoRunCountZero);
assert_eq!(validate_stream(&binary, 4, false), Ok(binary.len()));
assert_eq!(
validate_stream(&binary, 4, true).unwrap_err().check(),
Check::ReeNoRunCountZero
);
let grayscale = [TAG_GRAYSCALE, 0x00];
assert_eq!(decode(&grayscale, 4, false).unwrap().pixels, vec![0u8; 4]);
assert_eq!(check_of(&grayscale, 4, true), Check::ReeNoRunCountZero);
assert_eq!(encode(&[0u8; 4], 4, EncodeMode::Binary).unwrap(), None);
}
#[test]
fn binary_run_lengths_split_loose_from_strict() {
let empty_first = [TAG_BINARY, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02];
assert_eq!(
decode(&empty_first, 4, false).unwrap().pixels,
vec![255, 255, 0, 0]
);
assert_eq!(check_of(&empty_first, 4, true), Check::ReeRunLengths);
let implicit_empty = [TAG_BINARY, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x04];
assert_eq!(
decode(&implicit_empty, 4, false).unwrap().pixels,
vec![0, 0, 0, 0]
);
assert_eq!(check_of(&implicit_empty, 4, true), Check::ReeRunLengths);
let overshoot = [TAG_BINARY, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x05];
assert_eq!(check_of(&overshoot, 4, false), Check::ReeEndPositions);
assert_eq!(check_of(&overshoot, 4, true), Check::ReeEndPositions);
let too_many = [TAG_BINARY, 0x00, 0x06];
assert_eq!(check_of(&too_many, 4, false), Check::ReeRunLengths);
assert_eq!(
check_of(&[TAG_GRAYSCALE, 0x06], 4, false),
Check::ReeRunLengths
);
let canonical = [TAG_BINARY, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x02];
for strict in [false, true] {
assert_eq!(
decode(&canonical, 4, strict).unwrap().pixels,
vec![0, 0, 255, 255]
);
}
}
#[test]
fn grayscale_run_rules_split_loose_from_strict() {
let repeated = [
TAG_GRAYSCALE,
0x02,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x02,
];
assert_eq!(
decode(&repeated, 4, false).unwrap().pixels,
vec![0, 0, 0, 0]
);
assert_eq!(check_of(&repeated, 4, true), Check::ReeGrayscaleRuns);
let empty_run = [
TAG_GRAYSCALE,
0x02,
0x00,
0x05,
0x01,
0x00,
0x00,
0x00,
0x00,
];
assert_eq!(
decode(&empty_run, 4, false).unwrap().pixels,
vec![5, 5, 5, 5]
);
assert_eq!(check_of(&empty_run, 4, true), Check::ReeGrayscaleRuns);
let implicit_empty = [
TAG_GRAYSCALE,
0x02,
0x00,
0x05,
0x01,
0x00,
0x00,
0x00,
0x04,
];
assert_eq!(
decode(&implicit_empty, 4, false).unwrap().pixels,
vec![0, 0, 0, 0]
);
assert_eq!(check_of(&implicit_empty, 4, true), Check::ReeGrayscaleRuns);
let past = [
TAG_GRAYSCALE,
0x02,
0x00,
0x05,
0x01,
0x00,
0x00,
0x00,
0x05,
];
assert_eq!(check_of(&past, 4, false), Check::ReeEndPositions);
assert_eq!(check_of(&past, 4, true), Check::ReeEndPositions);
let binary_values = [
TAG_GRAYSCALE,
0x02,
0x00,
0xFF,
0x01,
0x00,
0x00,
0x00,
0x02,
];
assert_eq!(
decode(&binary_values, 4, false).unwrap().pixels,
vec![0, 0, 255, 255]
);
assert_eq!(
check_of(&binary_values, 4, true),
Check::ReeGrayscaleAllBinary
);
let one_run = [TAG_GRAYSCALE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
assert_eq!(decode(&one_run, 4, false).unwrap().pixels, vec![0u8; 4]);
assert_eq!(check_of(&one_run, 4, true), Check::ReeGrayscaleAllBinary);
assert_eq!(
validate_stream(&bytes(LAYER_GRAYSCALE), TOTAL, true),
Ok(LAYER_GRAYSCALE.len() / 2)
);
}
const SPLIT_TOTAL: u32 = 8;
const SPLIT_CANONICAL: [u8; 18] = [
TAG_SPLIT, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, 0x01, 0xC8, 0xC8, ];
#[test]
fn split_overlay_positions_are_delta_encoded() {
let expected = [0, 0, 0, 0, 200, 200, 0, 0];
for strict in [false, true] {
assert_eq!(
decode(&SPLIT_CANONICAL, SPLIT_TOTAL, strict)
.unwrap()
.pixels,
expected
);
}
assert_eq!(
encode_split(&expected, SPLIT_TOTAL).unwrap(),
SPLIT_CANONICAL
);
assert_eq!(&SPLIT_CANONICAL[14..16], &[0x04, 0x01]);
}
#[test]
fn split_overlay_rules_are_enforced() {
let repeated = [
TAG_SPLIT, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x00, 0x00,
0x00, 0x04, 0x00, 0xC8, 0xC8,
];
assert_eq!(
check_of(&repeated, SPLIT_TOTAL, false),
Check::ReeSplitPositions
);
assert_eq!(
check_of(&repeated, SPLIT_TOTAL, true),
Check::ReeSplitPositions
);
let out_of_range = [
TAG_SPLIT, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x00, 0x00,
0x00, 0x08, 0x01, 0xC8, 0xC8,
];
assert_eq!(
check_of(&out_of_range, SPLIT_TOTAL, false),
Check::ReeSplitPositions
);
let too_many = [TAG_SPLIT, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06];
assert_eq!(check_of(&too_many, 4, false), Check::ReeSplitPositions);
let short_values = [
TAG_SPLIT, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04,
];
assert_eq!(
check_of(&short_values, SPLIT_TOTAL, false),
Check::ReeVarint
);
let wrong_threshold = [
TAG_SPLIT, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x00, 0x00,
0x00, 0x04, 0x01, 0x64, 0xC8,
];
assert!(decode(&wrong_threshold, SPLIT_TOTAL, false).is_ok());
assert_eq!(
check_of(&wrong_threshold, SPLIT_TOTAL, true),
Check::ReeSplitThreshold
);
let white_overlay = [
TAG_SPLIT, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x00, 0x00,
0x00, 0x04, 0x01, 0xFF, 0xC8,
];
assert_eq!(
check_of(&white_overlay, SPLIT_TOTAL, true),
Check::ReeSplitThreshold
);
let no_overlay = [
TAG_SPLIT, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let expected = mask(&[(0, 4), (255, 4)]);
assert_eq!(
decode(&no_overlay, SPLIT_TOTAL, false).unwrap().pixels,
expected
);
assert_eq!(
check_of(&no_overlay, SPLIT_TOTAL, true),
Check::ReeSplitAllBinary
);
assert_eq!(encode_split(&expected, SPLIT_TOTAL).unwrap(), no_overlay);
let non_canonical_core = [TAG_SPLIT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
assert_eq!(
check_of(&non_canonical_core, SPLIT_TOTAL, true),
Check::ReeNoRunCountZero
);
assert!(decode(&non_canonical_core, SPLIT_TOTAL, false).is_ok());
}
fn planes(sizes: [u8; PLANES], bytes: &[u8]) -> Vec<u8> {
let mut out = sizes.to_vec();
out.extend_from_slice(bytes);
out
}
#[test]
fn varint_bytes_are_laid_out_in_significance_planes() {
let pixels = mask(&[(0, 100), (255, 300), (0, 3)]);
let data = encode_binary(&pixels, 403).unwrap();
let mut expected = vec![TAG_BINARY, 0x00, 0x03];
expected.extend(planes([2, 1, 0, 0], &[100, 0xAC, 0x02]));
assert_eq!(data, expected);
assert_eq!(decode(&data, 403, true).unwrap().pixels, pixels);
let wide = mask(&[(0, 128), (255, 128)]);
let data = encode_binary(&wide, 256).unwrap();
let mut expected = vec![TAG_BINARY, 0x00, 0x02];
expected.extend(planes([1, 1, 0, 0], &[0x80, 0x01]));
assert_eq!(data, expected);
assert_eq!(decode(&data, 256, true).unwrap().pixels, wide);
}
#[test]
fn planes_must_be_prefix_closed_and_exactly_used() {
let not_prefix_closed = [TAG_BINARY, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x01];
assert!(decode(¬_prefix_closed, 4, false).is_ok());
assert_eq!(
check_of(¬_prefix_closed, 4, true),
Check::ReePlanes,
"a non-empty plane may not follow an empty one"
);
let leftover = [TAG_BINARY, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02];
assert_eq!(
decode(&leftover, 4, false).unwrap().pixels,
vec![0, 0, 255, 255]
);
assert_eq!(check_of(&leftover, 4, true), Check::ReePlanes);
let too_many_planes = [
TAG_BINARY, 0x00, 0x02, 0x01, 0x01, 0x01, 0x01, 0x80, 0x80, 0x80, 0x80,
];
assert_eq!(check_of(&too_many_planes, 4, false), Check::ReeVarint);
let overlong = [TAG_BINARY, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x80, 0x00];
assert_eq!(check_of(&overlong, 4, false), Check::ReeVarint);
let short = [TAG_BINARY, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00];
assert_eq!(check_of(&short, 4, false), Check::ReeVarint);
let truncated = [TAG_BINARY, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00];
assert_eq!(check_of(&truncated, 4, false), Check::ReeVarint);
}
#[test]
fn a_length_needing_a_fifth_plane_is_refused() {
let total = (1u64 << 28) + 1;
let runs = [Run::new(1 << 28, 0), Run::new(1, 255)];
assert_eq!(
encode_runs(&runs, total as u32, EncodeMode::Binary)
.unwrap_err()
.check(),
Check::ReePlanes
);
assert_eq!(
encode_runs(&runs, total as u32, EncodeMode::Grayscale)
.unwrap_err()
.check(),
Check::ReePlanes
);
let fits = [Run::new((1 << 28) - 1, 255), Run::new(1, 0)];
let (_, data) = encode_runs(&fits, 1 << 28, EncodeMode::Binary)
.unwrap()
.unwrap();
assert_eq!(data.len(), 2 + 1 + 4 + 4, "four plane bytes, one per plane");
assert_eq!(&data[7..11], &[0xFF, 0xFF, 0xFF, 0x7F]);
}
#[test]
fn a_single_run_stream_carries_the_four_plane_lengths() {
let one_run = [TAG_BINARY, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00];
assert_eq!(validate_stream(&one_run, 7, true), Ok(one_run.len()));
for strict in [false, true] {
assert_eq!(decode(&one_run, 7, strict).unwrap().pixels, vec![255u8; 7]);
}
let headerless = [TAG_BINARY, 0xFF, 0x01];
assert_eq!(check_of(&headerless, 7, false), Check::ReeVarint);
let grayscale = [TAG_GRAYSCALE, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00];
assert_eq!(validate_stream(&grayscale, 7, true), Ok(grayscale.len()));
assert_eq!(decode(&grayscale, 7, true).unwrap().pixels, vec![0x80u8; 7]);
assert_eq!(
check_of(&[TAG_GRAYSCALE, 0x01, 0x80], 7, false),
Check::ReeVarint
);
let split = [
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, ];
assert_eq!(validate_stream(&split, 7, true), Ok(split.len()));
assert_eq!(decode(&split, 7, true).unwrap().pixels, vec![0x80u8; 7]);
let split = [
TAG_SPLIT, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
assert_eq!(validate_stream(&split, 7, false), Ok(split.len()));
assert_eq!(decode(&split, 7, false).unwrap().pixels, vec![0u8; 7]);
assert_eq!(check_of(&split, 7, true), Check::ReeSplitAllBinary);
}
#[test]
fn a_split_over_an_all_binary_mask_is_strict_only() {
let empty_overlay = [
TAG_SPLIT, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let expected = mask(&[(0, 4), (255, 4)]);
assert_eq!(
decode(&empty_overlay, SPLIT_TOTAL, false).unwrap().pixels,
expected
);
assert_eq!(
check_of(&empty_overlay, SPLIT_TOTAL, true),
Check::ReeSplitAllBinary
);
assert_eq!(
validate_stream(&empty_overlay, SPLIT_TOTAL, true)
.unwrap_err()
.check(),
Check::ReeSplitAllBinary
);
let binary = encode_binary(&expected, SPLIT_TOTAL).unwrap();
assert_eq!(
validate_stream(&binary, SPLIT_TOTAL, true),
Ok(binary.len())
);
let grayscale = encode_grayscale(&expected, SPLIT_TOTAL).unwrap();
assert_eq!(
check_of(&grayscale, SPLIT_TOTAL, true),
Check::ReeGrayscaleAllBinary
);
let zero_overlay = [
TAG_SPLIT, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00,
0x04, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, ];
assert_eq!(
check_of(&zero_overlay, SPLIT_TOTAL, true),
Check::ReeSplitThreshold
);
}
#[test]
fn validate_stream_matches_decode() {
assert_eq!(
validate_stream(&bytes(LAYER_BINARY), TOTAL, true),
Ok(LAYER_BINARY.len() / 2)
);
assert_eq!(
validate_stream(&bytes(LAYER_SPLIT), TOTAL, true),
Ok(LAYER_SPLIT.len() / 2)
);
assert_eq!(
validate_stream(&[], TOTAL, false),
Err(Error::new(
Check::ReeTag,
"layer mask data is empty: the empty-layer form carries no bytes"
))
);
}
fn covered(ranges: &[(u64, u64)], total: usize) -> Vec<bool> {
let mut pixels = vec![false; total];
for &(start, end) in ranges {
for pixel in &mut pixels[start as usize..end as usize] {
*pixel = true;
}
}
pixels
}
fn every_small_mask(total: usize, mut f: impl FnMut(&[u8])) {
const ALPHABET: [u8; 5] = [0x00, 0x01, 0x7F, 0x80, 0xFF];
let mut pixels = vec![0u8; total];
for index in 0..ALPHABET.len().pow(total as u32) {
let mut rest = index;
for pixel in pixels.iter_mut() {
*pixel = ALPHABET[rest % ALPHABET.len()];
rest /= ALPHABET.len();
}
f(&pixels);
}
}
#[test]
fn the_exposed_walk_matches_the_mask_it_decodes_to() {
let mut compared = 0usize;
for total in 1usize..=5 {
every_small_mask(total, |pixels| {
for mode in MODES {
let Ok(Some((_, data))) = encode(pixels, total as u32, mode) else {
continue;
};
let decoded = decode(&data, total as u32, true);
let mut ranges: Vec<(u64, u64)> = Vec::new();
let walked = exposed_ranges(&data, total as u32, |start, end| {
ranges.push((start, end));
Ok(())
});
match (decoded, walked) {
(Ok(mask), Ok(())) => {
assert_eq!(
covered(&ranges, total),
mask.pixels.iter().map(|p| *p != 0).collect::<Vec<_>>(),
"{pixels:?} as {mode:?}"
);
}
(Err(decoded), Err(walked)) => {
assert_eq!(decoded.check(), walked.check(), "{pixels:?} as {mode:?}")
}
(decoded, walked) => {
panic!("{pixels:?} as {mode:?}: {decoded:?} but {walked:?}")
}
}
compared += 1;
}
});
}
for hex in [LAYER_BINARY, LAYER_GRAYSCALE, LAYER_SPLIT] {
let data = bytes(hex);
for at in 0..data.len() {
for byte in [0x00, 0x01, 0x7F, 0x80, 0xFF, 0x02] {
for stream in [data[..at].to_vec(), {
let mut changed = data.clone();
changed[at] = byte;
changed
}] {
let decoded = decode(&stream, TOTAL, true).is_ok();
let walked = exposed_ranges(&stream, TOTAL, |_, _| Ok(())).is_ok();
assert_eq!(
decoded, walked,
"{hex} with byte {at} set to 0x{byte:02X}: decoded {decoded}, \
walked {walked}"
);
compared += 1;
}
}
}
}
println!("{compared} streams compared");
}
#[test]
fn run_path_encodes_the_corpus_masks_byte_for_byte() {
for (hex, spec, tag, chosen) in corpus_cases() {
let pixels = mask(&spec);
let runs = run_list(&spec);
assert_eq!(
encode_runs(&runs, TOTAL, chosen).unwrap(),
Some((tag, bytes(hex))),
"the corpus stream is what the run path must produce"
);
for mode in MODES {
assert_run_path_matches(&pixels, &runs, TOTAL, mode);
}
}
}
fn large_mask() -> Vec<u8> {
const W: usize = 1920;
const H: usize = 1080;
const MARGIN: usize = 480;
const RAMP: usize = 64;
let mut pixels = vec![0u8; W * H];
for row in 0..H {
let line = &mut pixels[row * W..(row + 1) * W];
for offset in 0..RAMP {
line[MARGIN + offset] = (offset * 4) as u8;
line[W - MARGIN - RAMP + offset] = 255 - (offset * 4) as u8;
}
line[MARGIN + RAMP..W - MARGIN - RAMP].fill(255);
}
pixels
}
#[test]
fn run_path_matches_the_pixel_path_on_a_large_anti_aliased_mask() {
let pixels = large_mask();
let runs = runs_of(&pixels);
let total = pixels.len() as u32;
assert_eq!(total, 1920 * 1080);
assert!(
pixels.iter().any(|pixel| *pixel != 0x00 && *pixel != 0xFF),
"the mask must exercise the split overlay"
);
for mode in MODES {
assert_run_path_matches(&pixels, &runs, total, mode);
}
}
#[test]
fn run_path_matches_the_pixel_path_over_every_small_mask() {
const ALPHABET: [u8; 5] = [0x00, 0x01, 0x7F, 0x80, 0xFF];
let mut pixels = [0u8; 5];
let mut counter = 0usize;
while counter < ALPHABET.len().pow(pixels.len() as u32) {
let mut rest = counter;
for pixel in &mut pixels {
*pixel = ALPHABET[rest % ALPHABET.len()];
rest /= ALPHABET.len();
}
counter += 1;
let runs = runs_of(&pixels);
for mode in MODES {
assert_run_path_matches(&pixels, &runs, 5, mode);
}
}
}
#[test]
fn split_core_merges_runs_that_threshold_alike() {
let pixels = [90u8, 100, 90, 255, 255];
let runs = runs_of(&pixels);
assert_eq!(runs.len(), 4, "the mask's own runs do not merge");
assert_eq!(runs[0], Run::new(1, 90));
assert_eq!(runs[1], Run::new(1, 100));
assert_run_path_matches(&pixels, &runs, 5, EncodeMode::Split);
let (tag, data) = encode_runs(&runs, 5, EncodeMode::Split).unwrap().unwrap();
assert_eq!(tag, TAG_SPLIT);
assert_eq!(
&data[..9],
&[TAG_SPLIT, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x03, 0x03]
);
assert_eq!(decode(&data, 5, true).unwrap().pixels, pixels);
}
#[test]
fn run_path_rejects_non_canonical_runs() {
assert_eq!(
encode_runs(&[Run::new(0, 0), Run::new(4, 255)], 4, EncodeMode::Auto)
.unwrap_err()
.check(),
Check::ReeRunLengths
);
assert_eq!(
encode_runs(
&[Run::new(4, 255), Run::new(0, 0)],
4,
EncodeMode::Grayscale
)
.unwrap_err()
.check(),
Check::ReeRunLengths
);
for mode in MODES {
assert_eq!(
encode_runs(&[Run::new(2, 0), Run::new(2, 0)], 4, mode)
.unwrap_err()
.check(),
Check::ReeGrayscaleRuns,
"mode {mode:?}"
);
}
assert_eq!(
encode_runs(
&[Run::new(1, 200), Run::new(1, 200), Run::new(2, 0)],
4,
EncodeMode::Split
)
.unwrap_err()
.check(),
Check::ReeGrayscaleRuns
);
for runs in [
vec![Run::new(2, 0), Run::new(1, 255)],
vec![Run::new(5, 255)],
vec![],
] {
assert_eq!(
encode_runs(&runs, 4, EncodeMode::Auto).unwrap_err().check(),
Check::ReeDataSize
);
}
assert_eq!(encode_runs(&[], 0, EncodeMode::Auto).unwrap(), None);
assert_eq!(
encode_runs(&[Run::new(4, 0)], 4, EncodeMode::Auto).unwrap(),
None
);
assert_eq!(
encode_runs(&[Run::new(1, 0), Run::new(3, 0)], 4, EncodeMode::Auto)
.unwrap_err()
.check(),
Check::ReeGrayscaleRuns
);
assert_eq!(
encode_runs(&[Run::new(1, 0), Run::new(3, 7)], 4, EncodeMode::Binary)
.unwrap_err()
.check(),
Check::ReeFirstValue
);
assert_eq!(
encode_runs(&[Run::new(4, 7)], 4, EncodeMode::Binary)
.unwrap_err()
.check(),
Check::ReeFirstValue
);
}
}