duration_human/
syn.rs

1use syn::{
2    parse::{Parse, ParseStream},
3    punctuated::Punctuated,
4    Ident, LitInt, Token,
5};
6
7use crate::{DurationError, DurationHuman, DurationHumanValidator};
8
9struct ParsedDuration {
10    arg: DurationRangeArgument,
11    duration: DurationHuman,
12}
13
14enum DurationRangeArgument {
15    Min,
16    Default,
17    Max,
18}
19
20impl Parse for DurationHuman {
21    fn parse(input: ParseStream) -> syn::Result<Self> {
22        let human_readable = input.parse::<LitInt>()?.to_string();
23
24        TryInto::<Self>::try_into(human_readable.as_str())
25            .map_err(|duration_error| input.error(duration_error.to_string()))
26    }
27}
28
29impl Parse for DurationHumanValidator {
30    fn parse(input: ParseStream) -> syn::Result<Self> {
31        let parser = Punctuated::<ParsedDuration, Token![,]>::parse_separated_nonempty;
32        let durations: Vec<ParsedDuration> = parser(input)?.into_iter().collect();
33
34        TryInto::<Self>::try_into(durations).map_err(|duration_error| {
35            println!("Validator failure: {duration_error}");
36            input.error(duration_error.to_string())
37        })
38    }
39}
40
41impl Parse for DurationRangeArgument {
42    fn parse(input: ParseStream) -> syn::Result<Self> {
43        let name: Ident = input.parse()?;
44        let name = name.to_string();
45        match name.as_str() {
46            "min" => Ok(Self::Min),
47            "max" => Ok(Self::Max),
48            "default" => Ok(Self::Default),
49
50            _ => Err(input.error(format!(
51                "duration argument '{}' not recognized, use min, max and default",
52                name
53            ))),
54        }
55    }
56}
57
58impl Parse for ParsedDuration {
59    fn parse(input: ParseStream) -> syn::Result<Self> {
60        let arg: DurationRangeArgument = input.parse()?;
61        let _punc: Token![:] = input.parse()?;
62        let duration: DurationHuman = input.parse()?;
63
64        Ok(Self { arg, duration })
65    }
66}
67
68#[derive(Default)]
69struct DurationRangeWithOptionalValues {
70    min: Option<DurationHuman>,
71    max: Option<DurationHuman>,
72    default: Option<DurationHuman>,
73}
74
75impl From<Vec<ParsedDuration>> for DurationRangeWithOptionalValues {
76    fn from(value: Vec<ParsedDuration>) -> Self {
77        value.iter().fold(Self::default(), |mut y, x| {
78            match x.arg {
79                DurationRangeArgument::Min => y.min = Some(x.duration),
80                DurationRangeArgument::Max => y.max = Some(x.duration),
81                DurationRangeArgument::Default => y.default = Some(x.duration),
82            }
83
84            y
85        })
86    }
87}
88
89impl TryFrom<Vec<ParsedDuration>> for DurationHumanValidator {
90    type Error = DurationError;
91
92    fn try_from(value: Vec<ParsedDuration>) -> Result<Self, Self::Error> {
93        let optionals: DurationRangeWithOptionalValues = value.into();
94        optionals.min.map_or_else(
95            || Err(DurationError::DurationValidationMinMustBeSpecified),
96            |min| {
97                optionals.max.map_or_else(
98                    || Err(DurationError::DurationValidationMaxMustBeSpecified),
99                    |max| {
100                        optionals.default.map_or_else(
101                            || Self::try_from((min, max)),
102                            |default| Self::try_from((min, default, max)),
103                        )
104                    },
105                )
106            },
107        )
108    }
109}