flams_utils/
globals.rs

1pub mod reexport {
2    pub use inventory::{collect, iter, submit};
3    pub use paste::paste;
4}
5
6#[macro_export]
7macro_rules! global {
8  (NEW $({$path:path})? $structname:ty; $instance:ident [$($arg:expr),*]) => {
9    $crate::globals::reexport::paste!{
10      pub static [<$instance:snake:upper>]: $($path::)?[<$structname Id>] = $($path::)?[<$structname Id>](&$($path::)?$structname::__new__(
11        stringify!($instance) $(,$arg)*
12      ));
13      $crate::globals::reexport::submit!([<$instance:snake:upper>]);
14    }
15  };
16  (SER?
17    $(#[$meta:meta])*
18    $structname:ident {
19      $mainname:ident
20      $(, $name:ident : $type:ty )*
21    }
22  ) => {
23    #[cfg(feature="serde")]
24    $crate::global!{SER
25      $(#[$meta])*
26      $structname { $mainname $(,$name : $type)*}
27    }
28    #[cfg(not(feature="serde"))]
29    $crate::global!{@BASE
30      $(#[$meta])*
31      $structname { $mainname $(,$name : $type)*}
32    }
33  };
34  (SER
35    $(#[$meta:meta])*
36    $structname:ident {
37      $mainname:ident
38      $(, $name:ident : $type:ty )*
39    }
40  ) => {
41    $crate::global!{@BASE
42      $(#[$meta])*
43      $structname { $mainname $(,$name : $type)*}
44    }
45
46    $crate::globals::reexport::paste!{
47      impl ::serde::Serialize for [<$structname Id>] {
48        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
49            where
50                S: ::serde::Serializer {
51          serializer.serialize_str(self.0.$mainname)
52        }
53      }
54
55      impl<'de> ::serde::Deserialize<'de> for [<$structname Id>] {
56        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
57            where
58                D: ::serde::Deserializer<'de> {
59            let s = String::deserialize(deserializer)?;
60            $structname::get_from_str(&s)
61                .map_or_else(
62                  || Err(::serde::de::Error::custom("Unknown source file type")),
63                  Ok
64                )
65        }
66      }
67    }
68  };
69  (
70    $(#[$meta:meta])*
71    $structname:ident {
72      $mainname:ident
73      $(, $name:ident : $type:ty )*
74    }
75  ) => {
76    $crate::global!{@BASE
77      $(#[$meta])*
78      $structname { $mainname $(,$name : $type)*}
79    }
80  };
81  (@BASE
82    $(#[$meta:meta])*
83    $structname:ident {
84      $mainname:ident
85      $(, $name:ident : $type:ty )*
86    }
87  ) => {$crate::globals::reexport::paste!{
88
89    #[derive(Copy,Clone,Debug)]
90    pub struct [< $structname Id >](pub &'static $structname);
91    impl std::fmt::Display for [< $structname Id >] {
92      fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        f.write_str(self.0.$mainname)
94      }
95    }
96    impl Eq for [< $structname Id >] {}
97    impl PartialEq for [< $structname Id >] {
98      #[inline]
99      fn eq(&self, other: &Self) -> bool {
100          self.0.$mainname.as_ptr() == other.0.$mainname.as_ptr()
101      }
102    }
103    impl std::hash::Hash for [< $structname Id >] {
104      #[inline]
105      fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
106          self.0.$mainname.as_ptr().hash(state);
107      }
108    }
109    impl std::convert::AsRef<$structname> for [< $structname Id >] {
110      #[inline]
111      fn as_ref(&self) -> &'static $structname { self.0 }
112    }
113    impl std::ops::Deref for [< $structname Id >] {
114      type Target = $structname;
115      #[inline]
116      fn deref(&self) -> &'static $structname { self.0 }
117    }
118
119
120    $(#[$meta])*
121    #[derive(Debug)]
122    pub struct $structname {
123      $mainname:&'static str
124      $( ,$name:$type )*
125    }
126    $crate::globals::reexport::collect!([< $structname Id >]);
127
128    impl $structname {
129      #[inline]#[must_use] pub const fn __new__($mainname:&'static str $(,$name:$type)*) -> Self {
130        Self { $mainname $(,$name)* }
131      }
132      #[inline] pub fn all() -> impl Iterator<Item=&'static Self> {
133        $crate::globals::reexport::iter::<[< $structname Id >]>.into_iter().map(|e| e.0)
134      }
135
136      #[inline]#[must_use] pub fn get_from_str(s:&str) -> Option<[< $structname Id >]> {
137        Self::all().find(|i| i.$mainname.eq_ignore_ascii_case(s)).map([< $structname Id >])
138      }
139
140      #[inline]#[must_use] pub const fn $mainname(&self) -> &'static str { self.$mainname }
141      $(
142        #[inline]#[must_use] pub const fn $name(&self) -> &$type { &self.$name }
143      )*
144    }
145
146    impl std::fmt::Display for $structname {
147      fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148        f.write_str(self.$mainname)
149      }
150    }
151
152    impl std::hash::Hash for $structname {
153      #[inline]
154      fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
155          self.$mainname.hash(state);
156      }
157    }
158    impl PartialEq for $structname {
159      #[inline]
160      fn eq(&self, other: &Self) -> bool {
161          self.$mainname.as_ptr() == other.$mainname.as_ptr()
162      }
163    }
164  }};
165}