1use pest::{Parser, iterators::Pair};
2use pest_derive::Parser;
3use serde::{Deserialize, Serialize};
4use std::{collections::HashMap, fmt::Write};
5
6#[derive(Parser)]
7#[grammar = "meta.pest"]
8struct MetaParser;
9
10impl MetaParser {
11 fn parse_main(content: &str) -> Result<Meta, String> {
12 match Self::parse(Rule::main, content) {
13 Ok(mut pairs) => {
14 let pair = pairs.next().unwrap().into_inner().next().unwrap();
15 match pair.as_rule() {
16 Rule::meta => Ok(Self::parse_meta(pair)),
17 rule => unreachable!("{:?}", rule),
18 }
19 }
20 Err(error) => Err(format!("{}", error)),
21 }
22 }
23
24 fn parse_meta(pair: Pair<Rule>) -> Meta {
25 let pair = pair.into_inner().next().unwrap();
26 match pair.as_rule() {
27 Rule::identifier => Meta::Identifier(Self::parse_identifier(pair)),
28 Rule::value => Meta::Value(Self::parse_value(pair)),
29 Rule::array => Meta::Array(Self::parse_array(pair)),
30 Rule::map => Meta::Map(Self::parse_map(pair)),
31 Rule::named => {
32 let (id, meta) = Self::parse_named(pair);
33 Meta::Named(id, Box::new(meta))
34 }
35 rule => unreachable!("{:?}", rule),
36 }
37 }
38
39 fn parse_identifier(pair: Pair<Rule>) -> String {
40 pair.as_str().to_owned()
41 }
42
43 fn parse_value(pair: Pair<Rule>) -> MetaValue {
44 let pair = pair.into_inner().next().unwrap();
45 match pair.as_rule() {
46 Rule::literal_bool => MetaValue::Bool(pair.as_str().parse::<bool>().unwrap()),
47 Rule::literal_integer => MetaValue::Integer(pair.as_str().parse::<i64>().unwrap()),
48 Rule::literal_float => MetaValue::Float(pair.as_str().parse::<f64>().unwrap()),
49 Rule::literal_string => {
50 MetaValue::String(pair.into_inner().next().unwrap().as_str().to_owned())
51 }
52 rule => unreachable!("{:?}", rule),
53 }
54 }
55
56 fn parse_array(pair: Pair<Rule>) -> Vec<Meta> {
57 pair.into_inner().map(Self::parse_meta).collect()
58 }
59
60 fn parse_map(pair: Pair<Rule>) -> HashMap<String, Meta> {
61 pair.into_inner()
62 .map(|pair| {
63 let mut pairs = pair.into_inner();
64 (
65 Self::parse_identifier(pairs.next().unwrap()),
66 Self::parse_meta(pairs.next().unwrap()),
67 )
68 })
69 .collect()
70 }
71
72 fn parse_named(pair: Pair<Rule>) -> (String, Meta) {
73 let mut pairs = pair.into_inner();
74 (
75 Self::parse_identifier(pairs.next().unwrap()),
76 Self::parse_meta(pairs.next().unwrap()),
77 )
78 }
79}
80
81#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
82pub enum MetaValue {
83 Bool(bool),
84 Integer(i64),
85 Float(f64),
86 String(String),
87}
88
89impl MetaValue {
90 pub fn as_bool(&self) -> Option<bool> {
91 match self {
92 Self::Bool(value) => Some(*value),
93 _ => None,
94 }
95 }
96
97 pub fn as_integer(&self) -> Option<i64> {
98 match self {
99 Self::Integer(value) => Some(*value),
100 _ => None,
101 }
102 }
103
104 pub fn as_float(&self) -> Option<f64> {
105 match self {
106 Self::Float(value) => Some(*value),
107 _ => None,
108 }
109 }
110
111 pub fn as_str(&self) -> Option<&str> {
112 match self {
113 Self::String(value) => Some(value.as_str()),
114 _ => None,
115 }
116 }
117
118 pub fn as_string(&self) -> Option<String> {
119 match self {
120 Self::String(value) => Some(value.to_owned()),
121 _ => None,
122 }
123 }
124}
125
126impl std::fmt::Display for MetaValue {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 match self {
129 Self::Bool(value) => value.fmt(f),
130 Self::Integer(value) => value.fmt(f),
131 Self::Float(value) => value.fmt(f),
132 Self::String(value) => f.write_fmt(format_args!("{:?}", value)),
133 }
134 }
135}
136
137impl From<bool> for MetaValue {
138 fn from(value: bool) -> Self {
139 Self::Bool(value)
140 }
141}
142
143impl From<i64> for MetaValue {
144 fn from(value: i64) -> Self {
145 Self::Integer(value)
146 }
147}
148
149impl From<f64> for MetaValue {
150 fn from(value: f64) -> Self {
151 Self::Float(value)
152 }
153}
154
155impl From<&str> for MetaValue {
156 fn from(value: &str) -> Self {
157 Self::String(value.to_owned())
158 }
159}
160
161#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
162pub enum Meta {
163 Identifier(String),
164 Value(MetaValue),
165 Array(Vec<Meta>),
166 Map(HashMap<String, Meta>),
167 Named(String, Box<Meta>),
168}
169
170impl Meta {
171 pub fn parse(content: &str) -> Result<Self, String> {
172 MetaParser::parse_main(content)
173 }
174
175 pub fn as_identifier(&self) -> Option<&str> {
176 match self {
177 Self::Identifier(value) => Some(value.as_str()),
178 _ => None,
179 }
180 }
181
182 pub fn as_value(&self) -> Option<&MetaValue> {
183 match self {
184 Self::Value(value) => Some(value),
185 _ => None,
186 }
187 }
188
189 pub fn as_array(&self) -> Option<&Vec<Meta>> {
190 match self {
191 Self::Array(value) => Some(value),
192 _ => None,
193 }
194 }
195
196 pub fn as_map(&self) -> Option<&HashMap<String, Meta>> {
197 match self {
198 Self::Map(value) => Some(value),
199 _ => None,
200 }
201 }
202
203 pub fn as_named(&self) -> Option<(&str, &Meta)> {
204 match self {
205 Self::Named(name, value) => Some((name.as_str(), value)),
206 _ => None,
207 }
208 }
209}
210
211impl std::fmt::Display for Meta {
212 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213 match self {
214 Self::Identifier(value) => value.fmt(f),
215 Self::Value(value) => value.fmt(f),
216 Self::Array(value) => {
217 f.write_char('[')?;
218 for (index, value) in value.iter().enumerate() {
219 if index > 0 {
220 f.write_str(", ")?;
221 }
222 value.fmt(f)?;
223 }
224 f.write_char(']')
225 }
226 Self::Map(value) => {
227 f.write_char('{')?;
228 for (index, (key, value)) in value.iter().enumerate() {
229 if index > 0 {
230 f.write_str(", ")?;
231 }
232 key.fmt(f)?;
233 f.write_str(": ")?;
234 value.fmt(f)?;
235 }
236 f.write_char('}')
237 }
238 Self::Named(name, value) => {
239 f.write_str(name)?;
240 f.write_str(" = ")?;
241 value.fmt(f)
242 }
243 }
244 }
245}
246
247#[macro_export]
248macro_rules! meta {
249 (@item { $( $key:ident : $item:tt ),* }) => {{
250 #[allow(unused_mut)]
251 let mut result = std::collections::HashMap::default();
252 $(
253 result.insert(
254 stringify!($key).to_owned(),
255 $crate::meta!(@item $item),
256 );
257 )*
258 $crate::meta::Meta::Map(result)
259 }};
260 (@item [ $( $item:tt ),* ]) => {
261 $crate::meta::Meta::Array(vec![ $( $crate::meta!(@item $item) ),* ])
262 };
263 (@item ( $name:ident = $item:tt )) => {
264 $crate::meta::Meta::Named(
265 stringify!($name).to_owned(),
266 Box::new($crate::meta!(@item $item))
267 )
268 };
269 (@item $value:literal) => {
270 $crate::meta::Meta::Value($crate::meta::MetaValue::from($value))
271 };
272 (@item $value:ident) => {
273 $crate::meta::Meta::Identifier(stringify!($value).to_owned())
274 };
275 ($tree:tt) => {
276 $crate::meta!(@item $tree)
277 };
278}
279
280#[cfg(test)]
281mod tests {
282 use super::*;
283
284 #[test]
285 fn test_parser() {
286 println!("{}", MetaParser::parse_main("foo").unwrap());
287 println!("{}", MetaParser::parse_main("true").unwrap());
288 println!("{}", MetaParser::parse_main("42").unwrap());
289 println!("{}", MetaParser::parse_main("4.2").unwrap());
290 println!("{}", MetaParser::parse_main("'foo'").unwrap());
291 println!(
292 "{}",
293 MetaParser::parse_main("[true, 42, 4.2, 'foo']").unwrap()
294 );
295 println!(
296 "{}",
297 MetaParser::parse_main("{bool: true, integer: 42, float: 4.2, string: 'foo'}").unwrap()
298 );
299 println!("{}", MetaParser::parse_main("foo = true").unwrap());
300 }
301
302 #[test]
303 fn test_macro() {
304 let meta = crate::meta!(foo);
305 assert!(matches!(meta, Meta::Identifier(_)));
306 assert_eq!(meta.as_identifier().unwrap(), "foo");
307 let meta = crate::meta!(true);
308 assert!(matches!(meta, Meta::Value(MetaValue::Bool(_))));
309 assert!(meta.as_value().unwrap().as_bool().unwrap());
310 let meta = crate::meta!(42);
311 assert!(matches!(meta, Meta::Value(MetaValue::Integer(_))));
312 assert_eq!(meta.as_value().unwrap().as_integer().unwrap(), 42);
313 let meta = crate::meta!(4.2);
314 assert!(matches!(meta, Meta::Value(MetaValue::Float(_))));
315 assert_eq!(meta.as_value().unwrap().as_float().unwrap(), 4.2);
316 let meta = crate::meta!("foo");
317 assert!(matches!(meta, Meta::Value(MetaValue::String(_))));
318 assert_eq!(meta.as_value().unwrap().as_str().unwrap(), "foo");
319 let meta = crate::meta!([]);
320 assert!(matches!(meta, Meta::Array(_)));
321 let meta = crate::meta!([true, 42, 4.2, "foo"]);
322 assert!(
323 meta.as_array().unwrap()[0]
324 .as_value()
325 .unwrap()
326 .as_bool()
327 .unwrap()
328 );
329 assert_eq!(
330 meta.as_array().unwrap()[1]
331 .as_value()
332 .unwrap()
333 .as_integer()
334 .unwrap(),
335 42
336 );
337 assert_eq!(
338 meta.as_array().unwrap()[2]
339 .as_value()
340 .unwrap()
341 .as_float()
342 .unwrap(),
343 4.2
344 );
345 assert_eq!(
346 meta.as_array().unwrap()[3]
347 .as_value()
348 .unwrap()
349 .as_str()
350 .unwrap(),
351 "foo"
352 );
353 let meta = crate::meta!({});
354 assert!(matches!(meta, Meta::Map(_)));
355 let meta = crate::meta!({bool: true, integer: 42, float: 4.2, string: "foo"});
356 assert!(
357 meta.as_map().unwrap()["bool"]
358 .as_value()
359 .unwrap()
360 .as_bool()
361 .unwrap()
362 );
363 assert_eq!(
364 meta.as_map().unwrap()["integer"]
365 .as_value()
366 .unwrap()
367 .as_integer()
368 .unwrap(),
369 42
370 );
371 assert_eq!(
372 meta.as_map().unwrap()["float"]
373 .as_value()
374 .unwrap()
375 .as_float()
376 .unwrap(),
377 4.2
378 );
379 assert_eq!(
380 meta.as_map().unwrap()["string"]
381 .as_value()
382 .unwrap()
383 .as_str()
384 .unwrap(),
385 "foo"
386 );
387 let meta = crate::meta!((foo = true));
388 assert!(matches!(meta, Meta::Named(_, _)));
389 assert_eq!(meta.as_named().unwrap().0, "foo");
390 assert!(
391 meta.as_named()
392 .unwrap()
393 .1
394 .as_value()
395 .unwrap()
396 .as_bool()
397 .unwrap()
398 );
399 }
400}