kserd/parse/
map.rs

1use super::*;
2
3/// Key-Value pair, of `Kserd` to `Kserd`.
4fn kvp_kserd_to_kserd<'a, E: CxErr<'a>>(
5    force_inline: bool,
6) -> impl Fn(&'a str) -> IResult<&'a str, (Kserd<'a>, Kserd<'a>), E> {
7    move |input: &'a str| {
8        let value_parser = if force_inline {
9            kserd_inline
10        } else {
11            kserd_concise
12        };
13
14        context(
15            "kserd-kserd key-value pair",
16            separated_pair(
17                alt((kserd_concise, kserd_inline)),
18                ignore_inline_whitespace(char(':')),
19                ignore_inline_whitespace(value_parser),
20            ),
21        )(input)
22    }
23}
24
25/// Comma separated key-value pairs, where key and value are both `Kserd`s.
26fn inline_map_kserds<'a, E: CxErr<'a>>(
27    i: &'a str,
28) -> IResult<&'a str, Vec<(Kserd<'a>, Kserd<'a>)>, E> {
29    context(
30        "comma separated kserd-kserd pair",
31        separated_list0(
32            ignore_inline_whitespace(char(',')),
33            ignore_inline_whitespace(kvp_kserd_to_kserd(true)),
34        ),
35    )(i)
36}
37
38/// Concise maps are separated by new lines.
39fn concise_map_kserds<'a, E: CxErr<'a>>(
40    i: &'a str,
41) -> IResult<&'a str, Vec<(Kserd<'a>, Kserd<'a>)>, E> {
42    context(
43        "newline separated (concise) kserd-kserd pair",
44        preceded(
45            multiline_whitespace,
46            terminated(
47                separated_list0(multiline_whitespace, kvp_kserd_to_kserd(false)),
48                multiline_whitespace,
49            ),
50        ),
51    )(i)
52}
53
54/// Parse as a sequence. Will `Fail` if delimited by opening brace `{`.
55/// Tries to determine if the stream is in `Concise` or `Inline` format using
56/// simple heuristics. The decision can be overridden by forcing `Inline` format.
57pub(super) fn delimited<'a, E: CxErr<'a>>(
58    force_inline: bool,
59) -> impl Fn(&'a str) -> IResult<&'a str, Kserd<'a>, E> {
60    move |i: &'a str| {
61        let (i, ident) = opt(ident(false))(i)?;
62
63        let (i, _) = ignore_inline_whitespace(char('{'))(i)?; // open with bracket
64
65        // we manually work out if should be treating as inline or concise
66        let concise = recognise_concise(i) && !force_inline;
67
68        let parser = if concise {
69            concise_map_kserds
70        } else {
71            inline_map_kserds
72        };
73
74        let ctx = if concise { "concise map" } else { "inline map" };
75
76        let (i, value) = context(ctx, terminated(parser, ignore_inline_whitespace(char('}'))))(i)?;
77
78        let value = Value::Map(value.into_iter().collect());
79
80        Ok((i, kserd_ctor(ident, value)))
81    }
82}