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, PartialOrd, 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 pub fn has_id(&self, name: &str) -> bool {
211 match self {
212 Self::Identifier(value) => value == name,
213 Self::Value(value) => value.as_str() == Some(name),
214 Self::Array(values) => values.iter().any(|meta| meta.has_id(name)),
215 Self::Map(values) => values.iter().any(|(key, _)| key == name),
216 Self::Named(key, _) => key == name,
217 }
218 }
219
220 pub fn extract_by_id(&'_ self, name: &str) -> Option<MetaExtract<'_>> {
221 match self {
222 Self::Identifier(value) => {
223 if value == name {
224 Some(MetaExtract::Identifier(value.as_str()))
225 } else {
226 None
227 }
228 }
229 Self::Value(value) => {
230 if value.as_str() == Some(name) {
231 Some(MetaExtract::Value(value))
232 } else {
233 None
234 }
235 }
236 Self::Array(values) => values
237 .iter()
238 .filter_map(|meta| meta.extract_by_id(name))
239 .next(),
240 Self::Map(values) => values
241 .iter()
242 .filter_map(|(key, value)| {
243 if key == name {
244 Some(MetaExtract::Meta(value))
245 } else {
246 None
247 }
248 })
249 .next(),
250 Self::Named(key, value) => {
251 if key == name {
252 Some(MetaExtract::Meta(value))
253 } else {
254 None
255 }
256 }
257 }
258 }
259
260 pub fn items_iter(&'_ self) -> MetaExtractIter<'_> {
261 match self {
262 Self::Identifier(name) => {
263 MetaExtractIter::new(std::iter::once(MetaExtract::Identifier(name.as_str())))
264 }
265 Self::Value(value) => MetaExtractIter::new(std::iter::once(MetaExtract::Value(value))),
266 Self::Array(values) => MetaExtractIter::new(values.iter().map(MetaExtract::Meta)),
267 Self::Map(values) => MetaExtractIter::new(values.values().map(MetaExtract::Meta)),
268 Self::Named(_, value) => {
269 MetaExtractIter::new(std::iter::once(MetaExtract::Meta(value)))
270 }
271 }
272 }
273}
274
275impl std::fmt::Display for Meta {
276 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277 match self {
278 Self::Identifier(value) => value.fmt(f),
279 Self::Value(value) => value.fmt(f),
280 Self::Array(value) => {
281 f.write_char('[')?;
282 for (index, value) in value.iter().enumerate() {
283 if index > 0 {
284 f.write_str(", ")?;
285 }
286 value.fmt(f)?;
287 }
288 f.write_char(']')
289 }
290 Self::Map(value) => {
291 f.write_char('{')?;
292 for (index, (key, value)) in value.iter().enumerate() {
293 if index > 0 {
294 f.write_str(", ")?;
295 }
296 key.fmt(f)?;
297 f.write_str(": ")?;
298 value.fmt(f)?;
299 }
300 f.write_char('}')
301 }
302 Self::Named(name, value) => {
303 f.write_str(name)?;
304 f.write_str(" = ")?;
305 value.fmt(f)
306 }
307 }
308 }
309}
310
311#[derive(Debug, PartialEq)]
312pub enum MetaExtract<'a> {
313 Undefined,
314 Identifier(&'a str),
315 Meta(&'a Meta),
316 Value(&'a MetaValue),
317}
318
319impl MetaExtract<'_> {
320 pub fn is_undefined(&self) -> bool {
321 matches!(self, Self::Undefined)
322 }
323
324 pub fn as_identifier(&self) -> Option<&str> {
325 match self {
326 Self::Identifier(value) => Some(*value),
327 _ => None,
328 }
329 }
330
331 pub fn as_value(&self) -> Option<&MetaValue> {
332 match self {
333 Self::Value(value) => Some(*value),
334 _ => None,
335 }
336 }
337
338 pub fn as_meta(&self) -> Option<&Meta> {
339 match self {
340 Self::Meta(value) => Some(*value),
341 _ => None,
342 }
343 }
344}
345
346pub struct MetaExtractIter<'a>(Box<dyn Iterator<Item = MetaExtract<'a>> + 'a>);
347
348impl<'a> MetaExtractIter<'a> {
349 fn new(iter: impl Iterator<Item = MetaExtract<'a>> + 'a) -> Self {
350 Self(Box::new(iter))
351 }
352}
353
354impl<'a> Iterator for MetaExtractIter<'a> {
355 type Item = MetaExtract<'a>;
356
357 fn next(&mut self) -> Option<Self::Item> {
358 self.0.next()
359 }
360}
361
362#[macro_export]
363macro_rules! meta {
364 (@item { $( $key:ident : $item:tt ),* }) => {{
365 #[allow(unused_mut)]
366 let mut result = std::collections::HashMap::default();
367 $(
368 result.insert(
369 stringify!($key).to_owned(),
370 $crate::meta!(@item $item),
371 );
372 )*
373 $crate::meta::Meta::Map(result)
374 }};
375 (@item [ $( $item:tt ),* ]) => {
376 $crate::meta::Meta::Array(vec![ $( $crate::meta!(@item $item) ),* ])
377 };
378 (@item ( $name:ident = $item:tt )) => {
379 $crate::meta::Meta::Named(
380 stringify!($name).to_owned(),
381 Box::new($crate::meta!(@item $item))
382 )
383 };
384 (@item $value:literal) => {
385 $crate::meta::Meta::Value($crate::meta::MetaValue::from($value))
386 };
387 (@item $value:ident) => {
388 $crate::meta::Meta::Identifier(stringify!($value).to_owned())
389 };
390 ($tree:tt) => {
391 $crate::meta!(@item $tree)
392 };
393}
394
395#[cfg(test)]
396mod tests {
397 use super::*;
398
399 #[test]
400 fn test_parser() {
401 println!("{}", Meta::parse("foo").unwrap());
402 println!("{}", Meta::parse("true").unwrap());
403 println!("{}", Meta::parse("42").unwrap());
404 println!("{}", Meta::parse("4.2").unwrap());
405 println!("{}", Meta::parse("'foo'").unwrap());
406 println!("{}", Meta::parse("foo = true").unwrap());
407 println!(
408 "{}",
409 Meta::parse("[true, 42, 4.2, 'foo', foo = true]").unwrap()
410 );
411 println!(
412 "{}",
413 Meta::parse("{bool: true, integer: 42, float: 4.2, string: 'foo', named: foo = true}")
414 .unwrap()
415 );
416 }
417
418 #[test]
419 fn test_macro() {
420 let meta = crate::meta!(foo);
421 assert!(matches!(meta, Meta::Identifier(_)));
422 assert_eq!(meta.as_identifier().unwrap(), "foo");
423
424 let meta = crate::meta!(true);
425 assert!(matches!(meta, Meta::Value(MetaValue::Bool(_))));
426 assert!(meta.as_value().unwrap().as_bool().unwrap());
427
428 let meta = crate::meta!(42);
429 assert!(matches!(meta, Meta::Value(MetaValue::Integer(_))));
430 assert_eq!(meta.as_value().unwrap().as_integer().unwrap(), 42);
431
432 let meta = crate::meta!(4.2);
433 assert!(matches!(meta, Meta::Value(MetaValue::Float(_))));
434 assert_eq!(meta.as_value().unwrap().as_float().unwrap(), 4.2);
435
436 let meta = crate::meta!("foo");
437 assert!(matches!(meta, Meta::Value(MetaValue::String(_))));
438 assert_eq!(meta.as_value().unwrap().as_str().unwrap(), "foo");
439
440 let meta = crate::meta!([]);
441 assert!(matches!(meta, Meta::Array(_)));
442
443 let meta = crate::meta!([true, 42, 4.2, "foo"]);
444 assert!(
445 meta.as_array().unwrap()[0]
446 .as_value()
447 .unwrap()
448 .as_bool()
449 .unwrap()
450 );
451 assert_eq!(
452 meta.as_array().unwrap()[1]
453 .as_value()
454 .unwrap()
455 .as_integer()
456 .unwrap(),
457 42
458 );
459 assert_eq!(
460 meta.as_array().unwrap()[2]
461 .as_value()
462 .unwrap()
463 .as_float()
464 .unwrap(),
465 4.2
466 );
467 assert_eq!(
468 meta.as_array().unwrap()[3]
469 .as_value()
470 .unwrap()
471 .as_str()
472 .unwrap(),
473 "foo"
474 );
475
476 let meta = crate::meta!({});
477 assert!(matches!(meta, Meta::Map(_)));
478
479 let meta = crate::meta!({bool: true, integer: 42, float: 4.2, string: "foo"});
480 assert!(
481 meta.as_map().unwrap()["bool"]
482 .as_value()
483 .unwrap()
484 .as_bool()
485 .unwrap()
486 );
487 assert_eq!(
488 meta.as_map().unwrap()["integer"]
489 .as_value()
490 .unwrap()
491 .as_integer()
492 .unwrap(),
493 42
494 );
495 assert_eq!(
496 meta.as_map().unwrap()["float"]
497 .as_value()
498 .unwrap()
499 .as_float()
500 .unwrap(),
501 4.2
502 );
503 assert_eq!(
504 meta.as_map().unwrap()["string"]
505 .as_value()
506 .unwrap()
507 .as_str()
508 .unwrap(),
509 "foo"
510 );
511
512 let meta = crate::meta!((foo = true));
513 assert!(matches!(meta, Meta::Named(_, _)));
514 assert_eq!(meta.as_named().unwrap().0, "foo");
515 assert!(
516 meta.as_named()
517 .unwrap()
518 .1
519 .as_value()
520 .unwrap()
521 .as_bool()
522 .unwrap()
523 );
524 }
525
526 #[test]
527 fn test_meta_extract() {
528 let meta = crate::meta!(foo);
529 assert!(meta.has_id("foo"));
530 assert_eq!(
531 meta.extract_by_id("foo").unwrap(),
532 MetaExtract::Identifier("foo")
533 );
534 assert_eq!(
535 meta.items_iter().collect::<Vec<_>>(),
536 vec![MetaExtract::Identifier("foo")]
537 );
538
539 let meta = crate::meta!("foo");
540 assert!(meta.has_id("foo"));
541 assert_eq!(
542 meta.extract_by_id("foo").unwrap(),
543 MetaExtract::Value(&MetaValue::String("foo".to_owned()))
544 );
545 assert_eq!(
546 meta.items_iter().collect::<Vec<_>>(),
547 vec![MetaExtract::Value(&MetaValue::String("foo".to_owned()))]
548 );
549
550 let meta = crate::meta!([true, 42, 4.2, "foo"]);
551 assert!(meta.has_id("foo"));
552 assert_eq!(
553 meta.extract_by_id("foo").unwrap(),
554 MetaExtract::Value(&MetaValue::String("foo".to_owned()))
555 );
556 assert_eq!(
557 meta.items_iter().collect::<Vec<_>>(),
558 vec![
559 MetaExtract::Meta(&Meta::Value(MetaValue::Bool(true))),
560 MetaExtract::Meta(&Meta::Value(MetaValue::Integer(42))),
561 MetaExtract::Meta(&Meta::Value(MetaValue::Float(4.2))),
562 MetaExtract::Meta(&Meta::Value(MetaValue::String("foo".to_owned()))),
563 ]
564 );
565
566 let meta = crate::meta!({bool: true, integer: 42, float: 4.2, string: "foo"});
567 assert!(meta.has_id("bool"));
568 assert!(meta.has_id("integer"));
569 assert!(meta.has_id("float"));
570 assert!(meta.has_id("string"));
571 assert_eq!(
572 meta.extract_by_id("bool").unwrap(),
573 MetaExtract::Meta(&Meta::Value(MetaValue::Bool(true)))
574 );
575 assert_eq!(
576 meta.extract_by_id("integer").unwrap(),
577 MetaExtract::Meta(&Meta::Value(MetaValue::Integer(42)))
578 );
579 assert_eq!(
580 meta.extract_by_id("float").unwrap(),
581 MetaExtract::Meta(&Meta::Value(MetaValue::Float(4.2)))
582 );
583 assert_eq!(
584 meta.extract_by_id("string").unwrap(),
585 MetaExtract::Meta(&Meta::Value(MetaValue::String("foo".to_owned())))
586 );
587 let mut result = meta.items_iter().collect::<Vec<_>>();
588 result.sort_by(|a, b| {
589 let a = match a {
590 MetaExtract::Meta(Meta::Value(MetaValue::Bool(_))) => 0,
591 MetaExtract::Meta(Meta::Value(MetaValue::Integer(_))) => 1,
592 MetaExtract::Meta(Meta::Value(MetaValue::Float(_))) => 2,
593 MetaExtract::Meta(Meta::Value(MetaValue::String(_))) => 3,
594 _ => 4,
595 };
596 let b = match b {
597 MetaExtract::Meta(Meta::Value(MetaValue::Bool(_))) => 0,
598 MetaExtract::Meta(Meta::Value(MetaValue::Integer(_))) => 1,
599 MetaExtract::Meta(Meta::Value(MetaValue::Float(_))) => 2,
600 MetaExtract::Meta(Meta::Value(MetaValue::String(_))) => 3,
601 _ => 4,
602 };
603 a.cmp(&b)
604 });
605 assert_eq!(
606 result,
607 vec![
608 MetaExtract::Meta(&Meta::Value(MetaValue::Bool(true))),
609 MetaExtract::Meta(&Meta::Value(MetaValue::Integer(42))),
610 MetaExtract::Meta(&Meta::Value(MetaValue::Float(4.2))),
611 MetaExtract::Meta(&Meta::Value(MetaValue::String("foo".to_owned()))),
612 ]
613 );
614
615 let meta = crate::meta!((foo = true));
616 assert!(meta.has_id("foo"));
617 assert_eq!(
618 meta.extract_by_id("foo").unwrap(),
619 MetaExtract::Meta(&Meta::Value(MetaValue::Bool(true)))
620 );
621 assert_eq!(
622 meta.items_iter().collect::<Vec<_>>(),
623 vec![MetaExtract::Meta(&Meta::Value(MetaValue::Bool(true)))]
624 );
625 }
626}