staircase_derive/
lib.rs

1use darling::FromDeriveInput;
2use proc_macro::TokenStream;
3
4mod componentized_resource;
5mod labeled_resource;
6mod named_resource;
7
8fn format_attributed(
9    format_str: String,
10    add_name: Option<bool>,
11    add_namespace: Option<bool>,
12    add_component: Option<&syn::Ident>,
13) -> proc_macro2::TokenStream {
14    use quote::quote;
15    match (add_name.unwrap_or(true), add_namespace.unwrap_or(false), add_component) {
16        (true, true, Some(c)) => {
17            quote! {
18                format!(#format_str, name=self.metadata.name.as_ref().unwrap(), namespace=self.metadata.namespace.as_ref().unwrap(), component=<#c as ::staircase::resources::ComponentizedResource>::COMPONENT)
19            }
20        },
21        (true, true, None) => {
22            quote! {
23                format!(#format_str, name=self.metadata.name.as_ref().unwrap(), namespace=self.metadata.namespace.as_ref().unwrap())
24            }
25        },
26        (true, false, Some(c)) => {
27            quote! {
28                format!(#format_str, name=self.metadata.name.as_ref().unwrap(), component=<#c as ::staircase::resources::ComponentizedResource>::COMPONENT)
29            }
30        },
31        (true, false, None) => {
32            quote! {
33                format!(#format_str, name=self.metadata.name.as_ref().unwrap())
34            }
35        },
36        (false, true, Some(c)) => {
37            quote! {
38                format!(#format_str, namespace=self.metadata.namespace.as_ref().unwrap(), component=<#c as ::staircase::resources::ComponentizedResource>::COMPONENT)
39            }
40        },
41        (false, true, None) => {
42            quote! {
43                format!(#format_str, namespace=self.metadata.namespace.as_ref().unwrap())
44            }
45        },
46        (false, false, Some(c)) => {
47            quote! {
48                format!(#format_str, component=<#c as ::staircase::resources::ComponentizedResource>::COMPONENT)
49            }
50        },
51        (false, false, None) => {
52            quote! {
53                format!(#format_str)
54            }
55        },
56    }
57}
58
59#[proc_macro_derive(LabeledResource, attributes(staircase))]
60pub fn derive_labeled_resource(input: TokenStream) -> TokenStream {
61    labeled_resource::derive(proc_macro2::TokenStream::from(input)).into()
62}
63
64#[proc_macro_derive(NamedResource, attributes(staircase))]
65pub fn derive_named_resource(input: TokenStream) -> TokenStream {
66    named_resource::derive(proc_macro2::TokenStream::from(input)).into()
67}
68
69#[proc_macro_derive(ComponentizedResource, attributes(staircase))]
70pub fn derive_componentized_resource(input: TokenStream) -> TokenStream {
71    componentized_resource::derive(proc_macro2::TokenStream::from(input)).into()
72}
73
74#[allow(dead_code)]
75#[derive(FromDeriveInput)]
76#[darling(attributes(staircase))]
77struct StaircaseAttrs {
78    name: Option<String>,
79    label: Option<String>,
80    format_name: Option<bool>,
81    format_namespace: Option<bool>,
82    format_component: Option<bool>,
83    resource: Option<syn::Path>,
84    identifier: Option<syn::Path>,
85    component_type: Option<syn::Path>,
86    component_const: Option<syn::Path>,
87}
88
89#[cfg(test)]
90mod tests {
91    use quote::quote;
92
93    use super::*;
94
95    #[test]
96    fn test_parse_default() {
97        let input = quote! {
98            #[staircase(label = "{label}", name = "{name}")]
99            struct FooSpec;
100        };
101        let input = syn::parse2(input).unwrap();
102        let attrs = StaircaseAttrs::from_derive_input(&input).unwrap();
103        assert_eq!(attrs.label, Some("{label}".to_string()));
104        assert_eq!(attrs.name, Some("{name}".to_string()));
105    }
106}