validators_derive/
lib.rs

1/*!
2# Validators Derive
3
4The provided crate offers a procedural macro for defining validators, including optional parameters. See the [`validators`](https://crates.io/crates/validators) crate.
5 */
6
7#![cfg_attr(docsrs, feature(doc_auto_cfg))]
8
9mod common;
10#[allow(unused)]
11mod panic;
12mod supported_validators;
13mod validator_handlers;
14
15use proc_macro::TokenStream;
16use syn::{
17    parse::{Parse, ParseStream},
18    parse_macro_input,
19    spanned::Spanned,
20    DeriveInput, Meta,
21};
22#[allow(unused)]
23use validator_handlers::ValidatorHandler;
24
25use crate::supported_validators::Validator;
26
27fn derive_input_handler(ast: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
28    let mut use_validator: Option<(Validator, Meta)> = None;
29
30    for attr in ast.attrs.iter() {
31        let path = attr.path();
32
33        if path.is_ident("validator") {
34            if let Meta::List(list) = &attr.meta {
35                let meta: Meta = list.parse_args()?;
36
37                let path = meta.path();
38
39                if let Some(validator) = Validator::from_path(path) {
40                    if use_validator.is_some() {
41                        return Err(panic::validator_only_one_at_a_time(path.span()));
42                    }
43
44                    use_validator = Some((validator, meta));
45                } else {
46                    return Err(panic::unsupported_validator(path));
47                }
48            } else {
49                return Err(panic::validator_format_incorrect(path.span()));
50            }
51        }
52    }
53
54    if let Some((validator, meta)) = use_validator {
55        match validator {
56            #[cfg(feature = "base32")]
57            Validator::base32 => {
58                return validator_handlers::base32::Base32Handler::meta_handler(ast, meta);
59            },
60            #[cfg(feature = "base32_decoded")]
61            Validator::base32_decoded => {
62                return validator_handlers::base32_decoded::Base32DecodedHandler::meta_handler(
63                    ast, meta,
64                );
65            },
66            #[cfg(feature = "base64")]
67            Validator::base64 => {
68                return validator_handlers::base64::Base64Handler::meta_handler(ast, meta);
69            },
70            #[cfg(feature = "base64_decoded")]
71            Validator::base64_decoded => {
72                return validator_handlers::base64_decoded::Base64DecodedHandler::meta_handler(
73                    ast, meta,
74                );
75            },
76            #[cfg(feature = "base64_url")]
77            Validator::base64_url => {
78                return validator_handlers::base64_url::Base64UrlHandler::meta_handler(ast, meta);
79            },
80            #[cfg(feature = "base64_url_decoded")]
81            Validator::base64_url_decoded => {
82                return validator_handlers::base64_url_decoded::Base64UrlDecodedHandler::meta_handler(
83                    ast, meta,
84                );
85            },
86            #[cfg(feature = "bit")]
87            Validator::bit => {
88                return validator_handlers::bit::BitHandler::meta_handler(ast, meta);
89            },
90            #[cfg(feature = "boolean")]
91            Validator::boolean => {
92                return validator_handlers::boolean::BooleanHandler::meta_handler(ast, meta);
93            },
94            #[cfg(feature = "byte")]
95            Validator::byte => {
96                return validator_handlers::byte::ByteHandler::meta_handler(ast, meta);
97            },
98            #[cfg(feature = "domain")]
99            Validator::domain => {
100                return validator_handlers::domain::DomainHandler::meta_handler(ast, meta);
101            },
102            #[cfg(feature = "email")]
103            Validator::email => {
104                return validator_handlers::email::EmailHandler::meta_handler(ast, meta);
105            },
106            #[cfg(feature = "host")]
107            Validator::host => {
108                return validator_handlers::host::HostHandler::meta_handler(ast, meta);
109            },
110            #[cfg(feature = "http_url")]
111            Validator::http_url => {
112                return validator_handlers::http_url::HttpUrlHandler::meta_handler(ast, meta);
113            },
114            #[cfg(feature = "http_ftp_url")]
115            Validator::http_ftp_url => {
116                return validator_handlers::http_ftp_url::HttpFtpUrlHandler::meta_handler(
117                    ast, meta,
118                );
119            },
120            #[cfg(feature = "ip")]
121            Validator::ip => {
122                return validator_handlers::ip::IpHandler::meta_handler(ast, meta);
123            },
124            #[cfg(feature = "ipv4")]
125            Validator::ipv4 => {
126                return validator_handlers::ipv4::Ipv4Handler::meta_handler(ast, meta);
127            },
128            #[cfg(feature = "ipv6")]
129            Validator::ipv6 => {
130                return validator_handlers::ipv6::Ipv6Handler::meta_handler(ast, meta);
131            },
132            #[cfg(feature = "json")]
133            Validator::json => {
134                return validator_handlers::json::JsonHandler::meta_handler(ast, meta);
135            },
136            #[cfg(feature = "length")]
137            Validator::length => {
138                return validator_handlers::length::LengthHandler::meta_handler(ast, meta);
139            },
140            #[cfg(feature = "line")]
141            Validator::line => {
142                return validator_handlers::line::LineHandler::meta_handler(ast, meta);
143            },
144            #[cfg(feature = "mac_address")]
145            Validator::mac_address => {
146                return validator_handlers::mac_address::MacAddressHandler::meta_handler(ast, meta);
147            },
148            #[cfg(feature = "number")]
149            Validator::number => {
150                return validator_handlers::number::NumberHandler::meta_handler(ast, meta);
151            },
152            #[cfg(feature = "phone")]
153            Validator::phone => {
154                return validator_handlers::phone::PhoneHandler::meta_handler(ast, meta);
155            },
156            #[cfg(feature = "regex")]
157            Validator::regex => {
158                return validator_handlers::regex::RegexHandler::meta_handler(ast, meta);
159            },
160            #[cfg(feature = "semver")]
161            Validator::semver => {
162                return validator_handlers::semver::SemverHandler::meta_handler(ast, meta);
163            },
164            #[cfg(feature = "semver_req")]
165            Validator::semver_req => {
166                return validator_handlers::semver_req::SemverReqHandler::meta_handler(ast, meta);
167            },
168            #[cfg(feature = "signed_integer")]
169            Validator::signed_integer => {
170                return validator_handlers::signed_integer::SignedIntegerHandler::meta_handler(
171                    ast, meta,
172                );
173            },
174            #[cfg(feature = "text")]
175            Validator::text => {
176                return validator_handlers::text::TextHandler::meta_handler(ast, meta);
177            },
178            #[cfg(feature = "unsigned_integer")]
179            Validator::unsigned_integer => {
180                return validator_handlers::unsigned_integer::UnsignedIntegerHandler::meta_handler(
181                    ast, meta,
182                );
183            },
184            #[cfg(feature = "url")]
185            Validator::url => {
186                return validator_handlers::url::UrlHandler::meta_handler(ast, meta);
187            },
188            #[cfg(feature = "uuid")]
189            Validator::uuid => {
190                return validator_handlers::uuid::UuidHandler::meta_handler(ast, meta);
191            },
192            Validator::_Nothing => {
193                // avoid unused warnings
194                let _ = meta;
195                unreachable!();
196            },
197        }
198    }
199
200    Err(panic::derive_attribute_not_set_up_yet())
201}
202
203#[proc_macro_derive(Validator, attributes(validator))]
204pub fn validator_derive(input: TokenStream) -> TokenStream {
205    struct MyDeriveInput(proc_macro2::TokenStream);
206
207    impl Parse for MyDeriveInput {
208        #[inline]
209        fn parse(input: ParseStream) -> syn::Result<Self> {
210            let token_stream = derive_input_handler(input.parse::<DeriveInput>()?)?;
211
212            Ok(Self(token_stream))
213        }
214    }
215
216    // Parse the token stream
217    let derive_input = parse_macro_input!(input as MyDeriveInput);
218
219    derive_input.0.into()
220}