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}