use std::fmt;
use itoa;
pub trait Parseable: Sized + From<u8> + fmt::Debug {
fn checked_mul_ten(self) -> Option<Self>;
fn checked_add(self, digit: Self) -> Option<Self>;
fn write_to(self, bytes: &mut [u8]) -> usize;
}
macro_rules! impl_parseable {
($($t:ident)*) => {
$(
impl Parseable for $t {
fn checked_mul_ten(self) -> Option<Self> {
self.checked_mul(10)
}
fn checked_add(self, rhs: Self) -> Option<Self> {
self.checked_add(rhs)
}
fn write_to(self, bytes: &mut [u8]) -> usize {
itoa::write(bytes, self).unwrap()
}
}
)*
}
}
impl_parseable! { u8 u16 u32 u64 }
pub enum ParseUintError {
Empty,
BadByte(u8),
Overflow,
}
pub fn parse_uint<T: Parseable>(bytes: &[u8]) -> Result<T, ParseUintError> {
let mut iter = bytes.iter().map(|&d| {
(d as char)
.to_digit(10)
.map(|d| T::from(d as u8))
.ok_or_else(|| ParseUintError::BadByte(d))
});
match iter.next() {
Some(digit) => {
iter.fold(digit, |curr, digit| {
digit.and_then(|digit| {
curr.and_then(|curr| {
curr.checked_mul_ten()
.and_then(|curr| curr.checked_add(digit))
.ok_or(ParseUintError::Overflow)
})
})
})
}
None => Err(ParseUintError::Empty),
}
}