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