use std::cmp::Ordering;
use super::symbol_statistics::{ReportedSymbols, SymbolReporter};
#[derive(PartialEq, Clone, Debug, Hash, Eq)]
pub(crate) enum ZleSymbol {
RunA,
RunB,
Number(u8),
}
impl PartialOrd for ZleSymbol {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match self {
ZleSymbol::RunA => match other {
ZleSymbol::RunA => Some(Ordering::Equal),
ZleSymbol::RunB => Some(Ordering::Less),
ZleSymbol::Number(_) => Some(Ordering::Less),
},
ZleSymbol::RunB => match other {
ZleSymbol::RunA => Some(Ordering::Greater),
ZleSymbol::RunB => Some(Ordering::Equal),
ZleSymbol::Number(_) => Some(Ordering::Less),
},
ZleSymbol::Number(this_number) => match other {
ZleSymbol::RunA => Some(Ordering::Greater),
ZleSymbol::RunB => Some(Ordering::Greater),
ZleSymbol::Number(other_number) => this_number.partial_cmp(other_number),
},
}
}
}
impl Ord for ZleSymbol {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match self {
ZleSymbol::RunA => match other {
ZleSymbol::RunA => Ordering::Equal,
ZleSymbol::RunB => Ordering::Less,
ZleSymbol::Number(_) => Ordering::Less,
},
ZleSymbol::RunB => match other {
ZleSymbol::RunA => Ordering::Greater,
ZleSymbol::RunB => Ordering::Equal,
ZleSymbol::Number(_) => Ordering::Less,
},
ZleSymbol::Number(this_number) => match other {
ZleSymbol::RunA => Ordering::Greater,
ZleSymbol::RunB => Ordering::Greater,
ZleSymbol::Number(other_number) => this_number.cmp(other_number),
},
}
}
}
fn convert_remainder(input: u8) -> ZleSymbol {
match input {
0 => ZleSymbol::RunA,
_ => ZleSymbol::RunB,
}
}
fn encode_zero_amount(number_of_zeros: usize) -> Vec<ZleSymbol> {
let mut out = Vec::<ZleSymbol>::new();
let mut num = number_of_zeros + 1;
while num > 0 {
out.push(convert_remainder((num as u8) & 1));
num >>= 1;
}
out.split_last().map(|x| x.1.to_owned()).unwrap_or_default()
}
pub(crate) fn zle_transform(
input: Vec<u8>,
mut symbol_reporter: impl SymbolReporter,
) -> (Vec<ZleSymbol>, ReportedSymbols) {
let mut zle_result = Vec::<ZleSymbol>::new();
let mut zero_count = 0;
for i in input {
if i == 0 {
zero_count += 1;
} else {
if zero_count > 0 {
let zle_encoded = encode_zero_amount(zero_count);
zle_result.extend(zle_encoded.clone());
for x in zle_encoded.iter() {
symbol_reporter.report_symbol(x);
}
}
zero_count = 0;
zle_result.push(ZleSymbol::Number(i));
symbol_reporter.report_symbol(&ZleSymbol::Number(i));
}
}
if zero_count > 0 {
let zle_encoded = encode_zero_amount(zero_count);
zle_result.extend(zle_encoded.clone());
for x in zle_encoded.iter() {
symbol_reporter.report_symbol(x);
}
}
symbol_reporter.report_symbol(&ZleSymbol::RunA);
(zle_result, symbol_reporter.finalize())
}
pub(crate) fn decode_zle(input: &[ZleSymbol]) -> Vec<u8> {
let mut output = vec![];
let mut zeros = vec![];
for element in input {
match element {
ZleSymbol::Number(element) => {
if !zeros.is_empty() {
output.append(&mut vec![0u8; decode_zero_amount(&zeros)]);
zeros.clear();
}
output.push(*element);
}
_ => zeros.push(element.clone()),
}
}
if !zeros.is_empty() {
output.append(&mut vec![0u8; decode_zero_amount(&zeros)]);
zeros.clear();
}
output
}
fn decode_zero_amount(input: &[ZleSymbol]) -> usize {
let mut complete = vec![ZleSymbol::RunB];
let mut input = input.to_vec();
input.reverse();
complete.append(&mut input);
let mut number = 0;
for bit in complete.iter() {
number <<= 1;
match bit {
ZleSymbol::RunA => (),
ZleSymbol::RunB => number += 1,
ZleSymbol::Number(_) => (),
}
}
number - 1
}
#[cfg(test)]
mod test {
use crate::block::symbol_statistics::SinglePropabilityMap;
use super::*;
#[test]
pub fn decodes_zero_amount() {
let data = vec![
(1, vec![ZleSymbol::RunA]),
(2, vec![ZleSymbol::RunB]),
(3, vec![ZleSymbol::RunA, ZleSymbol::RunA]),
(4, vec![ZleSymbol::RunB, ZleSymbol::RunA]),
(5, vec![ZleSymbol::RunA, ZleSymbol::RunB]),
(6, vec![ZleSymbol::RunB, ZleSymbol::RunB]),
(7, vec![ZleSymbol::RunA, ZleSymbol::RunA, ZleSymbol::RunA]),
(8, vec![ZleSymbol::RunB, ZleSymbol::RunA, ZleSymbol::RunA]),
(9, vec![ZleSymbol::RunA, ZleSymbol::RunB, ZleSymbol::RunA]),
(10, vec![ZleSymbol::RunB, ZleSymbol::RunB, ZleSymbol::RunA]),
(11, vec![ZleSymbol::RunA, ZleSymbol::RunA, ZleSymbol::RunB]),
(12, vec![ZleSymbol::RunB, ZleSymbol::RunA, ZleSymbol::RunB]),
(13, vec![ZleSymbol::RunA, ZleSymbol::RunB, ZleSymbol::RunB]),
(14, vec![ZleSymbol::RunB, ZleSymbol::RunB, ZleSymbol::RunB]),
(
63,
vec![
ZleSymbol::RunA,
ZleSymbol::RunA,
ZleSymbol::RunA,
ZleSymbol::RunA,
ZleSymbol::RunA,
ZleSymbol::RunA,
],
),
];
for (num, encoded) in data.into_iter() {
let zeroes = decode_zero_amount(&encoded);
assert_eq!(zeroes, num);
}
}
#[test]
pub fn encodes_zero_amount() {
let data = vec![
(1, vec![ZleSymbol::RunA]),
(2, vec![ZleSymbol::RunB]),
(3, vec![ZleSymbol::RunA, ZleSymbol::RunA]),
(4, vec![ZleSymbol::RunB, ZleSymbol::RunA]),
(5, vec![ZleSymbol::RunA, ZleSymbol::RunB]),
(6, vec![ZleSymbol::RunB, ZleSymbol::RunB]),
(7, vec![ZleSymbol::RunA, ZleSymbol::RunA, ZleSymbol::RunA]),
(8, vec![ZleSymbol::RunB, ZleSymbol::RunA, ZleSymbol::RunA]),
(9, vec![ZleSymbol::RunA, ZleSymbol::RunB, ZleSymbol::RunA]),
(10, vec![ZleSymbol::RunB, ZleSymbol::RunB, ZleSymbol::RunA]),
(11, vec![ZleSymbol::RunA, ZleSymbol::RunA, ZleSymbol::RunB]),
(12, vec![ZleSymbol::RunB, ZleSymbol::RunA, ZleSymbol::RunB]),
(13, vec![ZleSymbol::RunA, ZleSymbol::RunB, ZleSymbol::RunB]),
(14, vec![ZleSymbol::RunB, ZleSymbol::RunB, ZleSymbol::RunB]),
(
63,
vec![
ZleSymbol::RunA,
ZleSymbol::RunA,
ZleSymbol::RunA,
ZleSymbol::RunA,
ZleSymbol::RunA,
ZleSymbol::RunA,
],
),
];
for (num, encoded) in data.into_iter() {
let zeroes = encode_zero_amount(num);
assert_eq!(zeroes, encoded);
}
}
#[test]
fn encodes_zeros() {
let encoded = zle_transform(vec![0, 0, 0], SinglePropabilityMap::create(1));
assert_eq!(encoded.0, vec![ZleSymbol::RunA, ZleSymbol::RunA]);
}
#[test]
fn encodes_zeros_and_numbers() {
let encoded = zle_transform(vec![1, 0, 0, 0], SinglePropabilityMap::create(2));
assert_eq!(
encoded.0,
vec![ZleSymbol::Number(1), ZleSymbol::RunA, ZleSymbol::RunA]
);
}
#[test]
fn decodes_zeros_and_numbers() {
let encoded = decode_zle(&[ZleSymbol::Number(1), ZleSymbol::RunA, ZleSymbol::RunA]);
assert_eq!(encoded, vec![1, 0, 0, 0]);
}
#[test]
fn encodes_zeros_and_trailing_numbers() {
let encoded = zle_transform(vec![1, 0, 0, 0, 2], SinglePropabilityMap::create(3)).0;
assert_eq!(
encoded,
vec![
ZleSymbol::Number(1),
ZleSymbol::RunA,
ZleSymbol::RunA,
ZleSymbol::Number(2)
]
);
}
#[test]
fn decodes_zeros_and_trailing_numbers() {
let encoded = decode_zle(&[
ZleSymbol::Number(1),
ZleSymbol::RunA,
ZleSymbol::RunA,
ZleSymbol::Number(2),
]);
assert_eq!(encoded, vec![1, 0, 0, 0, 2]);
}
#[test]
fn encodes_numbers_and_trailing_zeroes() {
let encoded = zle_transform(vec![1, 0, 0, 0, 2, 0, 0], SinglePropabilityMap::create(3));
assert_eq!(
encoded.0,
vec![
ZleSymbol::Number(1),
ZleSymbol::RunA,
ZleSymbol::RunA,
ZleSymbol::Number(2),
ZleSymbol::RunB,
]
);
}
}