aboutsummaryrefslogtreecommitdiffstats
path: root/validator_derive
diff options
context:
space:
mode:
authorVincent Prouillet2017-01-18 21:35:01 +0900
committerVincent Prouillet2017-01-19 13:38:47 +0900
commit1fd1b3d708a2737c2a678df8a37e719c29c754bc (patch)
tree67cb2b347ee2dab46bce64fdcfcb1f77a59e9a19 /validator_derive
parent8f54c9228d8cf8e2bede37ddc9958db7ce4c63a8 (diff)
downloadvalidator-1fd1b3d708a2737c2a678df8a37e719c29c754bc.tar.bz2
Make it work with lifetimes
Diffstat (limited to 'validator_derive')
-rw-r--r--validator_derive/Cargo.toml4
-rw-r--r--validator_derive/src/lib.rs45
-rw-r--r--validator_derive/tests/compile-fail/length/wrong_type.rs2
-rw-r--r--validator_derive/tests/run-pass/lifetime.rs19
-rw-r--r--validator_derive/tests/test_derive.rs12
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());
+//}