prae_macro/
parsing.rs

1use syn::parse::{Parse, ParseStream};
2use syn::spanned::Spanned;
3use syn::{parenthesized, Attribute, Error, ExprClosure, Ident, Token, Type, Visibility};
4
5pub(crate) struct Definition {
6    pub attrs: Vec<Attribute>,
7    pub vis: Visibility,
8    pub name: Ident,
9    pub inner_type: Type,
10    pub extend_bound: Option<Type>,
11    pub adjust: Option<AdjustClosure>,
12    pub validate: Option<ValidationClosure>,
13}
14
15impl Parse for Definition {
16    fn parse(input: ParseStream) -> syn::Result<Self> {
17        // Parse attributes.
18        let attrs = input.call(Attribute::parse_outer)?;
19
20        // Parse type definition.
21        let vis: Visibility = input.parse()?;
22        let name: Ident = input.parse()?;
23        input.parse::<Token![:]>()?;
24        let inner_type: Type = input.parse()?;
25
26        // Parse optional extend bound.
27        let extend_bound = parse_extend_bound(input)?;
28
29        // Parse closures.
30        let adjust = parse_adjust_closure(input)?;
31        let validate = parse_validation_closure(input)?;
32
33        Ok(Definition {
34            attrs,
35            vis,
36            name,
37            inner_type,
38            extend_bound,
39            adjust,
40            validate,
41        })
42    }
43}
44
45fn parse_extend_bound(input: ParseStream) -> syn::Result<Option<Type>> {
46    if !input.lookahead1().peek(kw::extend) {
47        return Ok(None);
48    }
49    input.parse::<kw::extend>()?;
50    Ok(Some(input.parse()?))
51}
52
53pub(crate) struct AdjustClosure {
54    pub expr: ExprClosure,
55}
56
57fn parse_adjust_closure(input: ParseStream) -> syn::Result<Option<AdjustClosure>> {
58    if !input.lookahead1().peek(kw::adjust) {
59        return Ok(None);
60    }
61    input.parse::<kw::adjust>()?;
62    Ok(Some(AdjustClosure {
63        expr: input.parse()?,
64    }))
65}
66
67#[allow(clippy::large_enum_variant)]
68pub(crate) enum ValidationClosure {
69    Validate(ValidateClosure),
70    Ensure(EnsureClosure),
71}
72
73fn parse_validation_closure(input: ParseStream) -> syn::Result<Option<ValidationClosure>> {
74    let validate = parse_validate_closure(input)?;
75    let ensure = parse_ensure_closure(input)?;
76    match (validate, ensure) {
77        (Some(_), Some(ensure)) => Err(Error::new(
78            ensure.expr.span(),
79            "you can't use both `ensure` and `validate` closures at the same time",
80        )),
81        (Some(validate), None) => Ok(Some(ValidationClosure::Validate(validate))),
82        (None, Some(ensure)) => Ok(Some(ValidationClosure::Ensure(ensure))),
83        (None, None) => Ok(None),
84    }
85}
86
87pub(crate) struct ValidateClosure {
88    pub expr: ExprClosure,
89    pub err_type: Type,
90}
91
92fn parse_validate_closure(input: ParseStream) -> syn::Result<Option<ValidateClosure>> {
93    if !input.lookahead1().peek(kw::validate) {
94        return Ok(None);
95    }
96    input.parse::<kw::validate>()?;
97    let err_type: Type = {
98        let buf;
99        parenthesized!(buf in input);
100        buf.parse()?
101    };
102    Ok(Some(ValidateClosure {
103        expr: input.parse()?,
104        err_type,
105    }))
106}
107
108pub(crate) struct EnsureClosure {
109    pub expr: ExprClosure,
110}
111
112fn parse_ensure_closure(input: ParseStream) -> syn::Result<Option<EnsureClosure>> {
113    if !input.lookahead1().peek(kw::ensure) {
114        return Ok(None);
115    }
116    input.parse::<kw::ensure>()?;
117    Ok(Some(EnsureClosure {
118        expr: input.parse()?,
119    }))
120}
121
122mod kw {
123    syn::custom_keyword!(extend);
124    syn::custom_keyword!(adjust);
125    syn::custom_keyword!(ensure);
126    syn::custom_keyword!(validate);
127}