#[macro_export(local_inner_macros)]
macro_rules! alt (
(__impl $i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)* ) => (
compile_error!("alt uses '|' as separator, not ',':
alt!(
tag!(\"abcd\") |
tag!(\"efgh\") |
tag!(\"ijkl\")
)
");
);
(__impl $i:expr, $e:path, $($rest:tt)* ) => (
alt!(__impl $i, call!($e) , $($rest)*);
);
(__impl $i:expr, $e:path | $($rest:tt)*) => (
alt!(__impl $i, call!($e) | $($rest)*);
);
(__impl $i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => (
{
use $crate::lib::std::result::Result::*;
use $crate::Err;
let i_ = $i.clone();
let res = $subrule!(i_, $($args)*);
match res {
Ok(o) => Ok(o),
Err(Err::Error(e)) => {
let out = alt!(__impl $i, $($rest)*);
#[allow(dead_code)]
fn unify_types<T>(_: &T, _: &T) {}
if let Err(Err::Error(ref e2)) = out {
unify_types(&e, e2);
}
out
},
Err(e) => Err(e),
}
}
);
(__impl $i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)*) => (
{
use $crate::lib::std::result::Result::*;
use $crate::Err;
let i_ = $i.clone();
match $subrule!(i_, $($args)* ) {
Ok((i,o)) => Ok((i,$gen(o))),
Err(Err::Error(e)) => {
let out = alt!(__impl $i, $($rest)*);
fn unify_types<T>(_: &T, _: &T) {}
if let Err(Err::Error(ref e2)) = out {
unify_types(&e, e2);
}
out
},
Err(e) => Err(e),
}
}
);
(__impl $i:expr, $e:path => { $gen:expr } | $($rest:tt)*) => (
alt!(__impl $i, call!($e) => { $gen } | $($rest)*);
);
(__impl $i:expr, __end) => (
{
use $crate::{Err,ErrorKind};
let e2 = ErrorKind::Alt;
let err = Err::Error(error_position!($i, e2));
Err(err)
}
);
($i:expr, $($rest:tt)*) => (
{
alt!(__impl $i, $($rest)* | __end)
}
);
);
#[macro_export(local_inner_macros)]
macro_rules! alt_complete (
($i:expr, $e:path | $($rest:tt)*) => (
alt_complete!($i, complete!(call!($e)) | $($rest)*);
);
($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => (
{
use $crate::lib::std::result::Result::*;
use $crate::Err;
let i_ = $i.clone();
let res = complete!(i_, $subrule!($($args)*));
match res {
Ok((_,_)) => res,
Err(Err::Failure(e)) => Err(Err::Failure(e)),
e => {
let out = alt_complete!($i, $($rest)*);
if let (&Err(Err::Error(ref e1)), &Err(Err::Error(ref e2))) = (&e, &out) {
fn unify_types<T>(_: &T, _: &T) {}
unify_types(e1, e2);
}
out
},
}
}
);
($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => (
{
use $crate::lib::std::result::Result::*;
use $crate::Err;
let i_ = $i.clone();
match complete!(i_, $subrule!($($args)*)) {
Ok((i,o)) => Ok((i,$gen(o))),
Err(Err::Failure(e)) => Err(Err::Failure(e)),
e => {
let out = alt_complete!($i, $($rest)*);
if let (&Err(Err::Error(ref e1)), &Err(Err::Error(ref e2))) = (&e, &out) {
fn unify_types<T>(_: &T, _: &T) {}
unify_types(e1, e2);
}
out
},
}
}
);
($i:expr, $e:path => { $gen:expr } | $($rest:tt)*) => (
alt_complete!($i, complete!(call!($e)) => { $gen } | $($rest)*);
);
($i:expr, $e:path => { $gen:expr }) => (
alt_complete!($i, call!($e) => { $gen });
);
($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => (
alt!(__impl $i, complete!($subrule!($($args)*)) => { $gen } | __end)
);
($i:expr, $e:path) => (
alt_complete!($i, call!($e));
);
($i:expr, $subrule:ident!( $($args:tt)*)) => (
alt!(__impl $i, complete!($subrule!($($args)*)) | __end)
);
);
#[macro_export(local_inner_macros)]
macro_rules! switch (
(__impl $i:expr, $submac:ident!( $($args:tt)* ), $( $($p:pat)|+ => $subrule:ident!( $($args2:tt)* ))|* ) => (
{
use $crate::lib::std::result::Result::*;
use $crate::lib::std::option::Option::*;
use $crate::{Err,Convert,ErrorKind};
let i_ = $i.clone();
match map!(i_, $submac!($($args)*), Some) {
Err(Err::Error(err)) => {
fn unify_types<T>(_: &T, _: &T) {}
let e1 = ErrorKind::Switch;
let e2 = error_position!($i, e1.clone());
unify_types(&err, &e2);
Err(Err::Error(error_node_position!($i, e1, err)))
},
Err(e) => Err(e),
Ok((i, o)) => {
match o {
$($(Some($p) )|+ => match $subrule!(i, $($args2)*) {
Err(Err::Error(err)) => {
fn unify_types<T>(_: &T, _: &T) {}
let e1 = ErrorKind::Switch;
let e2 = error_position!($i, e1.clone());
unify_types(&err, &e2);
Err(Err::Error(error_node_position!($i, e1, err)))
},
Ok(o) => Ok(o),
Err(e) => Err(e),
}),*,
_ => Err(Err::convert(Err::Error(error_position!($i, ErrorKind::Switch::<u32>))))
}
}
}
}
);
($i:expr, $submac:ident!( $($args:tt)*), $($rest:tt)*) => (
{
switch!(__impl $i, $submac!($($args)*), $($rest)*)
}
);
($i:expr, $e:path, $($rest:tt)*) => (
{
switch!(__impl $i, call!($e), $($rest)*)
}
);
);
#[macro_export(local_inner_macros)]
macro_rules! permutation (
($i:expr, $($rest:tt)*) => (
{
use $crate::lib::std::result::Result::*;
use $crate::lib::std::option::Option::*;
use $crate::{Err,Convert,ErrorKind};
let mut res = permutation_init!((), $($rest)*);
let mut input = $i;
let mut error = None;
let mut needed = None;
loop {
let mut all_done = true;
permutation_iterator!(0, input, all_done, needed, res, $($rest)*);
if !all_done {
error = Some(error_position!(input, ErrorKind::Permutation));
}
break;
}
if let Some(need) = needed {
Err(Err::convert(need))
} else {
if let Some(unwrapped_res) = { permutation_unwrap!(0, (), res, $($rest)*) } {
Ok((input, unwrapped_res))
} else {
if let Some(e) = error {
Err(Err::Error(error_node_position!($i, ErrorKind::Permutation, e)))
} else {
Err(Err::Error(error_position!($i, ErrorKind::Permutation)))
}
}
}
}
);
);
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! permutation_init (
((), $e:ident?, $($rest:tt)*) => (
permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
);
((), $e:ident, $($rest:tt)*) => (
permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
);
((), $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
);
((), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
);
(($($parsed:expr),*), $e:ident?, $($rest:tt)*) => (
permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
);
(($($parsed:expr),*), $e:ident, $($rest:tt)*) => (
permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
);
(($($parsed:expr),*), $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
);
(($($parsed:expr),*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
);
(($($parsed:expr),*), $e:ident) => (
($($parsed),* , $crate::lib::std::option::Option::None)
);
(($($parsed:expr),*), $e:ident?) => (
($($parsed),* , $crate::lib::std::option::Option::None)
);
(($($parsed:expr),*), $submac:ident!( $($args:tt)* )?) => (
($($parsed),* , $crate::lib::std::option::Option::None)
);
(($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => (
($($parsed),* , $crate::lib::std::option::Option::None)
);
(($($parsed:expr),*),) => (
($($parsed),*)
);
);
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! succ (
(0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*));
(1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
(2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
(3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
(4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
(5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
(6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
(7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
(8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
(9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*));
(10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*));
(11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*));
(12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*));
(13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*));
(14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*));
(15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*));
(16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*));
(17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
(18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
(19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
);
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! acc (
(0, $tup:expr) => ($tup.0);
(1, $tup:expr) => ($tup.1);
(2, $tup:expr) => ($tup.2);
(3, $tup:expr) => ($tup.3);
(4, $tup:expr) => ($tup.4);
(5, $tup:expr) => ($tup.5);
(6, $tup:expr) => ($tup.6);
(7, $tup:expr) => ($tup.7);
(8, $tup:expr) => ($tup.8);
(9, $tup:expr) => ($tup.9);
(10, $tup:expr) => ($tup.10);
(11, $tup:expr) => ($tup.11);
(12, $tup:expr) => ($tup.12);
(13, $tup:expr) => ($tup.13);
(14, $tup:expr) => ($tup.14);
(15, $tup:expr) => ($tup.15);
(16, $tup:expr) => ($tup.16);
(17, $tup:expr) => ($tup.17);
(18, $tup:expr) => ($tup.18);
(19, $tup:expr) => ($tup.19);
(20, $tup:expr) => ($tup.20);
);
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! permutation_unwrap (
($it:tt, (), $res:ident, $e:ident?, $($rest:tt)*) => (
succ!($it, permutation_unwrap!((acc!($it, $res)), $res, $($rest)*));
);
($it:tt, (), $res:ident, $e:ident, $($rest:tt)*) => ({
let res = acc!($it, $res);
if res.is_some() {
succ!($it, permutation_unwrap!((res.unwrap()), $res, $($rest)*))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, (), $res:ident, $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
succ!($it, permutation_unwrap!((acc!($it, $res)), $res, $($rest)*));
);
($it:tt, (), $res:ident, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({
let res = acc!($it, $res);
if res.is_some() {
succ!($it, permutation_unwrap!((res.unwrap()), $res, $($rest)*))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, ($($parsed:expr),*), $res:ident, $e:ident?, $($rest:tt)*) => (
succ!($it, permutation_unwrap!(($($parsed),* , acc!($it, $res)), $res, $($rest)*));
);
($it:tt, ($($parsed:expr),*), $res:ident, $e:ident, $($rest:tt)*) => ({
let res = acc!($it, $res);
if res.is_some() {
succ!($it, permutation_unwrap!(($($parsed),* , res.unwrap()), $res, $($rest)*))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
succ!($it, permutation_unwrap!(($($parsed),* , acc!($it, $res)), $res, $($rest)*));
);
($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({
let res = acc!($it, $res);
if res.is_some() {
succ!($it, permutation_unwrap!(($($parsed),* , res.unwrap()), $res, $($rest)*))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, ($($parsed:expr),*), $res:ident?, $e:ident) => (
$crate::lib::std::option::Option::Some(($($parsed),* , { acc!($it, $res) }))
);
($it:tt, ($($parsed:expr),*), $res:ident, $e:ident) => ({
let res = acc!($it, $res);
if res.is_some() {
$crate::lib::std::option::Option::Some(($($parsed),* , res.unwrap() ))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* )?) => (
$crate::lib::std::option::Option::Some(($($parsed),* , { acc!($it, $res) }))
);
($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* )) => ({
let res = acc!($it, $res);
if res.is_some() {
$crate::lib::std::option::Option::Some(($($parsed),* , res.unwrap() ))
} else {
$crate::lib::std::option::Option::None
}
});
);
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! permutation_iterator (
($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident?, $($rest:tt)*) => (
permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e), $($rest)*);
);
($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident, $($rest:tt)*) => (
permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e), $($rest)*);
);
($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => {
permutation_iterator!($it, $i, $all_done, $needed, $res, $submac!($($args)*) , $($rest)*);
};
($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({
use $crate::lib::std::result::Result::*;
use $crate::lib::std::option::Option::*;
use $crate::Err;
if acc!($it, $res).is_none() {
match $submac!($i, $($args)*) {
Ok((i,o)) => {
$i = i;
acc!($it, $res) = Some(o);
continue;
},
Err(Err::Error(_)) => {
$all_done = false;
},
Err(e) => {
$needed = Some(e);
break;
}
};
}
succ!($it, permutation_iterator!($i, $all_done, $needed, $res, $($rest)*));
});
($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident?) => (
permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e));
);
($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident) => (
permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e));
);
($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )?) => {
permutation_iterator!($it, $i, $all_done, $needed, $res, $submac!($($args)*));
};
($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )) => ({
use $crate::lib::std::result::Result::*;
use $crate::lib::std::option::Option::*;
use $crate::Err;
if acc!($it, $res).is_none() {
match $submac!($i, $($args)*) {
Ok((i,o)) => {
$i = i;
acc!($it, $res) = Some(o);
continue;
},
Err(Err::Error(_)) => {
$all_done = false;
},
Err(e) => {
$needed = Some(e);
break;
}
};
}
});
);
#[cfg(test)]
mod tests {
#[cfg(feature = "alloc")]
use lib::std::string::{String, ToString};
use internal::{Err, IResult, Needed};
use util::ErrorKind;
macro_rules! tag (
($i:expr, $inp: expr) => (
{
#[inline(always)]
fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
b.as_bytes()
}
let expected = $inp;
let bytes = as_bytes(&expected);
tag_bytes!($i,bytes)
}
);
);
macro_rules! tag_bytes (
($i:expr, $bytes: expr) => (
{
use $crate::need_more;
use $crate::lib::std::cmp::min;
let len = $i.len();
let blen = $bytes.len();
let m = min(len, blen);
let reduced = &$i[..m];
let b = &$bytes[..m];
let res: IResult<_,_,u32> = if reduced != b {
let e: ErrorKind<u32> = ErrorKind::Tag::<u32>;
Err(Err::Error(error_position!($i, e)))
} else if m < blen {
need_more($i, Needed::Size(blen))
} else {
Ok((&$i[blen..], reduced))
};
res
}
);
);
macro_rules! take(
($i:expr, $count:expr) => (
{
use $crate::need_more;
let cnt = $count as usize;
let res:IResult<&[u8],&[u8],u32> = if $i.len() < cnt {
need_more($i, Needed::Size(cnt))
} else {
Ok((&$i[cnt..],&$i[0..cnt]))
};
res
}
);
);
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq)]
pub struct ErrorStr(String);
#[cfg(feature = "alloc")]
impl From<u32> for ErrorStr {
fn from(i: u32) -> Self {
ErrorStr(format!("custom error code: {}", i))
}
}
#[cfg(feature = "alloc")]
impl<'a> From<&'a str> for ErrorStr {
fn from(i: &'a str) -> Self {
ErrorStr(format!("custom error message: {}", i))
}
}
#[cfg(feature = "alloc")]
#[test]
fn alt() {
fn work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
Ok((&b""[..], input))
}
#[allow(unused_variables)]
fn dont_work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
use Context;
Err(Err::Error(Context::Code(
&b""[..],
ErrorKind::Custom(ErrorStr("abcd".to_string())),
)))
}
fn work2(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
Ok((input, &b""[..]))
}
fn alt1(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
alt!(i, dont_work | dont_work)
}
fn alt2(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
alt!(i, dont_work | work)
}
fn alt3(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
alt!(i, dont_work | dont_work | work2 | dont_work)
}
let a = &b"abcd"[..];
assert_eq!(alt1(a), Err(Err::Error(error_position!(a, ErrorKind::Alt))));
assert_eq!(alt2(a), Ok((&b""[..], a)));
assert_eq!(alt3(a), Ok((a, &b""[..])));
named!(alt4, alt!(tag!("abcd") | tag!("efgh")));
let b = &b"efgh"[..];
assert_eq!(alt4(a), Ok((&b""[..], a)));
assert_eq!(alt4(b), Ok((&b""[..], b)));
named!(
alt5<bool>,
alt!(tag!("abcd") => { |_| false } | tag!("efgh") => { |_| true })
);
assert_eq!(alt5(a), Ok((&b""[..], false)));
assert_eq!(alt5(b), Ok((&b""[..], true)));
named!(alt_eof1, alt!(eof!() | eof!()));
named!(alt_eof2, alt!(eof!() => {|x| x} | eof!() => {|x| x}));
let _ = (alt_eof1, alt_eof2);
}
#[test]
fn alt_incomplete() {
named!(alt1, alt!(tag!("a") | tag!("bc") | tag!("def")));
let a = &b""[..];
assert_eq!(alt1(a), Err(Err::Incomplete(Needed::Size(1))));
let a = &b"b"[..];
assert_eq!(alt1(a), Err(Err::Incomplete(Needed::Size(2))));
let a = &b"bcd"[..];
assert_eq!(alt1(a), Ok((&b"d"[..], &b"bc"[..])));
let a = &b"cde"[..];
assert_eq!(alt1(a), Err(Err::Error(error_position!(a, ErrorKind::Alt))));
let a = &b"de"[..];
assert_eq!(alt1(a), Err(Err::Incomplete(Needed::Size(3))));
let a = &b"defg"[..];
assert_eq!(alt1(a), Ok((&b"g"[..], &b"def"[..])));
}
#[test]
fn alt_complete() {
named!(ac<&[u8], &[u8]>,
alt_complete!(tag!("abcd") | tag!("ef") | tag!("ghi") | tag!("kl"))
);
let a = &b""[..];
assert_eq!(ac(a), Err(Err::Error(error_position!(a, ErrorKind::Alt))));
let a = &b"ef"[..];
assert_eq!(ac(a), Ok((&b""[..], &b"ef"[..])));
let a = &b"cde"[..];
assert_eq!(ac(a), Err(Err::Error(error_position!(a, ErrorKind::Alt))));
}
#[allow(unused_variables)]
#[test]
fn switch() {
named!(
sw,
switch!(take!(4),
b"abcd" | b"xxxx" => take!(2) |
b"efgh" => take!(4)
)
);
let a = &b"abcdefgh"[..];
assert_eq!(sw(a), Ok((&b"gh"[..], &b"ef"[..])));
let b = &b"efghijkl"[..];
assert_eq!(sw(b), Ok((&b""[..], &b"ijkl"[..])));
let c = &b"afghijkl"[..];
assert_eq!(
sw(c),
Err(Err::Error(error_position!(
&b"afghijkl"[..],
ErrorKind::Switch
)))
);
let a = &b"xxxxefgh"[..];
assert_eq!(sw(a), Ok((&b"gh"[..], &b"ef"[..])));
}
#[test]
fn permutation() {
named!(
perm<(&[u8], &[u8], &[u8])>,
permutation!(tag!("abcd"), tag!("efg"), tag!("hi"))
);
let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]);
let a = &b"abcdefghijk"[..];
assert_eq!(perm(a), Ok((&b"jk"[..], expected)));
let b = &b"efgabcdhijk"[..];
assert_eq!(perm(b), Ok((&b"jk"[..], expected)));
let c = &b"hiefgabcdjk"[..];
assert_eq!(perm(c), Ok((&b"jk"[..], expected)));
let d = &b"efgxyzabcdefghi"[..];
assert_eq!(
perm(d),
Err(Err::Error(error_node_position!(
&b"efgxyzabcdefghi"[..],
ErrorKind::Permutation,
error_position!(&b"xyzabcdefghi"[..], ErrorKind::Permutation)
)))
);
let e = &b"efgabc"[..];
assert_eq!(perm(e), Err(Err::Incomplete(Needed::Size(4))));
}
}