webwire_cli/idl/
field_option.rs

1use nom::{
2    character::complete::char,
3    combinator::{cut, map},
4    error::context,
5    multi::separated_list0,
6    sequence::{preceded, separated_pair, terminated},
7    IResult,
8};
9
10#[cfg(test)]
11use crate::idl::common::assert_parse;
12use crate::idl::common::{parse_field_separator, parse_identifier, trailing_comma, ws, Span};
13use crate::idl::r#value::{parse_value, Value};
14
15#[derive(Debug, PartialEq)]
16pub struct FieldOption {
17    pub name: String,
18    pub value: Value,
19}
20
21pub fn parse_field_options(input: Span) -> IResult<Span, Vec<FieldOption>> {
22    context(
23        "options",
24        preceded(
25            preceded(ws, char('(')),
26            cut(terminated(
27                separated_list0(parse_field_separator, parse_field_option),
28                preceded(trailing_comma, preceded(ws, char(')'))),
29            )),
30        ),
31    )(input)
32}
33
34fn parse_field_option(input: Span) -> IResult<Span, FieldOption> {
35    map(
36        separated_pair(
37            preceded(ws, parse_identifier),
38            preceded(ws, char('=')),
39            preceded(ws, parse_value),
40        ),
41        |(name, value)| FieldOption { name, value },
42    )(input)
43}
44
45#[test]
46fn test_parse_field_options_0() {
47    let contents = ["()", "( )", "(,)", "( ,)", "(, )"];
48    for content in contents.iter() {
49        assert_parse(parse_field_options(Span::new(content)), vec![]);
50    }
51}
52
53#[test]
54fn test_parse_field_options_1() {
55    let contents = [
56        "(foo=42)",
57        "(foo= 42)",
58        "(foo=42 )",
59        "( foo=42)",
60        "(foo=42,)",
61    ];
62    for content in contents.iter() {
63        assert_parse(
64            parse_field_options(Span::new(content)),
65            vec![FieldOption {
66                name: "foo".to_owned(),
67                value: Value::Integer(42),
68            }],
69        );
70    }
71}
72
73#[test]
74fn test_parse_field_options_2() {
75    let contents = [
76        "(foo=42,bar=\"epic\")",
77        "(foo= 42, bar= \"epic\")",
78        "( foo=42,bar=\"epic\" )",
79        "( foo= 42, bar= \"epic\" )",
80        "( foo= 42, bar= \"epic\", )",
81    ];
82    for content in contents.iter() {
83        assert_parse(
84            parse_field_options(Span::new(content)),
85            vec![
86                FieldOption {
87                    name: "foo".to_owned(),
88                    value: Value::Integer(42),
89                },
90                FieldOption {
91                    name: "bar".to_owned(),
92                    value: Value::String("epic".to_string()),
93                },
94            ],
95        );
96    }
97}