verify_macros/
lib.rs

1use proc_macro2::TokenStream;
2use proc_macro_error::{abort, abort_call_site, emit_error, proc_macro_error};
3use quote::quote;
4use syn::{
5    parenthesized,
6    parse::{Parse, ParseStream},
7    parse_macro_input, token, Data, Ident, LitStr, Token,
8};
9
10#[proc_macro_error]
11#[proc_macro_derive(Verify, attributes(verify))]
12pub fn derive_verify(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
13    let input = parse_macro_input!(input as syn::DeriveInput);
14
15    let mut options = VerifyOptions::default();
16
17    for a in &input.attrs {
18        if a.path.is_ident("verify") {
19            let tokens = a.tokens.clone().into();
20            options.merge(parse_macro_input!(tokens as VerifyOptions));
21        }
22    }
23
24    match &input.data {
25        Data::Struct(_) => Verify::new(input, options).derive().into(),
26        Data::Enum(_) => Verify::new(input, options).derive().into(),
27        Data::Union(u) => {
28            abort!(u.union_token, "unions are not supported by Verify");
29        }
30    }
31}
32
33#[derive(Default)]
34struct VerifyOptions {
35    verifier: Option<Ident>,
36    verifier_name: Option<(Ident, TokenStream)>,
37    verifier_create: Option<(Ident, TokenStream)>,
38    verifier_error: Option<(Ident, TokenStream)>,
39
40    is_serde: Option<Ident>,
41    serde_spans: Option<(Ident, TokenStream)>,
42
43    is_schemars: Option<Ident>,
44}
45
46impl VerifyOptions {
47    fn merge(&mut self, other: VerifyOptions) {
48        if let Some(v) = other.verifier {
49            if let Some(existing_v) = &self.verifier {
50                emit_error!(existing_v, "{} defined here", existing_v);
51                abort!(v, r#"duplicate keys "{}""#, v);
52            }
53
54            self.verifier = v.into();
55        }
56
57        if let Some(v) = other.verifier_name {
58            if let Some(existing_v) = &self.verifier_name {
59                emit_error!(existing_v.0, "{} defined here", existing_v.0);
60                abort!(v.0, r#"duplicate keys "{}""#, v.0);
61            }
62
63            self.verifier_name = v.into();
64        }
65
66        if let Some(v) = other.verifier_create {
67            if let Some(existing_v) = &self.verifier_create {
68                emit_error!(existing_v.0, "{} defined here", existing_v.0);
69                abort!(v.0, r#"duplicate keys "{}""#, v.0);
70            }
71
72            self.verifier_create = v.into();
73        }
74
75        if let Some(v) = other.verifier_error {
76            if let Some(existing_v) = &self.verifier_error {
77                emit_error!(existing_v.0, "{} defined here", existing_v.0);
78                abort!(v.0, r#"duplicate keys "{}""#, v.0);
79            }
80
81            self.verifier_error = v.into();
82        }
83
84        if let Some(v) = other.is_serde {
85            if let Some(existing_v) = &self.is_serde {
86                emit_error!(existing_v, "{} defined here", existing_v);
87                abort!(v, r#"duplicate keys "{}""#, v);
88            }
89
90            self.is_serde = v.into();
91        }
92
93        if let Some(v) = other.serde_spans {
94            if let Some(existing_v) = &self.serde_spans {
95                emit_error!(existing_v.0, "{} defined here", existing_v.0);
96                abort!(v.0, r#"duplicate keys "{}""#, v.0);
97            }
98
99            self.serde_spans = v.into();
100        }
101
102        if let Some(v) = other.is_schemars {
103            if let Some(existing_v) = &self.is_schemars {
104                emit_error!(existing_v, "{} defined here", existing_v);
105                abort!(v, r#"duplicate keys "{}""#, v);
106            }
107
108            self.is_schemars = v.into();
109        }
110    }
111
112    fn parse_serde_options(&mut self, content: ParseStream) -> syn::Result<()> {
113        if content.is_empty() {
114            return Ok(());
115        }
116
117        let serde_id: Ident = content.parse()?;
118
119        if serde_id == "spans" {
120            content.parse::<Token![=]>()?;
121            let s = content.parse::<LitStr>()?;
122            let ts: TokenStream = s.parse()?;
123            self.serde_spans = Some((serde_id, ts));
124        } else {
125            abort!(serde_id, r#"unknown serde option "{}""#, serde_id);
126        }
127
128        Ok(())
129    }
130
131    fn parse_verifier_options(&mut self, content: ParseStream) -> syn::Result<()> {
132        loop {
133            if content.is_empty() {
134                return Ok(());
135            }
136
137            let id: Ident = content.parse()?;
138
139            if id == "name" {
140                content.parse::<Token![=]>()?;
141                let s = content.parse::<LitStr>()?;
142                let ts: TokenStream = s.parse()?;
143                self.verifier_name = Some((id, ts));
144            } else if id == "error" {
145                content.parse::<Token![=]>()?;
146                let s = content.parse::<LitStr>()?;
147                let ts: TokenStream = s.parse()?;
148                self.verifier_error = Some((id, ts));
149            } else if id == "create" {
150                content.parse::<Token![=]>()?;
151                let s = content.parse::<LitStr>()?;
152                let ts: TokenStream = s.parse()?;
153                self.verifier_create = Some((id, ts));
154            } else {
155                abort!(id, r#"unknown verifier option "{}""#, id);
156            }
157
158            if content.peek(Token![,]) {
159                content.parse::<Token!(,)>()?;
160            }
161        }
162    }
163
164    fn parse_option(&mut self, content: ParseStream) -> syn::Result<()> {
165        let id = content.parse::<Ident>()?;
166
167        if id == "serde" {
168            self.is_serde = Some(id);
169            if content.peek(token::Paren) {
170                let serde_content;
171                parenthesized!(serde_content in content);
172                self.parse_serde_options(&serde_content)?;
173            }
174
175            return Ok(());
176        }
177
178        if id == "verifier" {
179            self.verifier = id.clone().into();
180            if content.peek(token::Paren) {
181                let verifier_content;
182                parenthesized!(verifier_content in content);
183                self.parse_verifier_options(&verifier_content)?;
184            } else {
185                content.parse::<Token![=]>()?;
186                let s = content.parse::<LitStr>()?;
187                let ts: TokenStream = s.parse()?;
188                self.verifier_name = Some((id, ts));
189            }
190
191            return Ok(());
192        }
193
194        if id == "schemars" {
195            self.is_schemars = Some(id);
196            return Ok(());
197        }
198
199        abort!(id, r#"unknown option "{}""#, id);
200    }
201}
202
203impl Parse for VerifyOptions {
204    fn parse(input: ParseStream) -> syn::Result<Self> {
205        let mut opts = VerifyOptions::default();
206
207        if !input.peek(token::Paren) {
208            return Ok(opts);
209        }
210        let content;
211        parenthesized!(content in input);
212        loop {
213            if content.is_empty() {
214                break;
215            }
216
217            opts.parse_option(&content)?;
218
219            if content.peek(Token![,]) {
220                content.parse::<Token![,]>()?;
221            }
222        }
223
224        Ok(opts)
225    }
226}
227
228struct Verify {
229    input: syn::DeriveInput,
230    options: VerifyOptions,
231}
232
233impl Verify {
234    fn new(input: syn::DeriveInput, options: VerifyOptions) -> Self {
235        Self { input, options }
236    }
237
238    fn check_options(&self) {
239        if let Some(is_schemars) = &self.options.is_schemars {
240            if self.options.is_serde.is_none() {
241                abort!(
242                    is_schemars,
243                    r#"Serde is required for Schemars, use the "serde" option to enable it"#
244                );
245            }
246        }
247    }
248
249    fn derive(self) -> TokenStream {
250        self.check_options();
251
252        if self.options.is_serde.is_some() {
253            return self.derive_serde();
254        }
255
256        let ident = self.input.ident;
257        let (impl_gen, ty_gen, where_gen) = self.input.generics.split_for_impl();
258
259        let verifier_name = self
260            .options
261            .verifier_name
262            .unwrap_or_else(|| abort_call_site!("verifier name is required"))
263            .1;
264
265        let verifier_error = match self.options.verifier_error {
266            Some(e) => e.1,
267            None => {
268                quote! {
269                    <#verifier_name as ::verify::Verifier<<Self as ::verify::span::Spanned>::Span>>::Error
270                }
271            }
272        };
273
274        let verifier_create = match self.options.verifier_create {
275            Some(e) => e.1,
276            None => {
277                quote! {
278                    #verifier_name::default()
279                }
280            }
281        };
282
283        quote! {
284            impl#impl_gen ::verify::Verify for #ident#ty_gen #where_gen {
285                type Error = #verifier_error;
286
287                fn verify(&self) -> Result<(), Self::Error> {
288                    let __v = #verifier_create;
289                    <#verifier_name as ::verify::Verifier<<Self as ::verify::span::Spanned>::Span>>::verify_value(
290                        &__v,
291                        self,
292                    )
293                }
294            }
295        }
296    }
297
298    fn derive_serde(self) -> TokenStream {
299        if self.options.is_schemars.is_some() {
300            return self.derive_schemars();
301        }
302
303        let ident = self.input.ident;
304        let (impl_gen, ty_gen, where_gen) = self.input.generics.split_for_impl();
305
306        let spans = match self.options.serde_spans {
307            Some((_, s)) => s,
308            None => {
309                quote! {::verify::serde::KeySpans}
310            }
311        };
312
313        let verifier_name = self
314            .options
315            .verifier_name
316            .unwrap_or_else(|| abort_call_site!("verifier name is required"))
317            .1;
318
319        let verifier_error = match self.options.verifier_error {
320            Some(e) => e.1,
321            None => {
322                quote! {
323                    <#verifier_name as ::verify::Verifier<<#spans as ::verify::serde::Spans>::Span>>::Error
324                }
325            }
326        };
327
328        let verifier_create = match self.options.verifier_create {
329            Some(e) => e.1,
330            None => {
331                quote! {
332                    #verifier_name::default()
333                }
334            }
335        };
336
337        quote! {
338            impl#impl_gen ::verify::Verify for #ident#ty_gen #where_gen {
339                type Error = #verifier_error;
340
341                fn verify(&self) -> Result<(), Self::Error> {
342                    let __v = #verifier_create;
343                    <#verifier_name as ::verify::Verifier<<#spans as ::verify::serde::Spans>::Span>>::verify_value(
344                        &__v,
345                        &::verify::serde::Spanned::new(self, #spans::default()),
346                    )
347                }
348            }
349        }
350    }
351
352    fn derive_schemars(self) -> TokenStream {
353        let ident = self.input.ident;
354        let (impl_gen, ty_gen, where_gen) = self.input.generics.split_for_impl();
355
356        let spans = match self.options.serde_spans {
357            Some((_, s)) => s,
358            None => {
359                quote! {::verify::serde::KeySpans}
360            }
361        };
362
363        if let Some(v) = self.options.verifier {
364            abort!(v, "verifier option is not supported with Schemars");
365        }
366
367        if let Some(v) = self.options.verifier {
368            abort!(v, "verifier option is not supported with Schemars");
369        }
370
371        let verifier_error = quote! {
372            ::verify::schemars::errors::Errors<<#spans as ::verify::serde::Spans>::Span>
373        };
374
375        quote! {
376            impl#impl_gen ::verify::Verify for #ident#ty_gen #where_gen {
377                type Error = #verifier_error;
378
379                fn verify(&self) -> Result<(), Self::Error> {
380                    let __root = schemars::schema_for!(Self);
381
382                    <schemars::schema::RootSchema as ::verify::Verifier<_>>::verify_value(
383                        &__root,
384                        &::verify::serde::Spanned::new(self, #spans::default()),
385                    )
386                }
387            }
388        }
389    }
390}