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 let attrs = input.call(Attribute::parse_outer)?;
19
20 let vis: Visibility = input.parse()?;
22 let name: Ident = input.parse()?;
23 input.parse::<Token![:]>()?;
24 let inner_type: Type = input.parse()?;
25
26 let extend_bound = parse_extend_bound(input)?;
28
29 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}