use crate::tokens::{Flipped, NotFlipped};
pub trait MaybeFlipped<const N: usize> {
fn calculate(
position: usize,
bytes: impl DoubleEndedIterator<Item = u8> + ExactSizeIterator<Item = u8>,
) -> (
usize,
impl DoubleEndedIterator<Item = u8> + ExactSizeIterator<Item = u8>,
);
fn position(position: usize, len: usize) -> usize;
fn flip() -> impl MaybeFlipped<N>;
}
impl<const N: usize> MaybeFlipped<N> for NotFlipped {
fn calculate(
position: usize,
bytes: impl DoubleEndedIterator<Item = u8> + ExactSizeIterator<Item = u8>,
) -> (
usize,
impl DoubleEndedIterator<Item = u8> + ExactSizeIterator<Item = u8>,
) {
(position, bytes)
}
fn position(position: usize, _: usize) -> usize {
position
}
fn flip() -> impl MaybeFlipped<N> {
Flipped
}
}
impl<const N: usize> MaybeFlipped<N> for Flipped {
fn calculate(
position: usize,
bytes: impl DoubleEndedIterator<Item = u8> + ExactSizeIterator<Item = u8>,
) -> (
usize,
impl DoubleEndedIterator<Item = u8> + ExactSizeIterator<Item = u8>,
) {
fn calculate_bytes<const N: usize>(
bytes: impl DoubleEndedIterator<Item = u8> + ExactSizeIterator<Item = u8>,
position: usize,
) -> impl DoubleEndedIterator<Item = u8> + ExactSizeIterator<Item = u8> {
#[auto_enums::enum_derive(DoubleEndedIterator)]
enum I<A, B, C> {
A(A),
B(B),
C(C),
}
impl<
A: ExactSizeIterator<Item = u8>,
B: ExactSizeIterator<Item = u8>,
C: ExactSizeIterator<Item = u8>,
> ExactSizeIterator for I<A, B, C>
{
fn len(&self) -> usize {
match self {
I::A(a) => a.len(),
I::B(b) => b.len(),
I::C(c) => c.len(),
}
}
}
if position > N {
return I::C(::core::iter::empty());
}
match bytes.len() + position > N {
true => I::A(bytes.take(N - position).rev()),
false => I::B(bytes.rev()),
}
}
let new_position = match bytes.len() + position > N {
true => 0,
false => N - bytes.len() - position,
};
let bytes = calculate_bytes::<N>(bytes, position);
(new_position, bytes.map(crate::mappings::flip_mirror))
}
fn position(position: usize, len: usize) -> usize {
match len + position > N {
true => 0,
false => N - len - position,
}
}
fn flip() -> impl MaybeFlipped<N> {
NotFlipped
}
}
#[cfg(test)]
mod tests {
extern crate std;
use std::vec;
use std::vec::Vec;
use crate::mappings::{DigitBits, UpCharBits};
use super::*;
#[test]
fn flipped() {
let iter = [DigitBits::Zero as u8].iter().copied();
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(0, iter.clone());
let bytes = bytes.collect::<Vec<u8>>();
assert_eq!(position, 2);
assert_eq!(bytes, vec![DigitBits::Zero as u8]);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(1, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 1);
assert_eq!(bytes, vec![DigitBits::Zero as u8]);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(2, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 0);
assert_eq!(bytes, vec![DigitBits::Zero as u8]);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(3, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 0);
assert_eq!(bytes, vec![]);
let iter = [DigitBits::Zero as u8, DigitBits::Eight as u8]
.iter()
.copied();
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(0, iter.clone());
let bytes = bytes.collect::<Vec<u8>>();
assert_eq!(position, 1);
assert_eq!(bytes, vec![DigitBits::Eight as u8, DigitBits::Zero as u8]);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(1, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 0);
assert_eq!(bytes, vec![DigitBits::Eight as u8, DigitBits::Zero as u8]);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(2, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 0);
assert_eq!(bytes, vec![DigitBits::Zero as u8]);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(3, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 0);
assert_eq!(bytes, vec![]);
let iter = [
DigitBits::Zero as u8,
DigitBits::Eight as u8,
DigitBits::Three as u8,
]
.iter()
.copied();
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(0, iter.clone());
let bytes = bytes.collect::<Vec<u8>>();
assert_eq!(position, 0);
assert_eq!(
bytes,
vec![
UpCharBits::UpE as u8,
DigitBits::Eight as u8,
DigitBits::Zero as u8
]
);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(1, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 0);
assert_eq!(bytes, vec![DigitBits::Eight as u8, DigitBits::Zero as u8]);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(2, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 0);
assert_eq!(bytes, vec![DigitBits::Zero as u8]);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(3, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 0);
assert_eq!(bytes, vec![]);
let iter = [
DigitBits::Zero as u8,
DigitBits::Eight as u8,
DigitBits::Three as u8,
DigitBits::Eight as u8,
]
.iter()
.copied();
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(0, iter.clone());
let bytes = bytes.collect::<Vec<u8>>();
assert_eq!(position, 0);
assert_eq!(
bytes,
vec![
UpCharBits::UpE as u8,
DigitBits::Eight as u8,
DigitBits::Zero as u8,
]
);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(1, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 0);
assert_eq!(bytes, vec![DigitBits::Eight as u8, DigitBits::Zero as u8,]);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(2, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 0);
assert_eq!(bytes, vec![DigitBits::Zero as u8,]);
let (position, bytes) = <Flipped as MaybeFlipped<3>>::calculate(3, iter.clone());
let bytes = bytes.collect::<Vec<_>>();
assert_eq!(position, 0);
assert_eq!(bytes, vec![]);
}
}