krunner_derive/
lib.rs

1use darling::ast::Data;
2use darling::{FromDeriveInput, FromVariant};
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{Generics, Ident, LitStr};
6
7#[derive(Debug, FromVariant)]
8#[darling(attributes(action))]
9struct ActionField {
10	ident: Ident,
11
12	id: LitStr,
13	title: LitStr,
14	icon: LitStr,
15}
16
17#[derive(Debug, FromDeriveInput)]
18#[darling(attributes(action), supports(enum_unit))]
19struct Action {
20	ident: Ident,
21	data: Data<ActionField, ()>,
22	generics: Generics,
23}
24
25#[proc_macro_derive(Action, attributes(action))]
26pub fn derive_action(input: TokenStream) -> TokenStream {
27	let (ident, data, generics) = match Action::from_derive_input(&syn::parse_macro_input!(input)) {
28		Ok(Action {
29			ident,
30			data,
31			generics,
32		}) => (ident, data, generics),
33		Err(e) => return e.write_errors().into(),
34	};
35	let variants = data.take_enum().unwrap();
36
37	let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
38
39	let variant_ids = variants.iter().map(|v| &v.ident);
40	let from_ids = variants.iter().map(|ActionField { id, ident, .. }| {
41		quote! { #id => ::std::option::Option::Some(Self::#ident), }
42	});
43	let to_ids = variants.iter().map(|ActionField { id, ident, .. }| {
44		quote! { Self::#ident => #id, }
45	});
46	let infos = variants.iter().map(
47		|ActionField {
48		     ident, title, icon, ..
49		 }| {
50			quote! {
51				Self::#ident => ::krunner::ActionInfo {
52					title: ::std::string::String::from(#title),
53					icon: ::std::string::String::from(#icon),
54				},
55			}
56		},
57	);
58
59	quote! {
60		#[automatically_derived]
61		impl #impl_generics ::krunner::Action for #ident #ty_generics #where_clause {
62			fn all() -> &'static [Self] {
63				&[#(Self::#variant_ids),*]
64			}
65			fn from_id(s: &str) -> ::std::option::Option<Self> {
66				match s {
67					#(#from_ids)*
68					_ => ::std::option::Option::None,
69				}
70			}
71			fn to_id(&self) -> ::std::string::String {
72				<::std::string::String as ::std::convert::From<&str>>::from(match self {
73					#(#to_ids)*
74				})
75			}
76			fn info(&self) -> ::krunner::ActionInfo {
77				match self {
78					#(#infos)*
79				}
80			}
81		}
82	}
83	.into()
84}