• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use nom::{
2   bytes::complete::take_while,
3   character::complete::{
4     alphanumeric1 as alphanumeric, char, multispace0 as multispace, space0 as space,
5   },
6   combinator::{map, map_res, opt},
7   multi::many0,
8   sequence::{delimited, pair, separated_pair, terminated, tuple},
9   IResult,
10 };
11 
12 use std::collections::HashMap;
13 use std::str;
14 
category(i: &[u8]) -> IResult<&[u8], &str>15 fn category(i: &[u8]) -> IResult<&[u8], &str> {
16   map_res(
17     delimited(char('['), take_while(|c| c != b']'), char(']')),
18     str::from_utf8,
19   )(i)
20 }
21 
key_value(i: &[u8]) -> IResult<&[u8], (&str, &str)>22 fn key_value(i: &[u8]) -> IResult<&[u8], (&str, &str)> {
23   let (i, key) = map_res(alphanumeric, str::from_utf8)(i)?;
24   let (i, _) = tuple((opt(space), char('='), opt(space)))(i)?;
25   let (i, val) = map_res(take_while(|c| c != b'\n' && c != b';'), str::from_utf8)(i)?;
26   let (i, _) = opt(pair(char(';'), take_while(|c| c != b'\n')))(i)?;
27   Ok((i, (key, val)))
28 }
29 
keys_and_values(i: &[u8]) -> IResult<&[u8], HashMap<&str, &str>>30 fn keys_and_values(i: &[u8]) -> IResult<&[u8], HashMap<&str, &str>> {
31   map(many0(terminated(key_value, opt(multispace))), |vec| {
32     vec.into_iter().collect()
33   })(i)
34 }
35 
category_and_keys(i: &[u8]) -> IResult<&[u8], (&str, HashMap<&str, &str>)>36 fn category_and_keys(i: &[u8]) -> IResult<&[u8], (&str, HashMap<&str, &str>)> {
37   let (i, category) = terminated(category, opt(multispace))(i)?;
38   let (i, keys) = keys_and_values(i)?;
39   Ok((i, (category, keys)))
40 }
41 
categories(i: &[u8]) -> IResult<&[u8], HashMap<&str, HashMap<&str, &str>>>42 fn categories(i: &[u8]) -> IResult<&[u8], HashMap<&str, HashMap<&str, &str>>> {
43   map(
44     many0(separated_pair(
45       category,
46       opt(multispace),
47       map(
48         many0(terminated(key_value, opt(multispace))),
49         |vec: Vec<_>| vec.into_iter().collect(),
50       ),
51     )),
52     |vec: Vec<_>| vec.into_iter().collect(),
53   )(i)
54 }
55 
56 #[test]
parse_category_test()57 fn parse_category_test() {
58   let ini_file = &b"[category]
59 
60 parameter=value
61 key = value2"[..];
62 
63   let ini_without_category = &b"\n\nparameter=value
64 key = value2"[..];
65 
66   let res = category(ini_file);
67   println!("{:?}", res);
68   match res {
69     Ok((i, o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
70     _ => println!("error"),
71   }
72 
73   assert_eq!(res, Ok((ini_without_category, "category")));
74 }
75 
76 #[test]
parse_key_value_test()77 fn parse_key_value_test() {
78   let ini_file = &b"parameter=value
79 key = value2"[..];
80 
81   let ini_without_key_value = &b"\nkey = value2"[..];
82 
83   let res = key_value(ini_file);
84   println!("{:?}", res);
85   match res {
86     Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
87     _ => println!("error"),
88   }
89 
90   assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
91 }
92 
93 #[test]
parse_key_value_with_space_test()94 fn parse_key_value_with_space_test() {
95   let ini_file = &b"parameter = value
96 key = value2"[..];
97 
98   let ini_without_key_value = &b"\nkey = value2"[..];
99 
100   let res = key_value(ini_file);
101   println!("{:?}", res);
102   match res {
103     Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
104     _ => println!("error"),
105   }
106 
107   assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
108 }
109 
110 #[test]
parse_key_value_with_comment_test()111 fn parse_key_value_with_comment_test() {
112   let ini_file = &b"parameter=value;abc
113 key = value2"[..];
114 
115   let ini_without_key_value = &b"\nkey = value2"[..];
116 
117   let res = key_value(ini_file);
118   println!("{:?}", res);
119   match res {
120     Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
121     _ => println!("error"),
122   }
123 
124   assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
125 }
126 
127 #[test]
parse_multiple_keys_and_values_test()128 fn parse_multiple_keys_and_values_test() {
129   let ini_file = &b"parameter=value;abc
130 
131 key = value2
132 
133 [category]"[..];
134 
135   let ini_without_key_value = &b"[category]"[..];
136 
137   let res = keys_and_values(ini_file);
138   println!("{:?}", res);
139   match res {
140     Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
141     _ => println!("error"),
142   }
143 
144   let mut expected: HashMap<&str, &str> = HashMap::new();
145   expected.insert("parameter", "value");
146   expected.insert("key", "value2");
147   assert_eq!(res, Ok((ini_without_key_value, expected)));
148 }
149 
150 #[test]
parse_category_then_multiple_keys_and_values_test()151 fn parse_category_then_multiple_keys_and_values_test() {
152   //FIXME: there can be an empty line or a comment line after a category
153   let ini_file = &b"[abcd]
154 parameter=value;abc
155 
156 key = value2
157 
158 [category]"[..];
159 
160   let ini_after_parser = &b"[category]"[..];
161 
162   let res = category_and_keys(ini_file);
163   println!("{:?}", res);
164   match res {
165     Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
166     _ => println!("error"),
167   }
168 
169   let mut expected_h: HashMap<&str, &str> = HashMap::new();
170   expected_h.insert("parameter", "value");
171   expected_h.insert("key", "value2");
172   assert_eq!(res, Ok((ini_after_parser, ("abcd", expected_h))));
173 }
174 
175 #[test]
parse_multiple_categories_test()176 fn parse_multiple_categories_test() {
177   let ini_file = &b"[abcd]
178 
179 parameter=value;abc
180 
181 key = value2
182 
183 [category]
184 parameter3=value3
185 key4 = value4
186 "[..];
187 
188   let ini_after_parser = &b""[..];
189 
190   let res = categories(ini_file);
191   //println!("{:?}", res);
192   match res {
193     Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
194     _ => println!("error"),
195   }
196 
197   let mut expected_1: HashMap<&str, &str> = HashMap::new();
198   expected_1.insert("parameter", "value");
199   expected_1.insert("key", "value2");
200   let mut expected_2: HashMap<&str, &str> = HashMap::new();
201   expected_2.insert("parameter3", "value3");
202   expected_2.insert("key4", "value4");
203   let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
204   expected_h.insert("abcd", expected_1);
205   expected_h.insert("category", expected_2);
206   assert_eq!(res, Ok((ini_after_parser, expected_h)));
207 }
208