extern crate num_traits;
use std::fmt;
use std::io;
#[derive(Debug)]
pub enum ReadError {
IoError(io::Error),
Overflow,
}
impl fmt::Display for ReadError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
ReadError::IoError(ref e) => e.fmt(f),
ReadError::Overflow => write!(f, "encoded integer overflows the type"),
}
}
}
impl std::error::Error for ReadError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
ReadError::IoError(ref e) => Some(e),
ReadError::Overflow => None,
}
}
}
impl From<io::Error> for ReadError {
fn from(e: io::Error) -> Self {
ReadError::IoError(e)
}
}
pub fn read_positive<R, I>(mut reader: R) -> Result<I, ReadError>
where
R: io::Read,
I: num_traits::PrimInt,
{
let mut number: I = I::zero();
let mut buf = [0];
loop {
reader.read_exact(&mut buf)?;
let buffer_value: u8 = buf[0];
if number > I::max_value() >> 7 {
return Err(ReadError::Overflow);
}
number = (number << 7) | I::from(buffer_value & 0x7F).unwrap();
if buffer_value & 0x80 > 0 {
if number == I::max_value() {
return Err(ReadError::Overflow);
}
number = number + I::one();
} else {
return Ok(number);
}
}
}
#[test]
fn test_reading() {
assert_eq!(0, read_positive(&mut &[0x00][..]).unwrap());
assert_eq!(1, read_positive(&mut &[0x01][..]).unwrap());
assert_eq!(127, read_positive(&mut &[0x7F][..]).unwrap());
assert_eq!(128, read_positive(&mut &[0x80, 0x00][..]).unwrap());
assert_eq!(255, read_positive(&mut &[0x80, 0x7F][..]).unwrap());
assert_eq!(256, read_positive(&mut &[0x81, 0x00][..]).unwrap());
assert_eq!(16383, read_positive(&mut &[0xFE, 0x7F][..]).unwrap());
assert_eq!(16384, read_positive(&mut &[0xFF, 0x00][..]).unwrap());
assert_eq!(16511, read_positive(&mut &[0xFF, 0x7F][..]).unwrap());
assert_eq!(65535, read_positive(&mut &[0x82, 0xFE, 0x7F][..]).unwrap());
assert_eq!(
1u64 << 32,
read_positive(&mut &[0x8E, 0xFE, 0xFE, 0xFF, 0x00][..]).unwrap()
);
}
#[derive(Debug)]
pub enum WriteError {
IoError(io::Error),
Negative,
}
impl fmt::Display for WriteError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
WriteError::IoError(ref e) => e.fmt(f),
WriteError::Negative => write!(f, "writing a negative integer is unsupported"),
}
}
}
impl std::error::Error for WriteError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
WriteError::IoError(ref e) => Some(e),
WriteError::Negative => None,
}
}
}
impl From<io::Error> for WriteError {
fn from(e: io::Error) -> Self {
WriteError::IoError(e)
}
}
pub fn write_positive<W, I>(mut writer: W, input: I) -> Result<usize, WriteError>
where
W: io::Write,
I: num_traits::PrimInt,
{
if input < I::zero() {
return Err(WriteError::Negative);
}
let mut val = input.clone();
let mut tmp = std::vec::Vec::new();
let mut index = 0;
loop {
let b = (val & I::from(0x7Fu8).unwrap())
| (if index > 0 {
I::from(0x80).unwrap()
} else {
I::zero()
});
tmp.push(b.to_u8().unwrap());
if val <= I::from(0x7Fu8).unwrap() {
break;
}
val = (val >> 7) - I::one();
index += 1;
}
tmp.reverse();
writer.write_all(tmp.as_slice())?;
Ok(tmp.len())
}
#[test]
fn test_writing() {
let testcases = vec![
(0, 1, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
(1, 1, [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
(127, 1, [0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
(128, 2, [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
(255, 2, [0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
(256, 2, [0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
(16383, 2, [0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
(16384, 2, [0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
(16511, 2, [0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
(65535, 3, [0x82, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00]),
(
1i64 << 32,
5,
[0x8E, 0xFE, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00],
),
];
for tc in testcases {
let mut buf = [0u8; 8];
assert_eq!(tc.1, write_positive(&mut buf[..], tc.0).unwrap());
assert_eq!(tc.2, buf);
}
}
#[test]
fn test_write_and_then_read() {
let mut buf = [0u8; 4096];
let mut testcases = vec![];
for i in 2..128 {
testcases.push((1u128 << i) - 1);
testcases.push(1u128 << i);
testcases.push((1u128 << i) + 1);
}
let mut writable = &mut buf[..];
for tc in testcases.clone() {
write_positive(&mut writable, tc).unwrap();
}
let mut readable = &buf[..];
for tc in testcases {
let val: u128 = read_positive(&mut readable).unwrap();
assert_eq!(tc, val);
}
}
#[test]
fn test_is_err_on_negative_write() {
let mut buf = [0u8; 8];
let mut writable = &mut buf[..];
assert!(write_positive(&mut writable, -2).is_err());
}