1use pest::{Parser, iterators::Pair};
18use pest_derive::Parser;
19use serde::{Deserialize, Serialize};
20use std::{collections::HashMap, fmt::Write};
21
22#[derive(Parser)]
24#[grammar = "meta.pest"]
25struct MetaParser;
26
27impl MetaParser {
28 fn parse_main(content: &str) -> Result<Meta, String> {
29 match Self::parse(Rule::main, content) {
30 Ok(mut pairs) => {
31 let pair = pairs.next().unwrap().into_inner().next().unwrap();
32 match pair.as_rule() {
33 Rule::meta => Ok(Self::parse_meta(pair)),
34 rule => unreachable!("{:?}", rule),
35 }
36 }
37 Err(error) => Err(format!("{error}")),
38 }
39 }
40
41 fn parse_meta(pair: Pair<Rule>) -> Meta {
42 let pair = pair.into_inner().next().unwrap();
43 match pair.as_rule() {
44 Rule::identifier => Meta::Identifier(Self::parse_identifier(pair)),
45 Rule::value => Meta::Value(Self::parse_value(pair)),
46 Rule::array => Meta::Array(Self::parse_array(pair)),
47 Rule::map => Meta::Map(Self::parse_map(pair)),
48 Rule::named => {
49 let (id, meta) = Self::parse_named(pair);
50 Meta::Named(id, Box::new(meta))
51 }
52 rule => unreachable!("{:?}", rule),
53 }
54 }
55
56 fn parse_identifier(pair: Pair<Rule>) -> String {
57 pair.as_str().to_owned()
58 }
59
60 fn parse_value(pair: Pair<Rule>) -> MetaValue {
61 let pair = pair.into_inner().next().unwrap();
62 match pair.as_rule() {
63 Rule::literal_bool => MetaValue::Bool(pair.as_str().parse::<bool>().unwrap()),
64 Rule::literal_integer => MetaValue::Integer(pair.as_str().parse::<i64>().unwrap()),
65 Rule::literal_float => MetaValue::Float(pair.as_str().parse::<f64>().unwrap()),
66 Rule::literal_string => {
67 MetaValue::String(pair.into_inner().next().unwrap().as_str().to_owned())
68 }
69 rule => unreachable!("{:?}", rule),
70 }
71 }
72
73 fn parse_array(pair: Pair<Rule>) -> Vec<Meta> {
74 pair.into_inner().map(Self::parse_meta).collect()
75 }
76
77 fn parse_map(pair: Pair<Rule>) -> HashMap<String, Meta> {
78 pair.into_inner()
79 .map(|pair| {
80 let mut pairs = pair.into_inner();
81 (
82 Self::parse_identifier(pairs.next().unwrap()),
83 Self::parse_meta(pairs.next().unwrap()),
84 )
85 })
86 .collect()
87 }
88
89 fn parse_named(pair: Pair<Rule>) -> (String, Meta) {
90 let mut pairs = pair.into_inner();
91 (
92 Self::parse_identifier(pairs.next().unwrap()),
93 Self::parse_meta(pairs.next().unwrap()),
94 )
95 }
96}
97
98#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
100pub enum MetaValue {
101 Bool(bool),
103 Integer(i64),
105 Float(f64),
107 String(String),
109}
110
111impl MetaValue {
112 pub fn as_bool(&self) -> Option<bool> {
114 match self {
115 Self::Bool(value) => Some(*value),
116 _ => None,
117 }
118 }
119
120 pub fn as_integer(&self) -> Option<i64> {
122 match self {
123 Self::Integer(value) => Some(*value),
124 _ => None,
125 }
126 }
127
128 pub fn as_float(&self) -> Option<f64> {
130 match self {
131 Self::Float(value) => Some(*value),
132 _ => None,
133 }
134 }
135
136 pub fn as_str(&self) -> Option<&str> {
138 match self {
139 Self::String(value) => Some(value.as_str()),
140 _ => None,
141 }
142 }
143
144 pub fn as_string(&self) -> Option<String> {
146 match self {
147 Self::String(value) => Some(value.to_owned()),
148 _ => None,
149 }
150 }
151}
152
153impl std::fmt::Display for MetaValue {
154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155 match self {
156 Self::Bool(value) => value.fmt(f),
157 Self::Integer(value) => value.fmt(f),
158 Self::Float(value) => value.fmt(f),
159 Self::String(value) => f.write_fmt(format_args!("{value:?}")),
160 }
161 }
162}
163
164impl From<bool> for MetaValue {
165 fn from(value: bool) -> Self {
166 Self::Bool(value)
167 }
168}
169
170impl From<i64> for MetaValue {
171 fn from(value: i64) -> Self {
172 Self::Integer(value)
173 }
174}
175
176impl From<f64> for MetaValue {
177 fn from(value: f64) -> Self {
178 Self::Float(value)
179 }
180}
181
182impl From<&str> for MetaValue {
183 fn from(value: &str) -> Self {
184 Self::String(value.to_owned())
185 }
186}
187
188#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
190pub enum Meta {
191 Identifier(String),
193 Value(MetaValue),
195 Array(Vec<Meta>),
197 Map(HashMap<String, Meta>),
199 Named(String, Box<Meta>),
201}
202
203impl Meta {
204 pub fn parse(content: &str) -> Result<Self, String> {
206 MetaParser::parse_main(content)
207 }
208
209 pub fn as_identifier(&self) -> Option<&str> {
211 match self {
212 Self::Identifier(value) => Some(value.as_str()),
213 _ => None,
214 }
215 }
216
217 pub fn as_value(&self) -> Option<&MetaValue> {
219 match self {
220 Self::Value(value) => Some(value),
221 _ => None,
222 }
223 }
224
225 pub fn as_array(&self) -> Option<&Vec<Meta>> {
227 match self {
228 Self::Array(value) => Some(value),
229 _ => None,
230 }
231 }
232
233 pub fn as_map(&self) -> Option<&HashMap<String, Meta>> {
235 match self {
236 Self::Map(value) => Some(value),
237 _ => None,
238 }
239 }
240
241 pub fn as_named(&self) -> Option<(&str, &Meta)> {
243 match self {
244 Self::Named(name, value) => Some((name.as_str(), value)),
245 _ => None,
246 }
247 }
248
249 pub fn has_id(&self, name: &str) -> bool {
255 match self {
256 Self::Identifier(value) => value == name,
257 Self::Value(value) => value.as_str() == Some(name),
258 Self::Array(values) => values.iter().any(|meta| meta.has_id(name)),
259 Self::Map(values) => values.iter().any(|(key, _)| key == name),
260 Self::Named(key, _) => key == name,
261 }
262 }
263
264 pub fn extract_by_id(&'_ self, name: &str) -> Option<MetaExtract<'_>> {
266 match self {
267 Self::Identifier(value) => {
268 if value == name {
269 Some(MetaExtract::Identifier(value.as_str()))
270 } else {
271 None
272 }
273 }
274 Self::Value(value) => {
275 if value.as_str() == Some(name) {
276 Some(MetaExtract::Value(value))
277 } else {
278 None
279 }
280 }
281 Self::Array(values) => values
282 .iter()
283 .filter_map(|meta| meta.extract_by_id(name))
284 .next(),
285 Self::Map(values) => values
286 .iter()
287 .filter_map(|(key, value)| {
288 if key == name {
289 Some(MetaExtract::Meta(value))
290 } else {
291 None
292 }
293 })
294 .next(),
295 Self::Named(key, value) => {
296 if key == name {
297 Some(MetaExtract::Meta(value))
298 } else {
299 None
300 }
301 }
302 }
303 }
304
305 pub fn items_iter(&'_ self) -> MetaExtractIter<'_> {
307 match self {
308 Self::Identifier(name) => {
309 MetaExtractIter::new(std::iter::once(MetaExtract::Identifier(name.as_str())))
310 }
311 Self::Value(value) => MetaExtractIter::new(std::iter::once(MetaExtract::Value(value))),
312 Self::Array(values) => MetaExtractIter::new(values.iter().map(MetaExtract::Meta)),
313 Self::Map(values) => MetaExtractIter::new(values.values().map(MetaExtract::Meta)),
314 Self::Named(_, value) => {
315 MetaExtractIter::new(std::iter::once(MetaExtract::Meta(value)))
316 }
317 }
318 }
319}
320
321impl std::fmt::Display for Meta {
322 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
323 match self {
324 Self::Identifier(value) => value.fmt(f),
325 Self::Value(value) => value.fmt(f),
326 Self::Array(value) => {
327 f.write_char('[')?;
328 for (index, value) in value.iter().enumerate() {
329 if index > 0 {
330 f.write_str(", ")?;
331 }
332 value.fmt(f)?;
333 }
334 f.write_char(']')
335 }
336 Self::Map(value) => {
337 f.write_char('{')?;
338 for (index, (key, value)) in value.iter().enumerate() {
339 if index > 0 {
340 f.write_str(", ")?;
341 }
342 key.fmt(f)?;
343 f.write_str(": ")?;
344 value.fmt(f)?;
345 }
346 f.write_char('}')
347 }
348 Self::Named(name, value) => {
349 f.write_str(name)?;
350 f.write_str(" = ")?;
351 value.fmt(f)
352 }
353 }
354 }
355}
356
357#[derive(Debug, PartialEq)]
359pub enum MetaExtract<'a> {
360 Undefined,
362 Identifier(&'a str),
364 Meta(&'a Meta),
366 Value(&'a MetaValue),
368}
369
370impl MetaExtract<'_> {
371 pub fn is_undefined(&self) -> bool {
373 matches!(self, Self::Undefined)
374 }
375
376 pub fn as_identifier(&self) -> Option<&str> {
378 match self {
379 Self::Identifier(value) => Some(*value),
380 _ => None,
381 }
382 }
383
384 pub fn as_value(&self) -> Option<&MetaValue> {
386 match self {
387 Self::Value(value) => Some(*value),
388 _ => None,
389 }
390 }
391
392 pub fn as_meta(&self) -> Option<&Meta> {
394 match self {
395 Self::Meta(value) => Some(*value),
396 _ => None,
397 }
398 }
399}
400
401pub struct MetaExtractIter<'a>(Box<dyn Iterator<Item = MetaExtract<'a>> + 'a>);
403
404impl<'a> MetaExtractIter<'a> {
405 fn new(iter: impl Iterator<Item = MetaExtract<'a>> + 'a) -> Self {
406 Self(Box::new(iter))
407 }
408}
409
410impl<'a> Iterator for MetaExtractIter<'a> {
411 type Item = MetaExtract<'a>;
412
413 fn next(&mut self) -> Option<Self::Item> {
414 self.0.next()
415 }
416}
417
418#[macro_export]
426macro_rules! meta {
427 (@item { $( $key:ident : $item:tt ),* }) => {{
428 #[allow(unused_mut)]
429 let mut result = std::collections::HashMap::default();
430 $(
431 result.insert(
432 stringify!($key).to_owned(),
433 $crate::meta!(@item $item),
434 );
435 )*
436 $crate::meta::Meta::Map(result)
437 }};
438 (@item [ $( $item:tt ),* ]) => {
439 $crate::meta::Meta::Array(vec![ $( $crate::meta!(@item $item) ),* ])
440 };
441 (@item ( $name:ident = $item:tt )) => {
442 $crate::meta::Meta::Named(
443 stringify!($name).to_owned(),
444 Box::new($crate::meta!(@item $item))
445 )
446 };
447 (@item $value:literal) => {
448 $crate::meta::Meta::Value($crate::meta::MetaValue::from($value))
449 };
450 (@item $value:ident) => {
451 $crate::meta::Meta::Identifier(stringify!($value).to_owned())
452 };
453 ($tree:tt) => {
454 $crate::meta!(@item $tree)
455 };
456}
457
458#[cfg(test)]
459mod tests {
460 use super::*;
461
462 #[test]
463 fn test_parser() {
464 println!("{}", Meta::parse("foo").unwrap());
465 println!("{}", Meta::parse("true").unwrap());
466 println!("{}", Meta::parse("42").unwrap());
467 println!("{}", Meta::parse("4.2").unwrap());
468 println!("{}", Meta::parse("'foo'").unwrap());
469 println!("{}", Meta::parse("foo = true").unwrap());
470 println!(
471 "{}",
472 Meta::parse("[true, 42, 4.2, 'foo', foo = true]").unwrap()
473 );
474 println!(
475 "{}",
476 Meta::parse("{bool: true, integer: 42, float: 4.2, string: 'foo', named: foo = true}")
477 .unwrap()
478 );
479 }
480
481 #[test]
482 fn test_macro() {
483 let meta = crate::meta!(foo);
484 assert!(matches!(meta, Meta::Identifier(_)));
485 assert_eq!(meta.as_identifier().unwrap(), "foo");
486
487 let meta = crate::meta!(true);
488 assert!(matches!(meta, Meta::Value(MetaValue::Bool(_))));
489 assert!(meta.as_value().unwrap().as_bool().unwrap());
490
491 let meta = crate::meta!(42);
492 assert!(matches!(meta, Meta::Value(MetaValue::Integer(_))));
493 assert_eq!(meta.as_value().unwrap().as_integer().unwrap(), 42);
494
495 let meta = crate::meta!(4.2);
496 assert!(matches!(meta, Meta::Value(MetaValue::Float(_))));
497 assert_eq!(meta.as_value().unwrap().as_float().unwrap(), 4.2);
498
499 let meta = crate::meta!("foo");
500 assert!(matches!(meta, Meta::Value(MetaValue::String(_))));
501 assert_eq!(meta.as_value().unwrap().as_str().unwrap(), "foo");
502
503 let meta = crate::meta!([]);
504 assert!(matches!(meta, Meta::Array(_)));
505
506 let meta = crate::meta!([true, 42, 4.2, "foo"]);
507 assert!(
508 meta.as_array().unwrap()[0]
509 .as_value()
510 .unwrap()
511 .as_bool()
512 .unwrap()
513 );
514 assert_eq!(
515 meta.as_array().unwrap()[1]
516 .as_value()
517 .unwrap()
518 .as_integer()
519 .unwrap(),
520 42
521 );
522 assert_eq!(
523 meta.as_array().unwrap()[2]
524 .as_value()
525 .unwrap()
526 .as_float()
527 .unwrap(),
528 4.2
529 );
530 assert_eq!(
531 meta.as_array().unwrap()[3]
532 .as_value()
533 .unwrap()
534 .as_str()
535 .unwrap(),
536 "foo"
537 );
538
539 let meta = crate::meta!({});
540 assert!(matches!(meta, Meta::Map(_)));
541
542 let meta = crate::meta!({bool: true, integer: 42, float: 4.2, string: "foo"});
543 assert!(
544 meta.as_map().unwrap()["bool"]
545 .as_value()
546 .unwrap()
547 .as_bool()
548 .unwrap()
549 );
550 assert_eq!(
551 meta.as_map().unwrap()["integer"]
552 .as_value()
553 .unwrap()
554 .as_integer()
555 .unwrap(),
556 42
557 );
558 assert_eq!(
559 meta.as_map().unwrap()["float"]
560 .as_value()
561 .unwrap()
562 .as_float()
563 .unwrap(),
564 4.2
565 );
566 assert_eq!(
567 meta.as_map().unwrap()["string"]
568 .as_value()
569 .unwrap()
570 .as_str()
571 .unwrap(),
572 "foo"
573 );
574
575 let meta = crate::meta!((foo = true));
576 assert!(matches!(meta, Meta::Named(_, _)));
577 assert_eq!(meta.as_named().unwrap().0, "foo");
578 assert!(
579 meta.as_named()
580 .unwrap()
581 .1
582 .as_value()
583 .unwrap()
584 .as_bool()
585 .unwrap()
586 );
587 }
588
589 #[test]
590 fn test_meta_extract() {
591 let meta = crate::meta!(foo);
592 assert!(meta.has_id("foo"));
593 assert_eq!(
594 meta.extract_by_id("foo").unwrap(),
595 MetaExtract::Identifier("foo")
596 );
597 assert_eq!(
598 meta.items_iter().collect::<Vec<_>>(),
599 vec![MetaExtract::Identifier("foo")]
600 );
601
602 let meta = crate::meta!("foo");
603 assert!(meta.has_id("foo"));
604 assert_eq!(
605 meta.extract_by_id("foo").unwrap(),
606 MetaExtract::Value(&MetaValue::String("foo".to_owned()))
607 );
608 assert_eq!(
609 meta.items_iter().collect::<Vec<_>>(),
610 vec![MetaExtract::Value(&MetaValue::String("foo".to_owned()))]
611 );
612
613 let meta = crate::meta!([true, 42, 4.2, "foo"]);
614 assert!(meta.has_id("foo"));
615 assert_eq!(
616 meta.extract_by_id("foo").unwrap(),
617 MetaExtract::Value(&MetaValue::String("foo".to_owned()))
618 );
619 assert_eq!(
620 meta.items_iter().collect::<Vec<_>>(),
621 vec![
622 MetaExtract::Meta(&Meta::Value(MetaValue::Bool(true))),
623 MetaExtract::Meta(&Meta::Value(MetaValue::Integer(42))),
624 MetaExtract::Meta(&Meta::Value(MetaValue::Float(4.2))),
625 MetaExtract::Meta(&Meta::Value(MetaValue::String("foo".to_owned()))),
626 ]
627 );
628
629 let meta = crate::meta!({bool: true, integer: 42, float: 4.2, string: "foo"});
630 assert!(meta.has_id("bool"));
631 assert!(meta.has_id("integer"));
632 assert!(meta.has_id("float"));
633 assert!(meta.has_id("string"));
634 assert_eq!(
635 meta.extract_by_id("bool").unwrap(),
636 MetaExtract::Meta(&Meta::Value(MetaValue::Bool(true)))
637 );
638 assert_eq!(
639 meta.extract_by_id("integer").unwrap(),
640 MetaExtract::Meta(&Meta::Value(MetaValue::Integer(42)))
641 );
642 assert_eq!(
643 meta.extract_by_id("float").unwrap(),
644 MetaExtract::Meta(&Meta::Value(MetaValue::Float(4.2)))
645 );
646 assert_eq!(
647 meta.extract_by_id("string").unwrap(),
648 MetaExtract::Meta(&Meta::Value(MetaValue::String("foo".to_owned())))
649 );
650 let mut result = meta.items_iter().collect::<Vec<_>>();
651 result.sort_by(|a, b| {
652 let a = match a {
653 MetaExtract::Meta(Meta::Value(MetaValue::Bool(_))) => 0,
654 MetaExtract::Meta(Meta::Value(MetaValue::Integer(_))) => 1,
655 MetaExtract::Meta(Meta::Value(MetaValue::Float(_))) => 2,
656 MetaExtract::Meta(Meta::Value(MetaValue::String(_))) => 3,
657 _ => 4,
658 };
659 let b = match b {
660 MetaExtract::Meta(Meta::Value(MetaValue::Bool(_))) => 0,
661 MetaExtract::Meta(Meta::Value(MetaValue::Integer(_))) => 1,
662 MetaExtract::Meta(Meta::Value(MetaValue::Float(_))) => 2,
663 MetaExtract::Meta(Meta::Value(MetaValue::String(_))) => 3,
664 _ => 4,
665 };
666 a.cmp(&b)
667 });
668 assert_eq!(
669 result,
670 vec![
671 MetaExtract::Meta(&Meta::Value(MetaValue::Bool(true))),
672 MetaExtract::Meta(&Meta::Value(MetaValue::Integer(42))),
673 MetaExtract::Meta(&Meta::Value(MetaValue::Float(4.2))),
674 MetaExtract::Meta(&Meta::Value(MetaValue::String("foo".to_owned()))),
675 ]
676 );
677
678 let meta = crate::meta!((foo = true));
679 assert!(meta.has_id("foo"));
680 assert_eq!(
681 meta.extract_by_id("foo").unwrap(),
682 MetaExtract::Meta(&Meta::Value(MetaValue::Bool(true)))
683 );
684 assert_eq!(
685 meta.items_iter().collect::<Vec<_>>(),
686 vec![MetaExtract::Meta(&Meta::Value(MetaValue::Bool(true)))]
687 );
688 }
689}