use std::ops::{Add, Mul};
use conv::{
NoError,
ValueFrom,
};
use conv::errors::UnwrapOk;
use types::{Buffer, Input};
use combinators::option;
use parsers::{
SimpleResult,
satisfy,
skip_while,
take_while1,
};
#[inline]
pub fn is_lowercase(c: u8) -> bool {
b'a' <= c && c <= b'z'
}
#[inline]
pub fn is_uppercase(c: u8) -> bool {
b'A' <= c && c <= b'Z'
}
#[inline]
pub fn is_whitespace(c: u8) -> bool {
9 <= c && c <= 13 || c == b' '
}
#[inline]
pub fn is_horizontal_space(c: u8) -> bool {
c == b'\t' || c == b' '
}
#[inline]
pub fn is_end_of_line(c: u8) -> bool {
c == b'\n' || c == b'\r'
}
#[inline]
pub fn is_digit(c: u8) -> bool {
b'0' <= c && c <= b'9'
}
#[inline]
pub fn is_alpha(c: u8) -> bool {
is_lowercase(c) || is_uppercase(c)
}
#[inline]
pub fn is_alphanumeric(c: u8) -> bool {
is_alpha(c) || is_digit(c)
}
#[inline]
pub fn skip_whitespace<I: Input<Token=u8>>(i: I) -> SimpleResult<I, ()> {
skip_while(i, is_whitespace)
}
#[inline]
pub fn digit<I: Input<Token=u8>>(i: I) -> SimpleResult<I, u8> {
satisfy(i, is_digit)
}
#[inline]
pub fn signed<I: Input<Token=u8>, T, F>(i: I, f: F) -> SimpleResult<I, T>
where T: Copy + ValueFrom<i8, Err=NoError> + Add<Output=T> + Mul<Output=T>,
F: FnOnce(I) -> SimpleResult<I, T> {
option(i,
|i| satisfy(i, |c| c == b'-' || c == b'+')
.map(|s| T::value_from(if s == b'+' { 1 } else { -1 }).unwrap_ok()),
T::value_from(1).unwrap_ok())
.bind(|i, sign| f(i).map(|num| sign * num))
}
#[inline]
pub fn decimal<I: Input<Token=u8>, T: Copy + ValueFrom<u8, Err=NoError> + Add<Output=T> + Mul<Output=T>>(i: I) -> SimpleResult<I, T> {
take_while1(i, is_digit).map(to_decimal)
}
#[inline]
fn to_decimal<T: Copy + ValueFrom<u8, Err=NoError> + Add<Output=T> + Mul<Output=T>, I: Buffer<Token=u8>>(iter: I) -> T {
iter.fold(T::value_from(0).unwrap_ok(), |a, n| a * T::value_from(10).unwrap_ok() + T::value_from(n - b'0').unwrap_ok())
}
#[cfg(test)]
mod test {
use super::to_decimal;
macro_rules! test_to_decimal {
( $($n:ty),+ ) => { $(
assert_eq!(to_decimal::<$n, _>(&b""[..]), 0);
assert_eq!(to_decimal::<$n, _>(&b"0"[..]), 0);
assert_eq!(to_decimal::<$n, _>(&b"1"[..]), 1);
assert_eq!(to_decimal::<$n, _>(&b"2"[..]), 2);
assert_eq!(to_decimal::<$n, _>(&b"10"[..]), 10);
assert_eq!(to_decimal::<$n, _>(&b"20"[..]), 20);
assert_eq!(to_decimal::<$n, _>(&b"25"[..]), 25);
)+ }
}
#[test]
fn test_to_decimal_u8() {
test_to_decimal!(u8, u16, u32, u64, i16, i32, i64);
}
}