use snapbox::prelude::*;
use snapbox::str;
use crate::ascii::dec_uint;
use crate::ascii::digit0;
use crate::combinator::dispatch;
use crate::combinator::empty;
use crate::combinator::fail;
use crate::combinator::seq;
use crate::combinator::unordered_seq;
use crate::prelude::*;
use crate::stream::Partial;
use crate::token::any;
#[test]
fn dispatch_basics() {
fn escape_seq_char<'i>(input: &mut &'i str) -> TestResult<&'i str, char> {
dispatch! {any;
'b' => empty.value('\u{8}'),
'f' => empty.value('\u{c}'),
'n' => empty.value('\n'),
'r' => empty.value('\r'),
't' => empty.value('\t'),
'\\' => empty.value('\\'),
'"' => empty.value('"'),
_ => fail::<_, char, _>,
}
.parse_next(input)
}
assert_parse!(
escape_seq_char.parse_peek("b123"),
str![[r#"
Ok(
(
"123",
'\u{8}',
),
)
"#]]
.raw()
);
assert_parse!(
escape_seq_char.parse_peek("error"),
str![[r#"
Err(
Backtrack(
InputError {
input: "rror",
},
),
)
"#]]
.raw()
);
assert_parse!(
escape_seq_char.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn seq_struct_basics() {
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
}
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
Point {
x: 123,
y: 4,
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn seq_struct_default_init() {
#[derive(Debug, PartialEq, Default)]
struct Point {
x: u32,
y: u32,
z: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
..Default::default()
}
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
Point {
x: 123,
y: 4,
z: 0,
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn seq_struct_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
_: empty,
}
}
.parse_next(input)
}
}
#[test]
fn seq_struct_no_trailing_comma() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint
}
}
.parse_next(input)
}
}
#[test]
fn seq_struct_no_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
_: empty
}
}
.parse_next(input)
}
}
#[test]
fn seq_enum_struct_variant() {
#[derive(Debug, PartialEq, Eq)]
enum Expr {
Add { lhs: u32, rhs: u32 },
Mul(u32, u32),
}
fn add<'i>(input: &mut &'i [u8]) -> TestResult<&'i [u8], Expr> {
seq! {Expr::Add {
lhs: dec_uint::<_, u32, _>,
_: b" + ",
rhs: dec_uint::<_, u32, _>,
}}
.parse_next(input)
}
fn mul<'i>(input: &mut &'i [u8]) -> TestResult<&'i [u8], Expr> {
seq!(Expr::Mul(
dec_uint::<_, u32, _>,
_: b" * ",
dec_uint::<_, u32, _>,
))
.parse_next(input)
}
assert_parse!(
add.parse_peek(&b"1 + 2"[..]),
str![[r#"
Ok(
(
[],
Add {
lhs: 1,
rhs: 2,
},
),
)
"#]]
.raw()
);
assert_parse!(
mul.parse_peek(&b"3 * 4"[..]),
str![[r#"
Ok(
(
[],
Mul(
3,
4,
),
),
)
"#]]
.raw()
);
}
#[test]
fn seq_struct_borrow() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
let mut dec_uint = digit0.parse_to();
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
_: empty
}
}
.parse_next(input)
}
}
#[test]
fn seq_struct_many_fields() {
#[derive(Debug, PartialEq)]
struct Fields {
field_00: u8,
field_01: u8,
field_02: u8,
field_03: u8,
field_04: u8,
field_05: u8,
field_06: u8,
field_07: u8,
field_08: u8,
field_09: u8,
field_10: u8,
field_11: u8,
field_12: u8,
field_13: u8,
field_14: u8,
field_15: u8,
field_16: u8,
field_17: u8,
field_18: u8,
field_19: u8,
field_20: u8,
field_21: u8,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Fields> {
seq! {
Fields {
field_00: empty.value(0),
field_01: empty.value(1),
field_02: empty.value(2),
field_03: empty.value(3),
field_04: empty.value(4),
field_05: empty.value(5),
field_06: empty.value(6),
field_07: empty.value(7),
field_08: empty.value(8),
field_09: empty.value(9),
field_10: empty.value(10),
field_11: empty.value(11),
field_12: empty.value(12),
field_13: empty.value(13),
field_14: empty.value(14),
field_15: empty.value(15),
field_16: empty.value(16),
field_17: empty.value(17),
field_18: empty.value(18),
field_19: empty.value(19),
field_20: empty.value(20),
field_21: empty.value(21),
}
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("remaining"),
str![[r#"
Ok(
(
"remaining",
Fields {
field_00: 0,
field_01: 1,
field_02: 2,
field_03: 3,
field_04: 4,
field_05: 5,
field_06: 6,
field_07: 7,
field_08: 8,
field_09: 9,
field_10: 10,
field_11: 11,
field_12: 12,
field_13: 13,
field_14: 14,
field_15: 15,
field_16: 16,
field_17: 17,
field_18: 18,
field_19: 19,
field_20: 20,
field_21: 21,
},
),
)
"#]]
.raw()
);
}
#[test]
fn seq_tuple_struct_basics() {
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point(
dec_uint,
_: ',',
dec_uint,
)
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
Point(
123,
4,
),
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn seq_tuple_struct_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point(
dec_uint,
_: ',',
dec_uint,
_: empty,
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_struct_no_trailing_comma() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point(
dec_uint,
_: ',',
dec_uint
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_struct_no_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point(
dec_uint,
_: ',',
dec_uint,
_: empty
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_basics() {
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
seq! {
(
dec_uint,
_: ',',
dec_uint,
)
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
(
123,
4,
),
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn seq_tuple_trailing_comma_elided() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
seq! {
(
dec_uint,
_: ',',
dec_uint,
_: empty,
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_no_trailing_comma() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
seq! {
(
dec_uint,
_: ',',
dec_uint
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_no_trailing_comma_elided() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
seq! {
(
dec_uint,
_: ',',
dec_uint,
_: empty
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_no_parens() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
seq! (
dec_uint,
_: ',',
dec_uint,
)
.parse_next(input)
}
}
#[test]
fn seq_tuple_borrow() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
let mut dec_uint = digit0.parse_to();
seq! {
Point(
dec_uint,
_: ',',
dec_uint,
_: empty
)
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_struct_basics() {
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
unordered_seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
}
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
Point {
x: 123,
y: 4,
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn unordered_seq_struct_default_init() {
#[derive(Debug, PartialEq, Default)]
struct Point {
x: u32,
y: u32,
z: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
unordered_seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
..Default::default()
}
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
Point {
x: 123,
y: 4,
z: 0,
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn unordered_seq_struct_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
unordered_seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
_: empty,
}
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_struct_no_trailing_comma() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
unordered_seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint
}
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_struct_no_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
unordered_seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
_: empty
}
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_enum_struct_variant() {
#[derive(Debug, PartialEq, Eq)]
enum Expr {
Add { lhs: u32, rhs: u32 },
Mul(u32, u32),
}
fn add<'i>(input: &mut &'i [u8]) -> TestResult<&'i [u8], Expr> {
unordered_seq! {Expr::Add {
lhs: dec_uint::<_, u32, _>,
_: b" + ",
rhs: dec_uint::<_, u32, _>,
}}
.parse_next(input)
}
fn mul<'i>(input: &mut &'i [u8]) -> TestResult<&'i [u8], Expr> {
unordered_seq!(Expr::Mul(
dec_uint::<_, u32, _>,
_: b" * ",
dec_uint::<_, u32, _>,
))
.parse_next(input)
}
assert_parse!(
add.parse_peek(&b"1 + 2"[..]),
str![[r#"
Ok(
(
[],
Add {
lhs: 1,
rhs: 2,
},
),
)
"#]]
.raw()
);
assert_parse!(
mul.parse_peek(&b"3 * 4"[..]),
str![[r#"
Ok(
(
[],
Mul(
3,
4,
),
),
)
"#]]
.raw()
);
}
#[test]
fn unordered_seq_struct_borrow() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
let mut dec_uint = digit0.parse_to();
unordered_seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
_: empty
}
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_tuple_struct_basics() {
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
unordered_seq! {
Point(
dec_uint,
_: ',',
dec_uint,
)
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
Point(
123,
4,
),
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn unordered_seq_tuple_struct_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
unordered_seq! {
Point(
dec_uint,
_: ',',
dec_uint,
_: empty,
)
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_tuple_struct_no_trailing_comma() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
unordered_seq! {
Point(
dec_uint,
_: ',',
dec_uint
)
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_tuple_struct_no_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
unordered_seq! {
Point(
dec_uint,
_: ',',
dec_uint,
_: empty
)
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_tuple_basics() {
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
unordered_seq! {
(
dec_uint,
_: ',',
dec_uint,
)
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
(
123,
4,
),
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn unordered_seq_tuple_trailing_comma_elided() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
unordered_seq! {
(
dec_uint,
_: ',',
dec_uint,
_: empty,
)
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_tuple_no_trailing_comma() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
unordered_seq! {
(
dec_uint,
_: ',',
dec_uint
)
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_tuple_no_trailing_comma_elided() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
unordered_seq! {
(
dec_uint,
_: ',',
dec_uint,
_: empty
)
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_tuple_no_parens() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
unordered_seq! (
dec_uint,
_: ',',
dec_uint,
)
.parse_next(input)
}
}
#[test]
fn unordered_seq_tuple_borrow() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
let mut dec_uint = digit0.parse_to();
unordered_seq! {
Point(
dec_uint,
_: ',',
dec_uint,
_: empty
)
}
.parse_next(input)
}
}
#[test]
fn unordered_seq_permutation_test() {
#[allow(clippy::type_complexity)]
fn perm<'i>(
i: &mut Partial<&'i [u8]>,
) -> TestResult<Partial<&'i [u8]>, (&'i [u8], &'i [u8], &'i [u8])> {
unordered_seq!(("abcd", "efg", "hi")).parse_next(i)
}
let a = &b"abcdefghijk"[..];
assert_parse!(
perm.parse_peek(Partial::new(a)),
str![[r#"
Ok(
(
Partial {
input: [
106,
107,
],
partial: true,
},
(
[
97,
98,
99,
100,
],
[
101,
102,
103,
],
[
104,
105,
],
),
),
)
"#]]
.raw()
);
let b = &b"efgabcdhijk"[..];
assert_parse!(
perm.parse_peek(Partial::new(b)),
str![[r#"
Ok(
(
Partial {
input: [
106,
107,
],
partial: true,
},
(
[
97,
98,
99,
100,
],
[
101,
102,
103,
],
[
104,
105,
],
),
),
)
"#]]
.raw()
);
let c = &b"hiefgabcdjk"[..];
assert_parse!(
perm.parse_peek(Partial::new(c)),
str![[r#"
Ok(
(
Partial {
input: [
106,
107,
],
partial: true,
},
(
[
97,
98,
99,
100,
],
[
101,
102,
103,
],
[
104,
105,
],
),
),
)
"#]]
.raw()
);
let d = &b"efgxyzabcdefghi"[..];
assert_parse!(
perm.parse_peek(Partial::new(d)),
str![[r#"
Err(
Backtrack(
InputError {
input: Partial {
input: [
120,
121,
122,
97,
98,
99,
100,
101,
102,
103,
104,
105,
],
partial: true,
},
},
),
)
"#]]
.raw()
);
let e = &b"efgabc"[..];
assert_parse!(
perm.parse_peek(Partial::new(e)),
str![[r#"
Err(
Incomplete(
Unknown,
),
)
"#]]
.raw()
);
}