use std;
pub fn literal<'a, T: AsRef<[u8]>>(src: &mut &'a[u8], what: T) -> ::Result<()> {
let what = what.as_ref();
if !src.starts_with(what) {
return Err("invalid literal")
}
*src = &src[what.len()..];
Ok(())
}
#[test]
fn test_literal() {
let mut src = "tuonen joutsen 123%&#".as_bytes();
literal(&mut src, "tuonen").unwrap();
assert_eq!(b" joutsen 123%&#", src);
literal(&mut src, "").unwrap();
literal(&mut src, " joutsen 123%").unwrap();
assert_eq!(b"&#", src);
assert!(literal(&mut src, "k").is_err());
assert!(literal(&mut src, "&#o").is_err());
literal(&mut src, "&#").unwrap();
assert_eq!(0, src.len());
}
pub fn whitespace_if_any<'a>(src: &mut &'a[u8]) {
let mut i = 0;
while i < src.len() && is_whitespace(src[i]) {
i += 1;
}
*src = &src[i..];
}
pub fn whitespace<'a>(src: &mut &'a[u8]) -> ::Result<()> {
if src.len() < 1 || !is_whitespace(src[0]) {
return Err("no whitespace")
}
*src = &src[1..];
Ok(whitespace_if_any(src))
}
#[test]
fn test_whitespace() {
let mut src = "\n\t\r\n yyy \n\r\t\nzzz".as_bytes();
whitespace(&mut src).unwrap();
assert_eq!(b"yyy \n\r\t\nzzz", src);
literal(&mut src, "yyy").unwrap();
whitespace_if_any(&mut src);
assert_eq!(b"zzz", src);
whitespace_if_any(&mut src);
assert_eq!(b"zzz", src);
}
macro_rules! uint {
($T:ident) => {
pub fn $T(src: &mut &[u8]) -> ::Result<$T> {
let mut v = 0 as $T;
let mut i = 0;
let q = std::$T::MAX / 10;
let e = std::$T::MAX % 10;
while i < src.len() && is_digit(src[i]) {
let number = (src[i] - b'0') as $T;
if v > q || (v == q && number > e) {
return Err("invalid uint: overflow")
}
v = v * 10 + number;
i += 1;
}
if i == 0 {
return Err("invalid uint")
}
*src = &src[i..];
Ok(v)
}
}
}
uint!(u8);
uint!(u16);
uint!(u32);
uint!(u64);
#[test]
fn test_uint() {
let mut src = "1k".as_bytes();
assert_eq!(1u8, u8(&mut src).unwrap());
assert_eq!(b"k", src);
assert_eq!(1u8, u8(&mut "01".as_bytes()).unwrap());
assert_eq!(0u8, u8(&mut "0".as_bytes()).unwrap());
assert_eq!(255_u8, u8(&mut "255".as_bytes()).unwrap());
assert_eq!(256_u16, u16(&mut "256".as_bytes()).unwrap());
assert_eq!(65535_u16, u16(&mut "65535".as_bytes()).unwrap());
assert_eq!(4294967295_u32, u32(&mut "4294967295".as_bytes()).unwrap());
assert_eq!(18446744073709551615_u64, u64(&mut "18446744073709551615".as_bytes()).unwrap());
assert!(u8(&mut "256".as_bytes()).is_err());
assert!(u8(&mut "1000".as_bytes()).is_err());
assert!(u16(&mut "65536".as_bytes()).is_err());
assert!(u16(&mut "100000".as_bytes()).is_err());
assert!(u32(&mut "4294967296".as_bytes()).is_err());
assert!(u32(&mut "10000000000".as_bytes()).is_err());
assert!(u64(&mut "18446744073709551616".as_bytes()).is_err());
assert!(u64(&mut "100000000000000000000".as_bytes()).is_err());
assert!(u32(&mut "".as_bytes()).is_err());
assert!(u32(&mut "-255".as_bytes()).is_err());
assert!(u32(&mut "q".as_bytes()).is_err());
}
macro_rules! int {
($T:ident) => {
pub fn $T(src: &mut &[u8]) -> ::Result<$T> {
if src.len() == 0 {
return Err("invalid int: nothing to parse")
}
let mut i = 0;
let digit_offset;
let positive = src[0] != b'-';
if src[0] == b'-' || src[0] == b'+' {
i += 1;
digit_offset = 1;
} else {
digit_offset = 0;
}
let mut v = 0 as $T;
let q = if positive { std::$T::MAX / 10 } else { -(std::$T::MIN / 10) };
let e = if positive { std::$T::MAX % 10 } else { -(std::$T::MIN % 10) };
while i < src.len() && is_digit(src[i]) {
let number = (src[i] - b'0') as $T;
if v > q || (v == q && number > e) {
return Err("invalid int: overflow")
}
v = (v * 10).wrapping_add(number); i += 1;
}
if i <= digit_offset {
return Err("invalid int")
}
*src = &src[i..];
Ok(if positive { v } else { v.wrapping_neg() }) }
}
}
int!(i8);
int!(i16);
int!(i32);
int!(i64);
#[test]
fn test_int() {
let mut src = "1k".as_bytes();
assert_eq!(1i8, i8(&mut src).unwrap());
assert_eq!(b"k", src);
assert_eq!(1i8, i8(&mut "01".as_bytes()).unwrap());
assert_eq!(0i8, i8(&mut "0".as_bytes()).unwrap());
assert_eq!(1i8, i8(&mut "+1".as_bytes()).unwrap());
assert_eq!(-8i8, i8(&mut "-8".as_bytes()).unwrap());
assert_eq!(-128i8, i8(&mut "-128".as_bytes()).unwrap());
assert_eq!(127i8, i8(&mut "127".as_bytes()).unwrap());
assert_eq!(-32768_i16, i16(&mut "-32768".as_bytes()).unwrap());
assert_eq!(32767_i16, i16(&mut "32767".as_bytes()).unwrap());
assert_eq!(-2147483648_i32, i32(&mut "-2147483648".as_bytes()).unwrap());
assert_eq!(2147483647_i32, i32(&mut "2147483647".as_bytes()).unwrap());
assert_eq!(-9223372036854775808_i64, i64(&mut "-9223372036854775808".as_bytes()).unwrap());
assert_eq!(9223372036854775807_i64, i64(&mut "9223372036854775807".as_bytes()).unwrap());
assert!(i8(&mut "-129".as_bytes()).is_err());
assert!(i8(&mut "-1000".as_bytes()).is_err());
assert!(i8(&mut "128".as_bytes()).is_err());
assert!(i8(&mut "1000".as_bytes()).is_err());
assert!(i16(&mut "-32769".as_bytes()).is_err());
assert!(i16(&mut "-100000".as_bytes()).is_err());
assert!(i16(&mut "32768".as_bytes()).is_err());
assert!(i16(&mut "100000".as_bytes()).is_err());
assert!(i32(&mut "-2147483649".as_bytes()).is_err());
assert!(i32(&mut "-10000000000".as_bytes()).is_err());
assert!(i32(&mut "2147483648".as_bytes()).is_err());
assert!(i32(&mut "10000000000".as_bytes()).is_err());
assert!(i64(&mut "-9223372036854775809".as_bytes()).is_err());
assert!(i64(&mut "-10000000000000000000".as_bytes()).is_err());
assert!(i64(&mut "9223372036854775808".as_bytes()).is_err());
assert!(i64(&mut "10000000000000000000".as_bytes()).is_err());
assert!(i32(&mut "".as_bytes()).is_err());
assert!(i32(&mut "-".as_bytes()).is_err());
assert!(i32(&mut "+".as_bytes()).is_err());
assert!(i32(&mut "q".as_bytes()).is_err());
}
pub fn f32(src: &mut &[u8]) -> ::Result<f32> {
use std::str::{self, FromStr};
if src.len() == 0 {
return Err("invalid float: nothing to parse")
}
let mut i = 0;
if src[i] == b'-' || src[i] == b'+' {
i += 1;
}
while i < src.len() && is_digit(src[i]) {
i += 1;
}
if i < src.len() && src[i] == b'.' {
i += 1;
while i < src.len() && is_digit(src[i]) {
i += 1;
}
}
if i + 1 < src.len() && src[i] == b'e' {
if is_digit(src[i+1]) {
i += 2;
} else if i + 2 < src.len() && src[i+1] == b'-' && is_digit(src[i+2]) {
i += 3;
} else {
return Err("invalid float")
}
while i < src.len() && is_digit(src[i]) {
i += 1;
}
}
let s = unsafe { str::from_utf8_unchecked(&src[..i]) };
if let Ok(v) = FromStr::from_str(s) {
*src = &src[i..];
return Ok(v)
}
Err("invalid float")
}
#[test]
fn test_f32() {
assert_eq!(32., f32(&mut "+32".as_bytes()).unwrap());
assert_eq!(-32., f32(&mut "-32".as_bytes()).unwrap());
assert_eq!(32., f32(&mut "32".as_bytes()).unwrap());
assert_eq!(32e2, f32(&mut "32e2".as_bytes()).unwrap());
assert_eq!(32., f32(&mut "32.".as_bytes()).unwrap());
assert_eq!(32e2, f32(&mut "32.e2".as_bytes()).unwrap());
assert_eq!(32_f32, f32(&mut "32.0".as_bytes()).unwrap());
assert_eq!(32e2, f32(&mut "32.0e2".as_bytes()).unwrap());
assert_eq!(0.32, f32(&mut "32.0e-2".as_bytes()).unwrap());
}
pub fn bool(src: &mut &[u8]) -> ::Result<bool> {
if src.starts_with(b"true") {
*src = &src[4..];
return Ok(true)
} else if src.starts_with(b"false") {
*src = &src[5..];
return Ok(false)
}
Err("invalid bool")
}
#[test]
fn test_bool() {
assert_eq!(true, bool(&mut "true".as_bytes()).unwrap());
assert_eq!(false, bool(&mut "false".as_bytes()).unwrap());
assert_eq!(false, bool(&mut "falsee".as_bytes()).unwrap()); assert!(bool(&mut "tru".as_bytes()).is_err());
assert!(bool(&mut "trudat".as_bytes()).is_err());
assert!(bool(&mut "fals".as_bytes()).is_err());
}
macro_rules! hex {
($T:ident, $name:ident) => {
pub fn $name(src: &mut &[u8]) -> ::Result<$T> {
let mut v = 0 as $T;
let mut i = 0;
let q = std::$T::MAX / 16; let mut number = 0;
while i < src.len() && hex_digit_to_value(src[i], &mut number) {
if v > q {
return Err("invalid hex: overflow")
}
v = v * 16 + number as $T;
i += 1;
}
if i == 0 {
return Err("invalid hex")
}
*src = &src[i..];
Ok(v)
}
}
}
hex!(u8, hex_u8);
hex!(u16, hex_u16);
hex!(u32, hex_u32);
hex!(u64, hex_u64);
#[test]
fn test_hex() {
let mut src = "1k".as_bytes();
assert_eq!(1u8, hex_u8(&mut src).unwrap());
assert_eq!(b"k", src);
assert_eq!(1u8, hex_u8(&mut "01".as_bytes()).unwrap());
assert_eq!(10u8, hex_u8(&mut "a".as_bytes()).unwrap());
assert_eq!(16u8, hex_u8(&mut "10".as_bytes()).unwrap());
assert_eq!(255u8, hex_u8(&mut "ff".as_bytes()).unwrap());
assert_eq!(256u16, hex_u16(&mut "100".as_bytes()).unwrap());
assert_eq!(65535_u16, hex_u16(&mut "ffff".as_bytes()).unwrap());
assert_eq!(0xffff_ffff_u32, hex_u32(&mut "ffffffff".as_bytes()).unwrap());
assert_eq!(0xffff_ffff_u32, hex_u32(&mut "FFFFFFFF".as_bytes()).unwrap());
assert_eq!(0xffff_ffff_ffff_ffff_u64, hex_u64(&mut "ffffffffffffffff".as_bytes()).unwrap());
assert!(hex_u8(&mut "100".as_bytes()).is_err());
assert!(hex_u16(&mut "10000".as_bytes()).is_err());
assert!(hex_u32(&mut "100000000".as_bytes()).is_err());
assert!(hex_u64(&mut "10000000000000000".as_bytes()).is_err());
}
pub fn hex_string<'a>(src: &mut &[u8], dst: &'a mut[u8]) -> ::Result<()> {
if src.len() < 2 * dst.len() {
return Err("not enough digits for hex string")
}
let mut high = 0;
let mut low = 0;
let mut i = 0;
for d in &mut dst[..] {
if !hex_digit_to_value(src[i], &mut high)
|| !hex_digit_to_value(src[i+1], &mut low) {
return Err("invalid hex string")
}
*d = high * 16 + low;
i += 2;
}
*src = &src[i..];
Ok(())
}
#[test]
fn test_hex_string() {
let mut src = "AAbb70b7e752fcc3f51decbc656270834ed45a39 readme.txt".as_bytes();
let mut hash = [0u8; 20];
let res = b"\xAA\xbb\x70\xb7\xe7\x52\xfc\xc3\xf5\x1d\
\xec\xbc\x65\x62\x70\x83\x4e\xd4\x5a\x39";
hex_string(&mut src, &mut hash[..]).unwrap();
assert_eq!(&res[..], &hash[..]);
assert_eq!(b" readme.txt", src);
let mut src = "bb70b7e752fcc3f51decbc656270834ed45a39".as_bytes(); assert!(hex_string(&mut src, &mut hash[..]).is_err());
}
#[inline]
pub fn is_whitespace(c: u8) -> bool {
c == b' ' || c == b'\t' || c == b'\n' || c == b'\r'
}
#[inline]
pub fn is_digit(c: u8) -> bool {
b'0' <= c && c <= b'9'
}
pub fn hex_digit_to_value(digit: u8, out: &mut u8) -> bool {
if b'0' <= digit && digit <= b'9' {
*out = digit - b'0';
} else if b'a' <= digit && digit <= b'f' {
*out = digit - b'a' + 10;
} else if b'A' <= digit && digit <= b'F' {
*out = digit - b'A' + 10;
} else {
return false
}
true
}
pub mod bin {
use std::mem;
macro_rules! int_be {
($T:ident, $name:ident) => {
pub fn $name(src: &mut &[u8]) -> ::Result<$T> {
if src.len() < mem::size_of::<$T>() {
return Err("can't parse integer")
}
let res = $T::from_be(*unsafe { mem::transmute::<&u8, &$T>(&src[0]) });
*src = &src[mem::size_of::<$T>()..];
Ok(res)
}
}
}
int_be!(u8, u8);
int_be!(i8, i8);
int_be!(u16, u16_be);
int_be!(i16, i16_be);
int_be!(u32, u32_be);
int_be!(i32, i32_be);
int_be!(u64, u64_be);
int_be!(i64, i64_be);
macro_rules! int_le {
($T:ident, $name:ident) => {
pub fn $name(src: &mut &[u8]) -> ::Result<$T> {
if src.len() < mem::size_of::<$T>() {
return Err("can't parse integer")
}
let res = $T::from_le(*unsafe { mem::transmute::<&u8, &$T>(&src[0]) });
*src = &src[mem::size_of::<$T>()..];
Ok(res)
}
}
}
int_le!(u16, u16_le);
int_le!(i16, i16_le);
int_le!(u32, u32_le);
int_le!(i32, i32_le);
int_le!(u64, u64_le);
int_le!(i64, i64_le);
#[test]
fn test_bin() {
let src = [0xff, 0x01];
assert_eq!(0xff01, u16_be(&mut &src[..]).unwrap());
assert_eq!(0x01ff, u16_le(&mut &src[..]).unwrap());
}
}