1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*!
# Validators Derive

This crate provides a procedural macro to define validators with optional parameters. See the [`validators`](https://crates.io/crates/validators) crate.
 */

#![cfg_attr(not(feature = "std"), no_std)]

extern crate alloc;

#[macro_use]
extern crate enum_ordinalize;

#[allow(unused_imports)]
#[macro_use]
extern crate educe;

mod panic;
mod support_validators;
mod syn_validator_options;
mod type_enum;
mod validator_handlers;

use alloc::string::ToString;

use proc_macro::TokenStream;
use quote::ToTokens;
use support_validators::Validator;
use syn::{DeriveInput, Meta, NestedMeta};
#[allow(unused_imports)]
use syn_validator_options::*;
use type_enum::*;
use validator_handlers::*;
#[allow(unused_imports)]
use validators_options::*;

fn derive_input_handler(ast: DeriveInput) -> TokenStream {
    for attr in ast.attrs.iter() {
        if let Some(attr_meta_name) = attr.path.get_ident() {
            if attr_meta_name == "validator" {
                let attr_meta = attr.parse_meta().unwrap();

                match attr_meta {
                    Meta::List(list) => {
                        if list.nested.len() == 1 {
                            let p = list.nested.into_iter().next().unwrap();

                            match p {
                                NestedMeta::Meta(meta) => {
                                    let meta_name = meta.path().into_token_stream().to_string();

                                    match Validator::from_str(meta_name) {
                                        #[cfg(feature = "base32")]
                                        Validator::base32 => {
                                            return base32::base32_handler(ast, meta)
                                        },
                                        #[cfg(feature = "base32_decoded")]
                                        Validator::base32_decoded => {
                                            return base32_decoded::base32_decoded_handler(
                                                ast, meta,
                                            )
                                        },
                                        #[cfg(feature = "base64")]
                                        Validator::base64 => {
                                            return base64::base64_handler(ast, meta)
                                        },
                                        #[cfg(feature = "base64_decoded")]
                                        Validator::base64_decoded => {
                                            return base64_decoded::base64_decoded_handler(
                                                ast, meta,
                                            )
                                        },
                                        #[cfg(feature = "base64_url")]
                                        Validator::base64_url => {
                                            return base64_url::base64_url_handler(ast, meta)
                                        },
                                        #[cfg(feature = "base64_url_decoded")]
                                        Validator::base64_url_decoded => {
                                            return base64_url_decoded::base64_url_decoded_handler(
                                                ast, meta,
                                            )
                                        },
                                        #[cfg(feature = "boolean")]
                                        Validator::boolean => {
                                            return boolean::boolean_handler(ast, meta)
                                        },
                                        #[cfg(feature = "domain")]
                                        Validator::domain => {
                                            return domain::domain_handler(ast, meta)
                                        },
                                        #[cfg(feature = "email")]
                                        Validator::email => return email::email_handler(ast, meta),
                                        #[cfg(feature = "host")]
                                        Validator::host => return host::host_handler(ast, meta),
                                        #[cfg(feature = "http_url")]
                                        Validator::http_url => {
                                            return http_url::http_url_handler(ast, meta)
                                        },
                                        #[cfg(feature = "http_ftp_url")]
                                        Validator::http_ftp_url => {
                                            return http_ftp_url::http_ftp_url_handler(ast, meta)
                                        },
                                        #[cfg(feature = "ip")]
                                        Validator::ip => return ip::ip_handler(ast, meta),
                                        #[cfg(feature = "ipv4")]
                                        Validator::ipv4 => return ipv4::ipv4_handler(ast, meta),
                                        #[cfg(feature = "ipv6")]
                                        Validator::ipv6 => return ipv6::ipv6_handler(ast, meta),
                                        #[cfg(feature = "json")]
                                        Validator::json => return json::json_handler(ast, meta),
                                        #[cfg(feature = "length")]
                                        Validator::length => {
                                            return length::length_handler(ast, meta)
                                        },
                                        #[cfg(feature = "line")]
                                        Validator::line => return line::line_handler(ast, meta),
                                        #[cfg(feature = "mac_address")]
                                        Validator::mac_address => {
                                            return mac_address::mac_address_handler(ast, meta)
                                        },
                                        #[cfg(feature = "number")]
                                        Validator::number => {
                                            return number::number_handler(ast, meta)
                                        },
                                        #[cfg(feature = "phone")]
                                        Validator::phone => return phone::phone_handler(ast, meta),
                                        #[cfg(feature = "regex")]
                                        Validator::regex => return regex::regex_handler(ast, meta),
                                        #[cfg(feature = "semver")]
                                        Validator::semver => {
                                            return semver::semver_handler(ast, meta)
                                        },
                                        #[cfg(feature = "semver_req")]
                                        Validator::semver_req => {
                                            return semver_req::semver_req_handler(ast, meta)
                                        },
                                        #[cfg(feature = "signed_integer")]
                                        Validator::signed_integer => {
                                            return signed_integer::signed_integer_handler(
                                                ast, meta,
                                            )
                                        },
                                        #[cfg(feature = "text")]
                                        Validator::text => return text::text_handler(ast, meta),
                                        #[cfg(feature = "unsigned_integer")]
                                        Validator::unsigned_integer => {
                                            return unsigned_integer::unsigned_integer_handler(
                                                ast, meta,
                                            )
                                        },
                                        #[cfg(feature = "url")]
                                        Validator::url => return url::url_handler(ast, meta),
                                        #[cfg(feature = "uuid")]
                                        Validator::uuid => return uuid::uuid_handler(ast, meta),
                                    }
                                },
                                NestedMeta::Lit(_) => panic::validator_format_incorrect(),
                            }
                        } else {
                            panic::validator_format_incorrect()
                        }
                    },
                    _ => panic::validator_format_incorrect(),
                }
            }
        }
    }

    panic::derive_attribute_not_set_up_yet("Validator")
}

#[proc_macro_derive(Validator, attributes(validator))]
pub fn validator_derive(input: TokenStream) -> TokenStream {
    derive_input_handler(syn::parse(input).unwrap())
}