use bit_vec::BitVec;
use failure::Fail;
use num::CheckedSub;
use std::fmt::{Debug, Display, Error, Formatter};
#[derive(Debug, PartialEq)]
pub enum EncodeError<T>
where
T: Debug + Send + Sync + 'static,
{
ValueTooSmall(T),
Underflow(T),
}
impl<T> Display for EncodeError<T>
where
T: Debug + Send + Sync + 'static,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
match *self {
EncodeError::ValueTooSmall(ref n) => write!(f, "value {:?} is too small to encode", n),
EncodeError::Underflow(ref n) => {
write!(f, "underflow occurred, could not encode {:?}", n)
}
}
}
}
impl<T> Fail for EncodeError<T> where T: Debug + Send + Sync + 'static {}
#[derive(Debug, PartialEq)]
pub struct ElementEncodeError<T>
where
T: Debug + Send + Sync + 'static,
{
pub index: usize,
pub error: EncodeError<T>,
}
impl<T> Fail for ElementEncodeError<T> where T: Debug + Send + Sync + 'static {}
impl<T> Display for ElementEncodeError<T>
where
T: Debug + Send + Sync + 'static,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
write!(
f,
"could not encode iterator element {:?}: {}",
self.index, self.error
)
}
}
pub trait EncodeOne
where
Self: Sized + Debug + Send + Sync,
{
fn fib_encode(self) -> Result<BitVec, EncodeError<Self>> {
let mut vec = BitVec::default();
self.fib_encode_mut(&mut vec)?;
Ok(vec)
}
fn fib_encode_mut(self, vec: &mut BitVec) -> Result<(), EncodeError<Self>>;
}
pub trait Encode<T>
where
Self: Sized + Debug + Send + Sync,
T: Debug + Send + Sync,
{
fn fib_encode(self) -> Result<BitVec, ElementEncodeError<T>> {
let mut vec = BitVec::default();
self.fib_encode_mut(&mut vec)?;
Ok(vec)
}
fn fib_encode_mut(self, vec: &mut BitVec) -> Result<(), ElementEncodeError<T>>;
}
#[inline]
pub(crate) fn bits_from_table<T>(
n: T,
table: &'static [T],
result: &mut BitVec,
) -> Result<(), EncodeError<T>>
where
T: CheckedSub + PartialOrd + Debug + Copy + Send + Sync + 'static,
{
let mut current = n;
let split_pos = table
.iter()
.rposition(|elt| *elt <= n)
.ok_or(EncodeError::ValueTooSmall::<T>(n))?;
let mut i = result.len() + split_pos + 1;
result.grow(split_pos + 2, false);
result.set(i, true);
for elt in table.split_at(split_pos + 1).0.iter().rev() {
i -= 1;
let bit = if elt > ¤t {
false
} else {
let next = match current.checked_sub(elt) {
Some(next) => next,
None => {
result.truncate(split_pos + 2);
return Err(EncodeError::Underflow(n));
}
};
current = next;
true
};
result.set(i, bit);
}
Ok(())
}