alpm_parsers/
macros.rs

1/// Take an array of `dyn Iterator<Item = &'static str>` and return a closure that flattens the
2/// outer array to map the inner values  onto [winnow::error::StrContextValue::StringLiteral].
3///
4/// # Example
5///
6/// ```
7/// use alpm_parsers::iter_str_context;
8/// use winnow::{
9///     ModalResult,
10///     Parser,
11///     combinator::{alt, cut_err},
12/// };
13/// /// A parser with a single list of keywords
14/// fn parser_single<'a>(input: &mut &'a str) -> ModalResult<&'a str> {
15///     let first_list = ["first", "second", "third"];
16///     alt(first_list)
17///         .context_with(iter_str_context!([first_list]))
18///         .parse_next(input)
19/// }
20///
21/// const FIRST_LIST: [&str; 3] = ["first", "second", "third"];
22/// const SECOND_LIST: [&str; 2] = ["fourth", "fifth"];
23///
24/// fn first_parser<'a>(input: &mut &'a str) -> ModalResult<&'a str> {
25///     alt(FIRST_LIST).parse_next(input)
26/// }
27///
28/// fn second_parser<'a>(input: &mut &'a str) -> ModalResult<&'a str> {
29///     alt(SECOND_LIST).parse_next(input)
30/// }
31///
32/// /// Can be used like this on static arrays of varying length.
33/// fn parser_multi<'a>(input: &mut &'a str) -> ModalResult<&'a str> {
34///     cut_err(alt((first_parser, second_parser)))
35///         .context_with(iter_str_context!([
36///             FIRST_LIST.to_vec(),
37///             SECOND_LIST.to_vec()
38///         ]))
39///         .parse_next(input)
40/// }
41///
42/// /// And as follows on local arrays of varying length.
43/// fn parser_multi_alt<'a>(input: &mut &'a str) -> ModalResult<&'a str> {
44///     let first_list = ["first", "second", "third"];
45///     let second_list = ["fourth", "fifth"];
46///     alt((first_parser, second_parser))
47///         .context_with(iter_str_context!([
48///             first_list.to_vec(),
49///             second_list.to_vec()
50///         ]))
51///         .parse_next(input)
52/// }
53///
54/// assert!(parser_single.parse("second").is_ok());
55/// assert!(parser_multi.parse("fourth").is_ok());
56/// assert!(parser_multi_alt.parse("fourth").is_ok());
57/// ```
58#[macro_export]
59macro_rules! iter_str_context {
60    ($iter:expr) => {
61        || {
62            use winnow::error::{StrContext, StrContextValue};
63            $iter
64                .into_iter()
65                .flatten()
66                .map(|s| StrContext::Expected(StrContextValue::StringLiteral(s)))
67        }
68    };
69}
70
71/// Take a `dyn Iterator<Item = &char>` and return a closure that calls `.iter()` and maps
72/// the values onto [winnow::error::StrContextValue::CharLiteral].
73///
74/// # Example
75///
76/// ```
77/// use alpm_parsers::iter_char_context;
78/// use winnow::{ModalResult, Parser, combinator::cut_err, token::one_of};
79///
80/// fn parser(input: &mut &str) -> ModalResult<char> {
81///     let accepted_characters = ['a', 'b', 'c'];
82///     cut_err(one_of(accepted_characters))
83///         .context_with(iter_char_context!(accepted_characters))
84///         .parse_next(input)
85/// }
86///
87/// assert!(parser.parse("a").is_ok());
88/// ```
89#[macro_export]
90macro_rules! iter_char_context {
91    ($iter:expr) => {
92        || {
93            use winnow::error::{StrContext, StrContextValue};
94            $iter
95                .iter()
96                .map(|c| StrContext::Expected(StrContextValue::CharLiteral(*c)))
97        }
98    };
99}