1#![allow(clippy::needless_continue)]
3
4use proc_macro::TokenStream;
5
6use quote::{quote, ToTokens};
7use syn::{parse_macro_input, DeriveInput, LitStr};
8
9use darling::FromDeriveInput;
10
11#[derive(FromDeriveInput)]
12#[darling(attributes(ora))]
13struct JobType {
14 #[darling(default = default_output)]
15 output: syn::Type,
16 namespace: Option<LitStr>,
17 name: Option<LitStr>,
18
19 ident: syn::Ident,
20}
21
22fn default_output() -> syn::Type {
23 syn::parse_quote! { () }
24}
25
26impl ToTokens for JobType {
27 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
28 let output = &self.output;
29
30 let job_type_str = match (&self.name, &self.namespace) {
31 (None, None) => {
32 panic!(r#"#[ora(name = "..")] or #[ora(namespace = "..")] attributes are required"#)
33 }
34 (Some(_), Some(_)) => {
35 panic!(
36 r#"#[ora(name = "..")] and #[ora(namespace = "..")] attributes are mutually exclusive"#
37 )
38 }
39 (None, Some(ns)) => {
40 let mut job_type_str = ns.value();
41
42 if !job_type_str.is_empty() {
43 job_type_str.push('.');
44 }
45
46 job_type_str.push_str(&self.ident.to_string());
47 job_type_str
48 }
49 (Some(name), None) => name.value(),
50 };
51
52 let ident = &self.ident;
53 tokens.extend(quote! {
54 impl ora::JobType for #ident {
55 type Output = #output;
56
57 fn job_type_id() -> ora::JobTypeId {
58 const ID: ora::JobTypeId = ora::JobTypeId::new_const(#job_type_str);
59 ID
60 }
61 }
62 });
63 }
64}
65
66#[allow(clippy::missing_panics_doc)]
68#[proc_macro_derive(JobType, attributes(ora))]
69pub fn job_type_derive(input: TokenStream) -> TokenStream {
70 let input = parse_macro_input!(input as DeriveInput);
71
72 let job_type = JobType::from_derive_input(&input).unwrap();
73
74 quote! {#job_type}.into()
75}