1#![deny(
2 clippy::all,
3 clippy::pedantic,
4 clippy::cargo,
5 clippy::nursery,
6 clippy::unwrap_in_result,
7 clippy::unwrap_used,
8 clippy::expect_used
9)]
10use duration_human::DurationHumanValidator;
11use proc_macro::TokenStream;
12use quote::{format_ident, quote};
13use syn::{braced, parse::Parse, parse_macro_input, Ident, Token};
14
15#[proc_macro]
42pub fn assign_duration_range_validator(input: TokenStream) -> TokenStream {
43 let assignment = parse_macro_input!(input as DurationRangeAssignment);
44
45 let range = &assignment.range;
46
47 let ident = format_ident!("{}", assignment.name.to_ascii_uppercase());
48 let (minimal_ms, default_ms, maximal_ms): (u64, u64, u64) = range.into();
49
50 let s = format!(
51 "Validator to check that a human-friendly duration is between {min} and {max}, or defaults to {default:#}.",
52 min = &assignment.range.min,
53 default = &assignment.range.default,
54 max = &assignment.range.max
55 );
56
57 TokenStream::from(quote! {
58 #[doc=#s]
59 const #ident: DurationHumanValidator = DurationHumanValidator::new(#minimal_ms, #default_ms, #maximal_ms);
60 })
61}
62
63#[proc_macro]
64pub fn duration_range_validator(input: TokenStream) -> TokenStream {
65 let validator = parse_macro_input!(input as DurationHumanValidator);
66
67 let (minimal_ms, default_ms, maximal_ms): (u64, u64, u64) = (&validator).into();
68
69 TokenStream::from(quote! {
70 DurationHumanValidator::new(#minimal_ms, #default_ms, #maximal_ms)
71 })
72}
73
74#[proc_macro]
97pub fn duration_range_value_parse(input: TokenStream) -> TokenStream {
98 let validator = parse_macro_input!(input as DurationHumanValidator);
99
100 let (minimal_ms, default_ms, maximal_ms): (u64, u64, u64) = (&validator).into();
101
102 TokenStream::from(quote! {
103 {|interval: &str|DurationHumanValidator::new(#minimal_ms, #default_ms, #maximal_ms).parse_and_validate(interval)}
104 })
105}
106
107struct DurationRangeAssignment {
108 name: String,
109 range: DurationHumanValidator,
110}
111
112impl Parse for DurationRangeAssignment {
113 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
114 let name: Ident = input.parse()?;
115 let _punc: Token![=] = input.parse()?;
116 let inner;
117 braced!(inner in input);
118 let range: DurationHumanValidator = inner.parse()?;
119 Ok(Self {
120 name: name.to_string(),
121 range,
122 })
123 }
124}