1mod utils;
2use quote::{ToTokens, quote};
3use proc_macro::TokenStream;
4use syn::{parse_macro_input, parse_quote, AttributeArgs, DeriveInput, Meta, MetaList, NestedMeta};
5use utils::{fallible_macro, Options};
6
7
8fn strum_enum(input: &DeriveInput, attr_args: &[NestedMeta]) -> proc_macro2::TokenStream {
9 let name_arg = attr_args.iter().find_map(|meta| {
11 if let NestedMeta::Meta(Meta::List(MetaList { path, nested, .. })) = meta {
12 if path.is_ident("name") {
13 return Some(quote! { name(#nested) });
14 }
15 }
16 None
17 });
18
19 let maybe_name = if let Some(name) = name_arg {
20 quote! { #name, }
21 } else {
22 quote! {}
23 };
24
25 let ident = &input.ident;
26 quote! {
27 #[derive(
28 Clone, Debug, PartialEq,
29 ::saa_schema::strum_macros::Display,
30 ::saa_schema::strum_macros::EnumDiscriminants,
31 ::saa_schema::strum_macros::VariantNames
32 )]
33 #[strum_discriminants(
34 #maybe_name
35 derive(
36 ::saa_schema::strum_macros::Display,
37 ::saa_schema::strum_macros::EnumString,
38 ::saa_schema::strum_macros::VariantArray,
39 ::saa_schema::strum_macros::AsRefStr
40 ),
41 strum(serialize_all = "snake_case", crate = "::saa_schema::strum")
42 )]
43 #[strum(serialize_all = "snake_case", crate = "::saa_schema::strum")]
44 #[allow(clippy::derive_partial_eq_without_eq)]
45 #input
46
47 impl ::saa_schema::strum::IntoDiscriminant for Box<#ident> {
48 type Discriminant = <#ident as ::saa_schema::strum::IntoDiscriminant>::Discriminant;
49 fn discriminant(&self) -> Self::Discriminant {
50 (*self).discriminant()
51 }
52 }
53 }
54}
55
56
57
58
59#[proc_macro_attribute]
60pub fn saa_type(
61 _attr: TokenStream,
62 input: TokenStream,
63) -> TokenStream {
64 let input_ast = parse_macro_input!(input as DeriveInput);
65 match &input_ast.data {
66 syn::Data::Struct(_) => {
67 quote! {
68 #[derive(Clone, Debug, PartialEq)]
69 #[allow(clippy::derive_partial_eq_without_eq)]
70 #input_ast
71 }.into()
72 },
73 syn::Data::Enum(_) => {
74 quote! {
75 #[derive(Clone, Debug, PartialEq)]
76 #[allow(clippy::derive_partial_eq_without_eq)]
77 #input_ast
78 }.into()
79 },
80 syn::Data::Union(_) => panic!("unions are not supported"),
81 }
82}
83
84
85
86fallible_macro! {
87 #[proc_macro_attribute]
88 pub fn saa_error(
89 attr: proc_macro::TokenStream,
90 input: proc_macro::TokenStream,
91 ) -> syn::Result<proc_macro::TokenStream> {
92 let options = syn::parse(attr)?;
93 let input = syn::parse(input)?;
94 let expanded = saa_error_impl(input, options)?;
95 Ok(expanded.into_token_stream().into())
96 }
97}
98
99
100
101fn saa_error_impl(input: DeriveInput, options: Options) -> syn::Result<DeriveInput> {
102 let crate_path = &options.crate_path;
103 let error_path: syn::Path = syn::parse_quote!(#crate_path::thiserror::Error);
104 let mut stream = quote! {
105 #[derive(Debug, #error_path)]
106 };
107 match &input.data {
108 syn::Data::Enum(_) => {},
109 _ => return Err(syn::Error::new_spanned(&input, "Only enums are supported")),
110 };
111 stream.extend(input.to_token_stream());
112 syn::parse2(stream)
113}
114
115
116
117#[proc_macro_attribute]
118pub fn saa_derivable(
119 attr: TokenStream,
120 input: TokenStream,
121) -> TokenStream {
122 let attr_args = parse_macro_input!(attr as AttributeArgs);
123 let input_ast = parse_macro_input!(input as DeriveInput);
124 match &input_ast.data {
125 syn::Data::Struct(_) => {
126 quote! {
127 #[derive(Clone, Debug, PartialEq)]
128 #[allow(clippy::derive_partial_eq_without_eq)]
129 #input_ast
130 }.into()
131 },
132 syn::Data::Enum(_) => {
133 strum_enum(&input_ast, &attr_args).into()
134 },
135 syn::Data::Union(_) => panic!("unions are not supported"),
136 }
137}
138
139
140
141
142#[proc_macro_attribute]
143pub fn saa_str_struct(
144 _attr: proc_macro::TokenStream,
145 input: proc_macro::TokenStream,
146) -> proc_macro::TokenStream {
147 let input = parse_macro_input!(input as DeriveInput);
148
149 let expanded : DeriveInput = match input.data {
150 syn::Data::Struct(_) => parse_quote! {
151 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
152 #input
153 },
154 syn::Data::Enum(_) => panic!("enums are not supported"),
155 syn::Data::Union(_) => panic!("unions are not supported"),
156 };
157
158 let stream = expanded.into_token_stream();
159
160 proc_macro::TokenStream::from(stream)
161}