#[macro_export(local_inner_macros)]
macro_rules! bits (
($i:expr, $submac:ident!( $($args:tt)* )) => (
bits_impl!($i, $submac!($($args)*));
);
($i:expr, $f:expr) => (
bits_impl!($i, call!($f));
);
);
#[cfg(feature = "verbose-errors")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! bits_impl (
($i:expr, $submac:ident!( $($args:tt)* )) => (
{
use $crate::lib::std::result::Result::*;
use $crate::{Context,Err,Needed};
use $crate::Slice;
let input = ($i, 0usize);
match $submac!(input, $($args)*) {
Err(Err::Error(e)) => {
let err = match e {
Context::Code((i,b), kind) => Context::Code(i.slice(b/8..), kind),
Context::List(mut v) => {
Context::List(v.drain(..).map(|((i,b), kind)| (i.slice(b/8..), kind)).collect())
}
};
Err(Err::Error(err))
},
Err(Err::Failure(e)) => {
let err = match e {
Context::Code((i,b), kind) => Context::Code(i.slice(b/8..), kind),
Context::List(mut v) => {
Context::List(v.drain(..).map(|((i,b), kind)| (i.slice(b/8..), kind)).collect())
}
};
Err(Err::Failure(err))
},
Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)),
Err(Err::Incomplete(Needed::Size(i))) => {
Err(Err::Incomplete(Needed::Size(i / 8 + 1)))
},
Ok(((i, bit_index), o)) => {
let byte_index = bit_index / 8 + if bit_index % 8 == 0 { 0 } else { 1 } ;
Ok((i.slice(byte_index..), o))
}
}
}
);
);
#[cfg(not(feature = "verbose-errors"))]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! bits_impl (
($i:expr, $submac:ident!( $($args:tt)* )) => (
{
use $crate::lib::std::result::Result::*;
use $crate::{Err,Needed,Context};
use $crate::Slice;
let input = ($i, 0usize);
match $submac!(input, $($args)*) {
Err(Err::Error(e)) => {
let Context::Code(_,err) = e;
Err(Err::Error(error_position!($i, err)))
},
Err(Err::Failure(e)) => {
let Context::Code(_,err) = e;
Err(Err::Failure(error_position!($i, err)))
},
Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)),
Err(Err::Incomplete(Needed::Size(i))) => {
$crate::need_more($i, $crate::Needed::Size(i / 8 + 1))
},
Ok(((i, bit_index), o)) => {
let byte_index = bit_index / 8 + if bit_index % 8 == 0 { 0 } else { 1 } ;
Ok((i.slice(byte_index..), o))
}
}
}
);
);
#[macro_export(local_inner_macros)]
macro_rules! bytes (
($i:expr, $submac:ident!( $($args:tt)* )) => (
bytes_impl!($i, $submac!($($args)*));
);
($i:expr, $f:expr) => (
bytes_impl!($i, call!($f));
);
);
#[cfg(feature = "verbose-errors")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! bytes_impl (
($macro_i:expr, $submac:ident!( $($args:tt)* )) => (
{
use $crate::lib::std::result::Result::*;
use $crate::{Err,Needed,Context,Slice,ErrorKind};
let inp;
if $macro_i.1 % 8 != 0 {
inp = $macro_i.0.slice(1 + $macro_i.1 / 8 ..);
}
else {
inp = $macro_i.0.slice($macro_i.1 / 8 ..);
}
let sub = $submac!(inp, $($args)*);
let res = match sub {
Err(Err::Incomplete(Needed::Size(i))) => Err(match i.checked_mul(8) {
Some(v) => Err::Incomplete(Needed::Size(v)),
None => Err::Failure(error_position!((inp, 0),ErrorKind::TooLarge)),
}),
Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)),
Ok((i, o)) => {
Ok(((i, 0), o))
},
Err(Err::Error(e)) => {
let err = match e {
Context::Code(i, c) => Context::Code((i,0), c),
Context::List(mut v) => {
let (i, c) = v.remove(0);
Context::Code((i,0), c)
}
};
Err(Err::Error(err))
},
Err(Err::Failure(e)) => {
let err = match e {
Context::Code(i, c) => Context::Code((i,0), c),
Context::List(mut v) => {
let (i, c) = v.remove(0);
Context::Code((i,0), c)
}
};
Err(Err::Error(err))
},
Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)),
Err(Err::Incomplete(Needed::Size(i))) => Err(match i.checked_mul(8) {
Some(v) => Err::Incomplete(Needed::Size(v)),
None => Err::Failure(error_position!((inp, 0),ErrorKind::TooLarge)),
}),
Ok((i, o)) => {
Ok(((i, 0), o))
}
};
res
}
);
);
#[cfg(not(feature = "verbose-errors"))]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! bytes_impl (
($macro_i:expr, $submac:ident!( $($args:tt)* )) => (
{
use $crate::lib::std::result::Result::*;
use $crate::{Err,Needed,Context,Slice,ErrorKind};
let inp;
if $macro_i.1 % 8 != 0 {
inp = $macro_i.0.slice(1 + $macro_i.1 / 8 ..);
}
else {
inp = $macro_i.0.slice($macro_i.1 / 8 ..);
}
let sub = $submac!(inp, $($args)*);
let res = match sub {
Err(Err::Incomplete(Needed::Size(i))) => Err(match i.checked_mul(8) {
Some(v) => Err::Incomplete(Needed::Size(v)),
None => Err::Failure(error_position!((inp, 0),ErrorKind::TooLarge)),
}),
Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)),
Ok((i, o)) => {
Ok(((i, 0), o))
},
Err(Err::Error(e)) => {
let Context::Code(i, c) = e;
Err(Err::Error(Context::Code((i,0), c)))
},
Err(Err::Failure(e)) => {
let Context::Code(i, c) = e;
Err(Err::Failure(Context::Code((i,0), c)))
},
};
res
}
);
);
#[macro_export(local_inner_macros)]
macro_rules! take_bits (
($i:expr, $t:ty, $count:expr) => (
{
use $crate::lib::std::result::Result::*;
use $crate::{Needed,IResult};
use $crate::lib::std::ops::Div;
use $crate::lib::std::convert::Into;
use $crate::Slice;
let (input, bit_offset) = $i;
let res : IResult<_, $t> = if $count == 0 {
Ok(( (input, bit_offset), (0 as u8).into()))
} else {
let cnt = ($count as usize + bit_offset).div(8);
if input.len() * 8 < $count as usize + bit_offset {
$crate::need_more($i, Needed::Size($count as usize))
} else {
let mut acc:$t = (0 as u8).into();
let mut offset: usize = bit_offset;
let mut remaining: usize = $count;
let mut end_offset: usize = 0;
for byte in input.iter().take(cnt + 1) {
if remaining == 0 {
break;
}
let val: $t = if offset == 0 {
(*byte as u8).into()
} else {
(((*byte as u8) << offset) as u8 >> offset).into()
};
if remaining < 8 - offset {
acc += val >> (8 - offset - remaining);
end_offset = remaining + offset;
break;
} else {
acc += val << (remaining - (8 - offset));
remaining -= 8 - offset;
offset = 0;
}
}
Ok(( (input.slice(cnt..), end_offset) , acc))
}
};
res
}
);
);
#[macro_export(local_inner_macros)]
macro_rules! tag_bits (
($i:expr, $t:ty, $count:expr, $p: pat) => (
{
use $crate::lib::std::result::Result::*;
use $crate::{Err,IResult};
match take_bits!($i, $t, $count) {
Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)),
Ok((i, o)) => {
if let $p = o {
let res: IResult<_,$t> = Ok((i, o));
res
} else {
let e: $crate::ErrorKind<u32> = $crate::ErrorKind::TagBits;
Err(Err::Error(error_position!($i, e)))
}
},
_ => {
let e: $crate::ErrorKind<u32> = $crate::ErrorKind::TagBits;
Err(Err::Error(error_position!($i, e)))
}
}
}
)
);
#[cfg(test)]
mod tests {
use lib::std::ops::{AddAssign, Shl, Shr};
use internal::{Err, Needed};
use util::ErrorKind;
use types::CompleteByteSlice;
#[test]
fn take_bits() {
let input = [0b10_10_10_10, 0b11_11_00_00, 0b00_11_00_11];
let sl = &input[..];
assert_eq!(take_bits!((sl, 0), u8, 0), Ok(((sl, 0), 0)));
assert_eq!(take_bits!((sl, 0), u8, 8), Ok(((&sl[1..], 0), 170)));
assert_eq!(take_bits!((sl, 0), u8, 3), Ok(((&sl[0..], 3), 5)));
assert_eq!(take_bits!((sl, 0), u8, 6), Ok(((&sl[0..], 6), 42)));
assert_eq!(take_bits!((sl, 1), u8, 1), Ok(((&sl[0..], 2), 0)));
assert_eq!(take_bits!((sl, 1), u8, 2), Ok(((&sl[0..], 3), 1)));
assert_eq!(take_bits!((sl, 1), u8, 3), Ok(((&sl[0..], 4), 2)));
assert_eq!(take_bits!((sl, 6), u8, 3), Ok(((&sl[1..], 1), 5)));
assert_eq!(take_bits!((sl, 0), u16, 10), Ok(((&sl[1..], 2), 683)));
assert_eq!(take_bits!((sl, 0), u16, 8), Ok(((&sl[1..], 0), 170)));
assert_eq!(take_bits!((sl, 6), u16, 10), Ok(((&sl[2..], 0), 752)));
assert_eq!(take_bits!((sl, 6), u16, 11), Ok(((&sl[2..], 1), 1504)));
assert_eq!(take_bits!((sl, 0), u32, 20), Ok(((&sl[2..], 4), 700_163)));
assert_eq!(take_bits!((sl, 4), u32, 20), Ok(((&sl[3..], 0), 716_851)));
assert_eq!(take_bits!((CompleteByteSlice(sl), 4), u32, 20), Ok(((sl[3..].into(), 0), 716_851)));
assert_eq!(
take_bits!((sl, 4), u32, 22),
Err(Err::Incomplete(Needed::Size(22)))
);
}
#[test]
fn tag_bits() {
let input = [0b10_10_10_10, 0b11_11_00_00, 0b00_11_00_11];
let sl = &input[..];
assert_eq!(tag_bits!((sl, 0), u8, 3, 0b101), Ok(((&sl[0..], 3), 5)));
assert_eq!(tag_bits!((sl, 0), u8, 4, 0b1010), Ok(((&sl[0..], 4), 10)));
assert_eq!(tag_bits!((CompleteByteSlice(sl), 0), u8, 4, 0b1010), Ok(((sl[0..].into(), 4), 10)));
}
named!(ch<(&[u8],usize),(u8,u8)>,
do_parse!(
tag_bits!(u8, 3, 0b101) >>
x: take_bits!(u8, 4) >>
y: take_bits!(u8, 5) >>
(x,y)
)
);
#[test]
fn chain_bits() {
let input = [0b10_10_10_10, 0b11_11_00_00, 0b00_11_00_11];
let sl = &input[..];
assert_eq!(ch((&input[..], 0)), Ok(((&sl[1..], 4), (5, 15))));
assert_eq!(ch((&input[..], 4)), Ok(((&sl[2..], 0), (7, 16))));
assert_eq!(ch((&input[..1], 0)), Err(Err::Incomplete(Needed::Size(5))));
}
named!(ch_bytes<(u8, u8)>, bits!(ch));
#[test]
fn bits_to_bytes() {
let input = [0b10_10_10_10, 0b11_11_00_00, 0b00_11_00_11];
assert_eq!(ch_bytes(&input[..]), Ok((&input[2..], (5, 15))));
assert_eq!(ch_bytes(&input[..1]), Err(Err::Incomplete(Needed::Size(1))));
assert_eq!(
ch_bytes(&input[1..]),
Err(Err::Error(error_position!(&input[1..], ErrorKind::TagBits)))
);
}
named!(bits_bytes_bs, bits!(bytes!(::rest)));
named!(bits_bytes_cbs<CompleteByteSlice, CompleteByteSlice>, bits!(bytes!(::rest)));
#[test]
fn bits_bytes() {
let input = [0b10_10_10_10];
assert_eq!(bits_bytes_bs(&input[..]), Ok((&[][..], &[0b10_10_10_10][..])));
assert_eq!(bits_bytes_cbs(CompleteByteSlice(&input[..])), Ok(([][..].into(), [0b10_10_10_10][..].into())));
}
#[derive(PartialEq, Debug)]
struct FakeUint(u32);
impl AddAssign for FakeUint {
fn add_assign(&mut self, other: FakeUint) {
*self = FakeUint(self.0 + other.0);
}
}
impl Shr<usize> for FakeUint {
type Output = FakeUint;
fn shr(self, shift: usize) -> FakeUint {
FakeUint(self.0 >> shift)
}
}
impl Shl<usize> for FakeUint {
type Output = FakeUint;
fn shl(self, shift: usize) -> FakeUint {
FakeUint(self.0 << shift)
}
}
impl From<u8> for FakeUint {
fn from(i: u8) -> FakeUint {
FakeUint(u32::from(i))
}
}
#[test]
fn non_privitive_type() {
let input = [0b10_10_10_10, 0b11_11_00_00, 0b00_11_00_11];
let sl = &input[..];
assert_eq!(
take_bits!((sl, 0), FakeUint, 20),
Ok(((&sl[2..], 4), FakeUint(700_163)))
);
assert_eq!(
take_bits!((sl, 4), FakeUint, 20),
Ok(((&sl[3..], 0), FakeUint(716_851)))
);
assert_eq!(
take_bits!((sl, 4), FakeUint, 22),
Err(Err::Incomplete(Needed::Size(22)))
);
}
}