spacetime_bindings_macro_input/
util.rs1use proc_macro2::Span;
2use syn::Ident;
3
4pub trait ErrorSource {
5 fn error(self, msg: impl std::fmt::Display) -> syn::Error;
6}
7impl ErrorSource for Span {
8 fn error(self, msg: impl std::fmt::Display) -> syn::Error {
9 syn::Error::new(self, msg)
10 }
11}
12impl ErrorSource for &syn::meta::ParseNestedMeta<'_> {
13 fn error(self, msg: impl std::fmt::Display) -> syn::Error {
14 self.error(msg)
15 }
16}
17
18pub fn check_duplicate<T>(x: &Option<T>, src: impl ErrorSource) -> syn::Result<()> {
20 check_duplicate_msg(x, src, "duplicate attribute")
21}
22pub fn check_duplicate_msg<T>(
23 x: &Option<T>,
24 src: impl ErrorSource,
25 msg: impl std::fmt::Display,
26) -> syn::Result<()> {
27 if x.is_none() {
28 Ok(())
29 } else {
30 Err(src.error(msg))
31 }
32}
33
34pub fn one_of(options: &[super::sym::Symbol]) -> String {
35 match options {
36 [] => "unexpected attribute".to_owned(),
37 [a] => {
38 format!("expected `{a}`")
39 }
40 [a, b] => {
41 format!("expected `{a}` or `{b}`")
42 }
43 _ => {
44 let join = options.join("`, `");
45 format!("expected one of: `{}`", join)
46 }
47 }
48}
49
50#[macro_export]
51macro_rules! match_meta {
52 (match $meta:ident { $($matches:tt)* }) => {{
53 let meta: &syn::meta::ParseNestedMeta = &$meta;
54 match_meta!(@match (), (), meta { $($matches)* })
55 }};
56
57 (@match $acc:tt, $comparisons:tt, $meta:ident { $sym:path => $body:block $($rest:tt)* }) => {
58 match_meta!(@case $acc, $comparisons, $meta, _, $sym, $body, { $($rest)* })
59 };
60 (@match $acc:tt, $comparisons:tt, $meta:ident { $sym:path => $body:expr, $($rest:tt)* }) => {
61 match_meta!(@case $acc, $comparisons, $meta, _, $sym, $body, { $($rest)* })
62 };
63
64 (@match ($($acc:tt)*), ($($comparisons:expr),*), $meta:ident {}) => {
65 match () {
66 $($acc)*
67 _ => return Err($meta.error($crate::util::one_of(&[$($comparisons),*]))),
68 }
69 };
70
71 (@case ($($acc:tt)*), ($($comparisons:expr),*), $meta:ident, $binding:tt, $sym:path, $body:expr, { $($rest:tt)* }) => {
72 match_meta!(@match (
73 $($acc)*
74 _ if $meta.path == $sym => $body,
75 ), ($($comparisons,)* $sym), $meta { $($rest)* })
76 };
77}
78pub use match_meta;
79
80pub fn ident_to_litstr(ident: &Ident) -> syn::LitStr {
81 syn::LitStr::new(&ident.to_string(), ident.span())
82}