use crate::error::ErrorKind;
use nom::bytes::streaming::{take, take_while};
use nom::number::streaming::be_u8;
use nom::sequence::terminated;
use nom::Err::Failure;
use nom::IResult;
use uuid::Uuid;
pub fn twint(input: &[u8]) -> IResult<&[u8], i32, ErrorKind> {
let mut result = 0;
let mut len = 1;
let mut next = be_u8(input)?;
let mut src = next.1;
let sign = ((src >> 6) & 1) as i32;
result |= (src & 0b0011_1111) as i32;
for i in 0..4 {
if src & 0b1000_0000 == 0 {
break;
}
next = be_u8(next.0)?;
src = next.1;
len += 1;
if i == 3 && src & 0b1111_0000 != 0 {
return Err(Failure(ErrorKind::NonZeroIntPadding));
}
result |= ((src & 0b0111_1111) as i32) << (6 + 7 * i);
}
if len > 1 && src == 0b0000_0000 {
return Err(Failure(ErrorKind::OverlongIntEncoding));
}
result ^= -sign;
Ok((next.0, result))
}
pub fn cstring(input: &[u8]) -> IResult<&[u8], &[u8], ErrorKind> {
terminated(take_while(|c| c != b'\0'), take(1usize))(input)
}
pub fn uuid(input: &[u8]) -> IResult<&[u8], Uuid, ErrorKind> {
let (input, slice) = take(16usize)(input)?;
Ok((input, Uuid::from_slice(slice).unwrap()))
}
#[cfg(test)]
mod test {
use super::*;
fn assert_twint(input: &[u8], remaining: &[u8], result: i32) {
assert_eq!(twint(input), Ok((remaining, result)));
}
fn assert_twint_err(input: &[u8]) {
assert!(twint(input).is_err());
}
#[test]
fn twint_0() {
assert_twint(b"\x00", b"", 0)
}
#[test]
fn twint_1() {
assert_twint(b"\x01", b"", 1)
}
#[test]
fn twint_63() {
assert_twint(b"\x3f", b"", 63)
}
#[test]
fn twint_m1() {
assert_twint(b"\x40", b"", -1)
}
#[test]
fn twint_64() {
assert_twint(b"\x80\x01", b"", 64)
}
#[test]
fn twint_m65() {
assert_twint(b"\xc0\x01", b"", -65)
}
#[test]
fn twint_m64() {
assert_twint(b"\x7f", b"", -64)
}
#[test]
fn twint_min() {
assert_twint(b"\xff\xff\xff\xff\x0f", b"", i32::min_value())
}
#[test]
fn twint_max() {
assert_twint(b"\xbf\xff\xff\xff\x0f", b"", i32::max_value())
}
#[test]
fn twint_empty() {
assert_twint_err(b"")
}
#[test]
fn twint_extend_empty() {
assert_twint_err(b"\x80")
}
#[test]
fn uuid_teehistorian() {
assert_eq!(
Ok((
&b""[..],
Uuid::parse_str("699db17b-8efb-34ff-b1d8-da6f60c15dd1").unwrap()
)),
uuid(b"\x69\x9d\xb1\x7b\x8e\xfb\x34\xff\xb1\xd8\xda\x6f\x60\xc1\x5d\xd1"),
);
}
fn assert_cstring(input: &[u8], remaining: &[u8], result: &[u8]) {
assert_eq!(cstring(input), Ok((remaining, result)));
}
fn assert_cstring_err(input: &[u8]) {
assert!(cstring(input).is_err());
}
#[test]
fn cstr_empty() {
assert_cstring(b"\0", b"", b"")
}
#[test]
fn cstr_none() {
assert_cstring_err(b"")
}
#[test]
fn cstr_no_nul() {
assert_cstring_err(b"abc")
}
#[test]
fn cstr_rest1() {
assert_cstring(b"abc\0def", b"def", b"abc")
}
#[test]
fn cstr_rest2() {
assert_cstring(b"abc\0", b"", b"abc")
}
#[test]
fn cstr_rest3() {
assert_cstring(b"abc\0\0", b"\0", b"abc")
}
#[test]
fn cstr_rest4() {
assert_cstring(b"\0\0", b"\0", b"")
}
}