diff options
Diffstat (limited to 'validator_derive')
| -rw-r--r-- | validator_derive/Cargo.toml | 4 | ||||
| -rw-r--r-- | validator_derive/src/lib.rs | 45 | ||||
| -rw-r--r-- | validator_derive/tests/compile-fail/length/wrong_type.rs | 2 | ||||
| -rw-r--r-- | validator_derive/tests/run-pass/lifetime.rs | 19 | ||||
| -rw-r--r-- | validator_derive/tests/test_derive.rs | 12 |
5 files changed, 68 insertions, 14 deletions
diff --git a/validator_derive/Cargo.toml b/validator_derive/Cargo.toml index fc4a3be..3cbe9a8 100644 --- a/validator_derive/Cargo.toml +++ b/validator_derive/Cargo.toml @@ -24,5 +24,5 @@ regex = "0.2" lazy_static = "0.2" [dependencies.validator] -# path = "../validator" -version = "0.3.0" +path = "../validator" +# version = "0.3.0" diff --git a/validator_derive/src/lib.rs b/validator_derive/src/lib.rs index 68a4b2e..dafa49e 100644 --- a/validator_derive/src/lib.rs +++ b/validator_derive/src/lib.rs @@ -13,10 +13,14 @@ use quote::ToTokens; use validator::{Validator}; -static RANGE_TYPES: [&'static str; 12] = [ +static RANGE_TYPES: [&'static str; 24] = [ "usize", "u8", "u16", "u32", "u64", "isize", "i8", "i16", "i32", "i64", "f32", "f64", + + "Option<size>", "Option<8>", "Option<16>", "Option<32>", "Option<64>", + "Option<size>", "Option<8>", "Option<16>", "Option<32>", "Option<64>", + "Option<32>", "Option<64>", ]; #[derive(Debug)] @@ -59,7 +63,14 @@ fn expand_validation(ast: &syn::MacroInput) -> quote::Tokens { }; let (name, validators) = find_validators_for_field(field, &field_types); + let validator_param = if field_types.get(&field_ident.to_string()).unwrap().starts_with("&") { + quote!(self.#field_ident) + } else { + quote!(&self.#field_ident) + }; + for validator in &validators { + println!("field: {}, types: {:?}", field_ident, field_types); validations.push(match validator { &Validator::Length {min, max, equal} => { // Can't interpolate None @@ -73,7 +84,7 @@ fn expand_validation(ast: &syn::MacroInput) -> quote::Tokens { max: #max_tokens, equal: #equal_tokens }, - &self.#field_ident + #validator_param ) { errors.add(#name, "length"); } @@ -91,14 +102,14 @@ fn expand_validation(ast: &syn::MacroInput) -> quote::Tokens { }, &Validator::Email => { quote!( - if !::validator::validate_email(&self.#field_ident) { + if !::validator::validate_email(#validator_param) { errors.add(#name, "email"); } ) } &Validator::Url => { quote!( - if !::validator::validate_url(&self.#field_ident) { + if !::validator::validate_url(#validator_param) { errors.add(#name, "url"); } ) @@ -114,7 +125,7 @@ fn expand_validation(ast: &syn::MacroInput) -> quote::Tokens { &Validator::Custom(ref f) => { let fn_ident = syn::Ident::new(f.clone()); quote!( - match #fn_ident(&self.#field_ident) { + match #fn_ident(#validator_param) { ::std::option::Option::Some(s) => { errors.add(#name, &s); }, @@ -124,7 +135,7 @@ fn expand_validation(ast: &syn::MacroInput) -> quote::Tokens { }, &Validator::Contains(ref n) => { quote!( - if !::validator::validate_contains(&self.#field_ident, &#n) { + if !::validator::validate_contains(#validator_param, &#n) { errors.add(#name, "contains"); } ) @@ -132,7 +143,7 @@ fn expand_validation(ast: &syn::MacroInput) -> quote::Tokens { &Validator::Regex(ref re) => { let re_ident = syn::Ident::new(re.clone()); quote!( - if !#re_ident.is_match(&self.#field_ident) { + if !#re_ident.is_match(#validator_param) { errors.add(#name, "regex"); } ) @@ -171,8 +182,11 @@ fn expand_validation(ast: &syn::MacroInput) -> quote::Tokens { }; let ident = &ast.ident; + + // Helper is provided for handling complex generic types correctly and effortlessly + let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); let impl_ast = quote!( - impl Validate for #ident { + impl #impl_generics Validate for #ident #ty_generics #where_clause { fn validate(&self) -> ::std::result::Result<(), ::validator::Errors> { let mut errors = ::validator::Errors::new(); @@ -276,7 +290,6 @@ fn find_fields_type(fields: &Vec<syn::Field>) -> HashMap<String, String> { Some(ref s) => s.to_string(), None => unreachable!(), }; - let field_type = match field.ty { syn::Ty::Path(_, ref p) => { let mut tokens = quote::Tokens::new(); @@ -284,8 +297,18 @@ fn find_fields_type(fields: &Vec<syn::Field>) -> HashMap<String, String> { tokens.to_string().replace(' ', "") }, + syn::Ty::Rptr(ref l, ref p) => { + let mut tokens = quote::Tokens::new(); + p.ty.to_tokens(&mut tokens); + let mut name = tokens.to_string().replace(' ', ""); + if l.is_some() { + name.insert(0, '&') + } + name + }, _ => panic!("Type `{:?}` of field `{}` not supported", field.ty, field_name) }; + //println!("{:?}", field_type); types.insert(field_name, field_type); } @@ -474,9 +497,9 @@ fn find_validators_for_field(field: &syn::Field, field_types: &HashMap<String, S syn::MetaItem::List(ref name, ref meta_items) => { // Some sanity checking first if name == "length" { - if field_type != "String" && !field_type.starts_with("Vec<") { + if field_type != "String" && !field_type.starts_with("Vec<") && field_type != "&str" { error(&format!( - "Validator `length` can only be used on types `String` or `Vec` but found `{}`", + "Validator `length` can only be used on types `String`, `&str` or `Vec` but found `{}`", field_type )); } diff --git a/validator_derive/tests/compile-fail/length/wrong_type.rs b/validator_derive/tests/compile-fail/length/wrong_type.rs index e8a28ca..12dbb61 100644 --- a/validator_derive/tests/compile-fail/length/wrong_type.rs +++ b/validator_derive/tests/compile-fail/length/wrong_type.rs @@ -6,7 +6,7 @@ use validator::Validate; #[derive(Validate)] //~^ ERROR: custom derive attribute panicked -//~^^ HELP: Invalid attribute #[validate] on field `s`: Validator `length` can only be used on types `String` or `Vec` but found `usize` +//~^^ HELP: Invalid attribute #[validate] on field `s`: Validator `length` can only be used on types `String`, `&str` or `Vec` but found `usize` struct Test { #[validate(length())] s: usize, diff --git a/validator_derive/tests/run-pass/lifetime.rs b/validator_derive/tests/run-pass/lifetime.rs new file mode 100644 index 0000000..8547a1a --- /dev/null +++ b/validator_derive/tests/run-pass/lifetime.rs @@ -0,0 +1,19 @@ +#![feature(attr_literals)] + +#[macro_use] extern crate validator_derive; +extern crate validator; +use validator::Validate; + +#[derive(Validate)] +struct Test<'a> { + #[validate(length(min = 1))] + s: &'a str, + #[validate(length(min = 1, max = 2))] + s2: &'a str, + #[validate(length(equal = 1))] + s3: &'a str, + #[validate(length(max = 1))] + s4: &'a str, +} + +fn main() {} diff --git a/validator_derive/tests/test_derive.rs b/validator_derive/tests/test_derive.rs index 4e6c088..7ff542b 100644 --- a/validator_derive/tests/test_derive.rs +++ b/validator_derive/tests/test_derive.rs @@ -271,3 +271,15 @@ fn test_can_check_regex_validator() { let s2 = RegexStruct {name: "AL".to_string()}; assert!(s2.validate().is_err()); } + +// +//#[test] +//fn test_can_validate_option_fields() { +// #[derive(Debug, Validate)] +// struct PutStruct<'a> { +// #[validate(length(min = "1", max = "10"))] +// name: Option<&'a str>, +// } +// let s = PutStruct {name: Some("al")}; +// assert!(s.validate().is_ok()); +//} |
