use std::{error, fmt};
use std::marker::PhantomData;
pub trait Base {
fn pad(&self) -> u8;
fn val(&self, x: u8) -> Option<u8>;
fn bit(&self) -> usize {
let mut n = 0;
for s in 0..128u8 {
if self.val(s).is_some() {
n += 1;
}
}
let mut b = 0;
while n > 1 {
n /= 2;
b += 1;
}
return b;
}
fn sym(&self, x: u8) -> u8 {
for s in 0..128u8 {
match self.val(s) {
Some(v) if v == x => return s,
_ => (),
}
}
unreachable!();
}
}
pub fn mask<B: Base>(base: &B) -> u8 {
(1 << base.bit()) - 1
}
pub fn len<B: Base>(base: &B) -> usize {
match base.bit() {
1 | 2 | 4 => 8,
3 | 6 => 24,
5 => 40,
_ => unreachable!(),
}
}
pub fn enc<B: Base>(base: &B) -> usize {
len(base) / 8
}
pub fn dec<B: Base>(base: &B) -> usize {
len(base) / base.bit()
}
pub struct Opt<T> {
pub val: &'static [u8],
pub sym: &'static [u8],
pub bit: u8,
pub pad: u8,
pub _phantom: PhantomData<T>,
}
impl<T> Base for Opt<T> {
fn bit(&self) -> usize {
self.bit as usize
}
fn pad(&self) -> u8 {
self.pad
}
fn val(&self, x: u8) -> Option<u8> {
let v = self.val[x as usize];
if v < 128 { Some(v) } else { None }
}
fn sym(&self, x: u8) -> u8 {
self.sym[x as usize]
}
}
pub struct Spec {
pub val: &'static [(u8, u8)],
pub pad: u8,
}
impl Base for Spec {
fn pad(&self) -> u8 {
self.pad
}
fn val(&self, x: u8) -> Option<u8> {
let mut t = 0;
for &(l, u) in self.val {
if l <= x && x <= u {
return Some(t + x - l);
}
t += u - l + 1;
}
None
}
}
#[derive(Clone,Copy,Debug,PartialEq,Eq)]
pub enum ValidError {
BadBit,
PadNotAscii,
PadSymbol,
SymNotAscii(u8),
NotValue(u8),
NotInj(u8),
NotSurj,
}
impl fmt::Display for ValidError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::ValidError::*;
match self {
&BadBit => write!(f, "Size is not 2, 4, 8, 16, 32, or 64."),
&PadNotAscii => write!(f, "Padding is not ascii."),
&PadSymbol => write!(f, "Padding is a symbol."),
&SymNotAscii(s) => write!(f, "Symbol {:?} is not ascii.", s as char),
&NotValue(s) => write!(f, "Symbol {:?} is not mapped to a value.", s as char),
&NotInj(s) => write!(f, "Symbol {:?} is not uniquely mapped to its value.", s as char),
&NotSurj => write!(f, "All values do not have an associated symbol."),
}
}
}
impl error::Error for ValidError {
fn description(&self) -> &str {
use self::ValidError::*;
match self {
&BadBit => "size must be 2, 4, 8, 16, 32, or 64",
&PadNotAscii => "padding must be ascii",
&PadSymbol => "padding must not be a symbol",
&SymNotAscii(_) => "symbols must be ascii",
&NotValue(_) => "symbols must be mapped to values",
&NotInj(_) => "symbols must be uniquely mapped",
&NotSurj => "all values must be mapped",
}
}
}
pub fn valid<B: Base>(base: &B) -> Result<(), ValidError> {
use self::ValidError::*;
check!(BadBit, 1 <= base.bit() && base.bit() <= 6);
check!(PadNotAscii, base.pad() < 128);
check!(PadSymbol, base.val(base.pad()) == None);
let mut card = 0u8;
for s in 0..128u8 {
if let Some(v) = base.val(s) {
check!(NotValue(s), v < 1 << base.bit());
check!(NotInj(s), base.sym(v) == s);
card += 1;
}
let x = s + 128;
check!(SymNotAscii(x), base.val(x) == None);
}
check!(NotSurj, card == 1 << base.bit());
Ok(())
}
#[derive(Clone,Copy,Debug,PartialEq,Eq)]
pub enum EqualError {
Symbol(u8),
Padding,
}
impl fmt::Display for EqualError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::EqualError::*;
match self {
&Symbol(s) => write!(f, "Bases differ on symbol {:?}.", s as char),
&Padding => write!(f, "Bases differ on padding."),
}
}
}
impl error::Error for EqualError {
fn description(&self) -> &str {
use self::EqualError::*;
match self {
&Symbol(_) => "bases must agree on all symbols",
&Padding => "bases must agree on padding",
}
}
}
pub fn equal<B1: Base, B2: Base>(b1: &B1, b2: &B2) -> Result<(), EqualError> {
use self::EqualError::*;
check!(Padding, b1.pad() == b2.pad());
for s in 0..128u8 {
check!(Symbol(s), b1.val(s) == b2.val(s));
}
Ok(())
}