static_graph/parser/
annotations.rs1use std::ops::Deref;
2
3use nom::{
4 bytes::complete::{tag, take_while},
5 character::complete::satisfy,
6 combinator::{map, opt, recognize},
7 multi::many1,
8 sequence::tuple,
9 IResult,
10};
11
12use super::{blank, list_separator, literal::Literal, Parser};
13
14#[derive(Debug, Clone)]
15pub struct Annotation {
16 pub key: String,
17 pub value: Literal,
18}
19
20impl Deref for Annotations {
21 type Target = Vec<Annotation>;
22
23 fn deref(&self) -> &Self::Target {
24 self.0.as_ref()
25 }
26}
27
28#[derive(Debug, Clone, Default)]
29pub struct Annotations(pub Vec<Annotation>);
30
31impl<'a> Parser<'a> for Annotations {
32 fn parse(input: &'a str) -> IResult<&'a str, Annotations> {
33 map(
34 tuple((
35 tag("#["),
36 many1(map(
37 tuple((
38 opt(blank),
39 recognize(tuple((
40 satisfy(|c| c.is_ascii_alphabetic() || c == '_'),
41 take_while(|c: char| c.is_ascii_alphanumeric() || c == '_' || c == '.'),
42 ))),
43 opt(blank),
44 tag("="),
45 opt(blank),
46 Literal::parse,
47 opt(blank),
48 opt(list_separator),
49 )),
50 |(_, p, _, _, _, lit, _, _)| Annotation {
51 key: p.to_owned(),
52 value: lit,
53 },
54 )),
55 tag("]"),
56 )),
57 |(_, annotations, _)| Annotations(annotations),
58 )(input)
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_annotations() {
68 match Annotations::parse(r#"#[foo = "bar"]"#) {
69 Ok((remain, annotations)) => {
70 assert_eq!(remain, "");
71 assert_eq!(annotations.len(), 1);
72 assert_eq!(annotations[0].key, "foo");
73 assert_eq!(annotations[0].value.0, "bar");
74 }
75 Err(e) => panic!("{e:?}"),
76 }
77 }
78}