1use proc_macro::TokenStream;
4
5use quote::{quote, ToTokens};
6use syn::{parse_macro_input, DeriveInput, Expr};
7
8use darling::FromDeriveInput;
9
10#[derive(FromDeriveInput)]
11#[darling(attributes(ora))]
12struct JobType {
13 #[darling(default = default_output)]
14 output: syn::Type,
15 #[darling(default)]
16 retries: Option<Expr>,
17 #[darling(default)]
18 timeout: Option<String>,
19
20 #[darling(default)]
21 default_labels: Option<syn::Expr>,
22
23 ident: syn::Ident,
24}
25
26fn default_output() -> syn::Type {
27 syn::parse_quote! { () }
28}
29
30impl ToTokens for JobType {
31 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
32 let output = &self.output;
33 let ident_str = self.ident.to_string();
34
35 let retry_policy = match &self.retries {
36 Some(retries) => quote! {
37 fn default_retry_policy() -> ora::job_definition::RetryPolicy {
38 ora::job_definition::RetryPolicy {
39 retries: #retries,
40 }
41 }
42 },
43 None => quote! {},
44 };
45
46 let timeout_policy = match &self.timeout {
47 Some(timeout) => {
48 let timeout_seconds = humantime::parse_duration(timeout).unwrap().as_secs();
49
50 quote! {
51 fn default_timeout_policy() -> ora::job_definition::TimeoutPolicy {
52 ora::job_definition::TimeoutPolicy {
53 timeout: Some(std::time::Duration::from_secs(#timeout_seconds as _)),
54 base_time: ora::job_definition::TimeoutBaseTime::StartTime,
55 }
56 }
57 }
58 }
59 None => quote! {},
60 };
61
62 let default_labels = match &self.default_labels {
63 Some(default_labels) => quote! {
64 fn default_labels() -> std::collections::HashMap<String, String> {
65 #default_labels
66 }
67 },
68 None => quote! {},
69 };
70
71 let ident = &self.ident;
72 tokens.extend(quote! {
73 impl ora::JobType for #ident {
74 type Output = #output;
75
76 fn id() -> &'static str {
77 #ident_str
78 }
79
80 #retry_policy
81 #timeout_policy
82 #default_labels
83 }
84 });
85 }
86}
87
88#[allow(clippy::missing_panics_doc)]
90#[proc_macro_derive(JobType, attributes(ora))]
91pub fn job_type_derive(input: TokenStream) -> TokenStream {
92 let input = parse_macro_input!(input as DeriveInput);
93
94 let job_type = JobType::from_derive_input(&input).unwrap();
95
96 quote! {#job_type}.into()
97}