diff options
| author | Vincent Prouillet | 2017-01-18 22:43:34 +0900 | 
|---|---|---|
| committer | Vincent Prouillet | 2017-01-19 13:38:47 +0900 | 
| commit | 696e4273173033a6b1d488416c5433d9c49eb8e9 (patch) | |
| tree | 8c6e1776e627412f16d1116a732b23561c819a6f /validator_derive/src | |
| parent | 1fd1b3d708a2737c2a678df8a37e719c29c754bc (diff) | |
| download | validator-696e4273173033a6b1d488416c5433d9c49eb8e9.tar.bz2 | |
Validator works for Option<&
Diffstat (limited to 'validator_derive/src')
| -rw-r--r-- | validator_derive/src/lib.rs | 219 | 
1 files changed, 162 insertions, 57 deletions
diff --git a/validator_derive/src/lib.rs b/validator_derive/src/lib.rs index dafa49e..177f315 100644 --- a/validator_derive/src/lib.rs +++ b/validator_derive/src/lib.rs @@ -18,8 +18,8 @@ static RANGE_TYPES: [&'static str; 24] = [      "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<usize>", "Option<8>", "Option<16>", "Option<32>", "Option<64>", +    "Option<isize>", "Option<8>", "Option<16>", "Option<32>", "Option<64>",      "Option<32>", "Option<64>",  ]; @@ -63,56 +63,117 @@ 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("&") { +        let field_name = field_types.get(&field_ident.to_string()).unwrap(); +        // Don't put a & in front a pointer +        let validator_param = if field_name.starts_with("&") {            quote!(self.#field_ident)          } else {            quote!(&self.#field_ident)          }; +        // same but for the ident used in a if let block +        let optional_validator_param = if field_name.starts_with("Option<&") { +          quote!(#field_ident) +        } else { +          quote!(&#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                      let min_tokens = option_u64_to_tokens(min);                      let max_tokens = option_u64_to_tokens(max);                      let equal_tokens = option_u64_to_tokens(equal); -                    quote!( -                        if !::validator::validate_length( -                            ::validator::Validator::Length { -                                min: #min_tokens, -                                max: #max_tokens, -                                equal: #equal_tokens -                            }, -                            #validator_param -                        ) { -                            errors.add(#name, "length"); -                        } -                    ) +                    // wrap in if-let if we have an option +                    if field_name.starts_with("Option<") { +                        quote!( +                            if let Some(#field_ident) = self.#field_ident { +                                if !::validator::validate_length( +                                    ::validator::Validator::Length { +                                        min: #min_tokens, +                                        max: #max_tokens, +                                        equal: #equal_tokens +                                    }, +                                    #field_ident +                                ) { +                                    errors.add(#name, "length"); +                                } +                            } +                        ) +                    } else { +                        quote!( +                            if !::validator::validate_length( +                                ::validator::Validator::Length { +                                    min: #min_tokens, +                                    max: #max_tokens, +                                    equal: #equal_tokens +                                }, +                                #validator_param +                            ) { +                                errors.add(#name, "length"); +                            } +                        ) +                    }                  },                  &Validator::Range {min, max} => { -                    quote!( -                        if !::validator::validate_range( -                            ::validator::Validator::Range {min: #min, max: #max}, -                            self.#field_ident as f64 -                        ) { -                            errors.add(#name, "range"); -                        } -                    ) +                    // wrap in if-let if we have an option +                    if field_name.starts_with("Option<") { +                        quote!( +                            if let Some(#field_ident) = self.#field_ident { +                                if !::validator::validate_range( +                                    ::validator::Validator::Range {min: #min, max: #max}, +                                    #field_ident as f64 +                                ) { +                                    errors.add(#name, "range"); +                                } +                            } +                        ) +                    } else { +                        quote!( +                            if !::validator::validate_range( +                                ::validator::Validator::Range {min: #min, max: #max}, +                                self.#field_ident as f64 +                            ) { +                                errors.add(#name, "range"); +                            } +                        ) +                    }                  },                  &Validator::Email => { -                    quote!( -                        if !::validator::validate_email(#validator_param) { -                            errors.add(#name, "email"); -                        } -                    ) +                    // wrap in if-let if we have an option +                    if field_name.starts_with("Option<") { +                        quote!( +                            if let Some(#field_ident) = self.#field_ident { +                                if !::validator::validate_email(#field_ident) { +                                    errors.add(#name, "email"); +                                } +                            } +                        ) +                    } else { +                        quote!( +                            if !::validator::validate_email(#validator_param) { +                                errors.add(#name, "email"); +                            } +                        ) +                    }                  }                  &Validator::Url => { -                    quote!( -                        if !::validator::validate_url(#validator_param) { -                            errors.add(#name, "url"); -                        } -                    ) +                    // wrap in if-let if we have an option +                    if field_name.starts_with("Option<") { +                        quote!( +                            if let Some(#field_ident) = self.#field_ident { +                                if !::validator::validate_url(#field_ident) { +                                    errors.add(#name, "url"); +                                } +                            } +                        ) +                    } else { +                        quote!( +                            if !::validator::validate_url(#validator_param) { +                                errors.add(#name, "url"); +                            } +                        ) +                    }                  },                  &Validator::MustMatch(ref f) => {                      let other_ident = syn::Ident::new(f.clone()); @@ -124,29 +185,65 @@ fn expand_validation(ast: &syn::MacroInput) -> quote::Tokens {                  },                  &Validator::Custom(ref f) => {                      let fn_ident = syn::Ident::new(f.clone()); -                    quote!( -                        match #fn_ident(#validator_param) { -                            ::std::option::Option::Some(s) => { -                                errors.add(#name, &s); -                            }, -                            ::std::option::Option::None => (), -                        }; -                    ) +                    // wrap in if-let if we have an option +                    if field_name.starts_with("Option<") { +                        quote!( +                            if let Some(#field_ident) = self.#field_ident { +                                match #fn_ident(#field_ident) { +                                    ::std::option::Option::Some(s) => { +                                        errors.add(#name, &s); +                                    }, +                                    ::std::option::Option::None => (), +                                }; +                            } +                        ) +                    } else { +                        quote!( +                            match #fn_ident(#validator_param) { +                                ::std::option::Option::Some(s) => { +                                    errors.add(#name, &s); +                                }, +                                ::std::option::Option::None => (), +                            }; +                        ) +                    }                  },                  &Validator::Contains(ref n) => { -                    quote!( -                        if !::validator::validate_contains(#validator_param, &#n) { -                            errors.add(#name, "contains"); -                        } -                    ) +                    // wrap in if-let if we have an option +                    if field_name.starts_with("Option<") { +                        quote!( +                            if let Some(#field_ident) = self.#field_ident { +                                if !::validator::validate_contains(#optional_validator_param, &#n) { +                                    errors.add(#name, "contains"); +                                } +                            } +                        ) +                    } else { +                        quote!( +                            if !::validator::validate_contains(#validator_param, &#n) { +                                errors.add(#name, "contains"); +                            } +                        ) +                    }                  },                  &Validator::Regex(ref re) => {                      let re_ident = syn::Ident::new(re.clone()); -                    quote!( -                        if !#re_ident.is_match(#validator_param) { -                            errors.add(#name, "regex"); -                        } -                    ) +                    // wrap in if-let if we have an option +                    if field_name.starts_with("Option<") { +                        quote!( +                            if let Some(#field_ident) = self.#field_ident { +                                if !#re_ident.is_match(#field_ident) { +                                    errors.add(#name, "regex"); +                                } +                            } +                        ) +                    } else { +                        quote!( +                            if !#re_ident.is_match(#validator_param) { +                                errors.add(#name, "regex"); +                            } +                        ) +                    }                  },              });          } @@ -440,14 +537,18 @@ fn find_validators_for_field(field: &syn::Field, field_types: &HashMap<String, S                              // email, url                              syn::MetaItem::Word(ref name) => match name.to_string().as_ref() {                                  "email" => { -                                    if field_type != "String" { -                                        panic!("`email` validator can only be used on String"); +                                    if field_type != "String" +                                        && field_type != "&str" +                                        && !(field_type.starts_with("Option<") && field_type.ends_with("str>")) { +                                        panic!("`email` validator can only be used on String or &str");                                      }                                      validators.push(Validator::Email);                                  },                                  "url" => { -                                    if field_type != "String" { -                                        panic!("`url` validator can only be used on String"); +                                    if field_type != "String" +                                        && field_type != "&str" +                                        && !(field_type.starts_with("Option<") && field_type.ends_with("str>")) { +                                        panic!("`url` validator can only be used on String or &str");                                      }                                      validators.push(Validator::Url);                                  }, @@ -497,7 +598,11 @@ 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<") && field_type != "&str" { +                                    if field_type != "String" +                                        && !field_type.starts_with("Vec<") +                                        // a bit ugly +                                        && !(field_type.starts_with("Option<") && field_type.ends_with("str>")) +                                        && field_type != "&str" {                                          error(&format!(                                              "Validator `length` can only be used on types `String`, `&str` or `Vec` but found `{}`",                                              field_type  | 
