Skip to main content

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