Skip to main content

ora_macros/
lib.rs

1//! Macros for the ora crate.
2#![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/// Derive macro for the `JobType` trait.
67#[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}