use crate::types::Bit;
const fn toggle(bit: Bit) -> Bit {
match bit {
Bit::Zero => Bit::One,
Bit::One => Bit::Zero,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NrziEncoder {
level: Bit,
}
impl NrziEncoder {
#[must_use]
pub const fn new(initial: Bit) -> Self {
Self { level: initial }
}
pub const fn encode(&mut self, bit: Bit) -> Bit {
self.level = match bit {
Bit::Zero => toggle(self.level),
Bit::One => self.level,
};
self.level
}
pub fn encode_iter<I>(self, bits: I) -> EncodeIter<I>
where
I: Iterator<Item = Bit>,
{
EncodeIter {
encoder: self,
bits,
}
}
}
impl Default for NrziEncoder {
fn default() -> Self {
Self::new(Bit::One)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NrziDecoder {
prev: Bit,
}
impl NrziDecoder {
#[must_use]
pub const fn new(initial: Bit) -> Self {
Self { prev: initial }
}
pub const fn decode(&mut self, line: Bit) -> Bit {
let out = match (line, self.prev) {
(Bit::Zero, Bit::Zero) | (Bit::One, Bit::One) => Bit::One,
(Bit::Zero, Bit::One) | (Bit::One, Bit::Zero) => Bit::Zero,
};
self.prev = line;
out
}
pub fn decode_iter<I>(self, bits: I) -> DecodeIter<I>
where
I: Iterator<Item = Bit>,
{
DecodeIter {
decoder: self,
bits,
}
}
}
impl Default for NrziDecoder {
fn default() -> Self {
Self::new(Bit::One)
}
}
pub fn encode_iter<I>(bits: I) -> EncodeIter<I>
where
I: Iterator<Item = Bit>,
{
NrziEncoder::default().encode_iter(bits)
}
pub fn decode_iter<I>(bits: I) -> DecodeIter<I>
where
I: Iterator<Item = Bit>,
{
NrziDecoder::default().decode_iter(bits)
}
#[derive(Debug, Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct EncodeIter<I> {
encoder: NrziEncoder,
bits: I,
}
impl<I> Iterator for EncodeIter<I>
where
I: Iterator<Item = Bit>,
{
type Item = Bit;
fn next(&mut self) -> Option<Bit> {
self.bits.next().map(|bit| self.encoder.encode(bit))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.bits.size_hint()
}
}
#[derive(Debug, Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct DecodeIter<I> {
decoder: NrziDecoder,
bits: I,
}
impl<I> Iterator for DecodeIter<I>
where
I: Iterator<Item = Bit>,
{
type Item = Bit;
fn next(&mut self) -> Option<Bit> {
self.bits.next().map(|bit| self.decoder.decode(bit))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.bits.size_hint()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn pseudo_random_bits(seed: u32, len: usize) -> impl Iterator<Item = Bit> {
let mut state = seed | 1;
core::iter::repeat_with(move || {
state ^= state << 13;
state ^= state >> 17;
state ^= state << 5;
Bit::from(state & 1 != 0)
})
.take(len)
}
fn roundtrip(data: &[Bit], initial: Bit) {
let mut enc = NrziEncoder::new(initial);
let mut dec = NrziDecoder::new(initial);
for &bit in data {
let line = enc.encode(bit);
assert_eq!(dec.decode(line), bit);
}
}
#[test]
fn roundtrip_structured_sequences_both_initial_states() {
let sequences: &[&[Bit]] = &[
&[],
&[Bit::Zero],
&[Bit::One],
&[Bit::Zero, Bit::One, Bit::One, Bit::Zero, Bit::Zero],
&[Bit::One; 16],
&[Bit::Zero; 16],
&[
Bit::Zero,
Bit::One,
Bit::One,
Bit::One,
Bit::One,
Bit::One,
Bit::One,
Bit::Zero, ],
];
for &seq in sequences {
roundtrip(seq, Bit::Zero);
roundtrip(seq, Bit::One);
}
}
#[test]
fn roundtrip_pseudo_random_sequences() {
for seed in [1, 0xDEAD_BEEF, 0x1234_5678] {
for initial in [Bit::Zero, Bit::One] {
let mut enc = NrziEncoder::new(initial);
let mut dec = NrziDecoder::new(initial);
for bit in pseudo_random_bits(seed, 4096) {
assert_eq!(dec.decode(enc.encode(bit)), bit);
}
}
}
}
#[test]
fn all_ones_stall_encoding_holds_line() {
for initial in [Bit::Zero, Bit::One] {
let mut enc = NrziEncoder::new(initial);
for _ in 0..64 {
assert_eq!(enc.encode(Bit::One), initial);
}
}
}
#[test]
fn constant_line_decodes_to_all_ones_after_first_bit() {
for level in [Bit::Zero, Bit::One] {
for initial in [Bit::Zero, Bit::One] {
let mut dec = NrziDecoder::new(initial);
let first = dec.decode(level);
assert_eq!(first, Bit::from(level == initial));
for _ in 0..64 {
assert_eq!(dec.decode(level), Bit::One);
}
}
}
}
#[test]
fn all_zeros_yields_alternating_line() {
for initial in [Bit::Zero, Bit::One] {
let mut enc = NrziEncoder::new(initial);
let mut expected = initial;
for _ in 0..64 {
expected = toggle(expected);
assert_eq!(enc.encode(Bit::Zero), expected);
}
}
}
#[test]
fn decoder_self_synchronizes_after_one_bit() {
for enc_initial in [Bit::Zero, Bit::One] {
let dec_initial = toggle(enc_initial);
let mut enc = NrziEncoder::new(enc_initial);
let mut dec = NrziDecoder::new(dec_initial);
for (index, bit) in pseudo_random_bits(42, 1024).enumerate() {
let out = dec.decode(enc.encode(bit));
if index == 0 {
assert_eq!(out, toggle(bit), "first bit must be inverted");
} else {
assert_eq!(out, bit, "must match from the second bit on");
}
}
}
}
#[test]
fn iterator_adapters_agree_with_push_api() {
let data: [Bit; 8] = [
Bit::One,
Bit::Zero,
Bit::Zero,
Bit::One,
Bit::One,
Bit::One,
Bit::Zero,
Bit::One,
];
for initial in [Bit::Zero, Bit::One] {
let mut enc = NrziEncoder::new(initial);
let mut dec = NrziDecoder::new(initial);
let it_enc = NrziEncoder::new(initial).encode_iter(data.iter().copied());
for (bit, line_from_iter) in data.iter().copied().zip(it_enc) {
let line = enc.encode(bit);
assert_eq!(line, line_from_iter);
assert_eq!(dec.decode(line), bit);
}
let round = NrziDecoder::new(initial)
.decode_iter(NrziEncoder::new(initial).encode_iter(data.iter().copied()));
let mut count = 0usize;
for (out, expected) in round.zip(data.iter().copied()) {
assert_eq!(out, expected);
count += 1;
}
assert_eq!(count, data.len());
}
}
#[test]
fn free_functions_use_default_initial_state() {
let data = [Bit::Zero, Bit::One, Bit::Zero];
let via_free: [Option<Bit>; 3] = {
let mut it = encode_iter(data.iter().copied());
[it.next(), it.next(), it.next()]
};
let via_struct: [Option<Bit>; 3] = {
let mut it = NrziEncoder::default().encode_iter(data.iter().copied());
[it.next(), it.next(), it.next()]
};
assert_eq!(via_free, via_struct);
let line = [Bit::Zero, Bit::Zero, Bit::One];
let d_free: [Option<Bit>; 3] = {
let mut it = decode_iter(line.iter().copied());
[it.next(), it.next(), it.next()]
};
let d_struct: [Option<Bit>; 3] = {
let mut it = NrziDecoder::default().decode_iter(line.iter().copied());
[it.next(), it.next(), it.next()]
};
assert_eq!(d_free, d_struct);
}
#[test]
fn default_initial_state_is_one() {
assert_eq!(NrziEncoder::default(), NrziEncoder::new(Bit::One));
assert_eq!(NrziDecoder::default(), NrziDecoder::new(Bit::One));
}
#[test]
fn size_hints_pass_through() {
let data = [Bit::One, Bit::Zero];
assert_eq!(encode_iter(data.iter().copied()).size_hint(), (2, Some(2)));
assert_eq!(decode_iter(data.iter().copied()).size_hint(), (2, Some(2)));
}
}