aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--validator/src/validation/mod.rs4
-rw-r--r--validator/src/validation/range.rs44
-rw-r--r--validator_derive/src/lit.rs7
-rw-r--r--validator_derive/src/quoting.rs21
-rw-r--r--validator_derive/src/validation.rs43
-rw-r--r--validator_derive/tests/compile-fail/range/missing_arg.rs15
-rw-r--r--validator_derive/tests/compile-fail/range/no_args.rs2
-rw-r--r--validator_derive/tests/run-pass/range.rs4
9 files changed, 93 insertions, 51 deletions
diff --git a/README.md b/README.md
index 145c74c..09d2982 100644
--- a/README.md
+++ b/README.md
@@ -179,14 +179,16 @@ Examples:
```
### range
-Tests whether a number is in the given range. `range` takes 2 number arguments: `min` and `max`.
+Tests whether a number is in the given range. `range` takes between 1 and 2 number arguments: `min` and `max`.
Examples:
```rust
#[validate(range(min = "1", max = "10"))]
+#[validate(range(min = "1"))]
#[validate(range(min = "1", max = "10.8"))]
#[validate(range(min = "1.1", max = "10.8"))]
+#[validate(range(max = "10.8"))]
```
### must_match
diff --git a/validator/src/validation/mod.rs b/validator/src/validation/mod.rs
index 065b27e..95d9b79 100644
--- a/validator/src/validation/mod.rs
+++ b/validator/src/validation/mod.rs
@@ -27,8 +27,8 @@ pub enum Validator {
// No implementation in this crate, it's all in validator_derive
Regex(String),
Range {
- min: f64,
- max: f64,
+ min: Option<f64>,
+ max: Option<f64>,
},
// Any value that impl HasLen can be validated with Length
Length {
diff --git a/validator/src/validation/range.rs b/validator/src/validation/range.rs
index c643762..a89f707 100644
--- a/validator/src/validation/range.rs
+++ b/validator/src/validation/range.rs
@@ -5,7 +5,21 @@ use validation::Validator;
/// TODO: see if can be generic over the number type
pub fn validate_range(range: Validator, val: f64) -> bool {
match range {
- Validator::Range { min, max } => val >= min && val <= max,
+ Validator::Range { min, max } => {
+ if let Some(m) = min {
+ if val < m {
+ return false;
+ }
+ }
+
+ if let Some(m) = max {
+ if val > m {
+ return false;
+ }
+ }
+
+ true
+ }
_ => unreachable!(),
}
}
@@ -16,13 +30,37 @@ mod tests {
#[test]
fn test_validate_range_ok() {
- let validator = Validator::Range { min: 0.0, max: 10.0 };
+ let validator = Validator::Range { min: Some(0.0), max: Some(10.0) };
assert_eq!(validate_range(validator, 1 as f64), true);
}
#[test]
fn test_validate_range_fail() {
- let validator = Validator::Range { min: 0.0, max: 10.0 };
+ let validator = Validator::Range { min: Some(0.0), max: Some(10.0) };
assert_eq!(validate_range(validator, 20 as f64), false);
}
+
+ #[test]
+ fn test_validate_range_min_only_valid() {
+ let validator = Validator::Range { min: Some(10.0), max: None };
+ assert_eq!(validate_range(validator, 10.0), true);
+ }
+
+ #[test]
+ fn test_validate_range_min_only_invalid() {
+ let validator = Validator::Range { min: Some(10.0), max: None };
+ assert_eq!(validate_range(validator, 9.0), false);
+ }
+
+ #[test]
+ fn test_validate_range_max_only_valid() {
+ let validator = Validator::Range { min: None, max: Some(10.0) };
+ assert_eq!(validate_range(validator, 10.0), true);
+ }
+
+ #[test]
+ fn test_validate_range_max_only_invalid() {
+ let validator = Validator::Range { min: None, max: Some(10.0) };
+ assert_eq!(validate_range(validator, 11.0), false);
+ }
}
diff --git a/validator_derive/src/lit.rs b/validator_derive/src/lit.rs
index 14e3f56..de0e21e 100644
--- a/validator_derive/src/lit.rs
+++ b/validator_derive/src/lit.rs
@@ -46,3 +46,10 @@ pub fn option_u64_to_tokens(opt: Option<u64>) -> proc_macro2::TokenStream {
None => quote!(::std::option::Option::None),
}
}
+
+pub fn option_f64_to_tokens(opt: Option<f64>) -> proc_macro2::TokenStream {
+ match opt {
+ Some(ref t) => quote!(::std::option::Option::Some(#t)),
+ None => quote!(::std::option::Option::None),
+ }
+}
diff --git a/validator_derive/src/quoting.rs b/validator_derive/src/quoting.rs
index f94d8fc..fa97623 100644
--- a/validator_derive/src/quoting.rs
+++ b/validator_derive/src/quoting.rs
@@ -3,7 +3,7 @@ use syn;
use validator::Validator;
use asserts::{COW_TYPE, NUMBER_TYPES};
-use lit::option_u64_to_tokens;
+use lit::{option_f64_to_tokens, option_u64_to_tokens};
use validation::{FieldValidation, SchemaValidation};
/// Pass around all the information needed for creating a validation
@@ -183,12 +183,25 @@ pub fn quote_range_validation(
let quoted_ident = field_quoter.quote_validator_param();
if let Validator::Range { min, max } = validation.validator {
+ // Can't interpolate None
+ let min_tokens = option_f64_to_tokens(min);
+ let max_tokens = option_f64_to_tokens(max);
+
+ let min_err_param_quoted = if let Some(v) = min {
+ quote!(err.add_param(::std::borrow::Cow::from("min"), &#v);)
+ } else {
+ quote!()
+ };
+ let max_err_param_quoted = if let Some(v) = max {
+ quote!(err.add_param(::std::borrow::Cow::from("max"), &#v);)
+ } else {
+ quote!()
+ };
+
let quoted_error = quote_error(&validation);
- let min_err_param_quoted = quote!(err.add_param(::std::borrow::Cow::from("min"), &#min););
- let max_err_param_quoted = quote!(err.add_param(::std::borrow::Cow::from("max"), &#max););
let quoted = quote!(
if !::validator::validate_range(
- ::validator::Validator::Range {min: #min, max: #max},
+ ::validator::Validator::Range {min: #min_tokens, max: #max_tokens},
#quoted_ident as f64
) {
#quoted_error
diff --git a/validator_derive/src/validation.rs b/validator_derive/src/validation.rs
index a9762db..d9ad5a5 100644
--- a/validator_derive/src/validation.rs
+++ b/validator_derive/src/validation.rs
@@ -95,8 +95,8 @@ pub fn extract_range_validation(
field: String,
meta_items: &Vec<syn::NestedMeta>,
) -> FieldValidation {
- let mut min = 0.0;
- let mut max = 0.0;
+ let mut min = None;
+ let mut max = None;
let (message, code) = extract_message_and_code("range", &field, meta_items);
@@ -104,45 +104,38 @@ pub fn extract_range_validation(
panic!("Invalid attribute #[validate] on field `{}`: {}", field, msg);
};
- // whether it has both `min` and `max`
- let mut has_min = false;
- let mut has_max = false;
-
for meta_item in meta_items {
match *meta_item {
syn::NestedMeta::Meta(ref item) => match *item {
- syn::Meta::NameValue(syn::MetaNameValue { ref ident, ref lit, .. }) => match ident
- .to_string()
- .as_ref()
- {
- "message" | "code" => continue,
- "min" => {
- min = match lit_to_float(lit) {
- Some(s) => s,
+ syn::Meta::NameValue(syn::MetaNameValue { ref ident, ref lit, .. }) => {
+ match ident.to_string().as_ref() {
+ "message" | "code" => continue,
+ "min" => {
+ min = match lit_to_float(lit) {
+ Some(s) => Some(s),
None => error("invalid argument type for `min` of `range` validator: only integers are allowed")
};
- has_min = true;
- }
- "max" => {
- max = match lit_to_float(lit) {
- Some(s) => s,
+ }
+ "max" => {
+ max = match lit_to_float(lit) {
+ Some(s) => Some(s),
None => error("invalid argument type for `max` of `range` validator: only integers are allowed")
};
- has_max = true;
- }
- v => error(&format!(
+ }
+ v => error(&format!(
"unknown argument `{}` for validator `range` (it only has `min`, `max`)",
v
)),
- },
+ }
+ }
_ => panic!("unexpected item {:?} while parsing `range` validator", item),
},
_ => unreachable!(),
}
}
- if !has_min || !has_max {
- error("Validator `range` requires 2 arguments: `min` and `max`");
+ if !min.is_some() && !max.is_some() {
+ error("Validator `range` requires at least 1 argument out of `min` and `max`");
}
let validator = Validator::Range { min, max };
diff --git a/validator_derive/tests/compile-fail/range/missing_arg.rs b/validator_derive/tests/compile-fail/range/missing_arg.rs
deleted file mode 100644
index 3aed1f0..0000000
--- a/validator_derive/tests/compile-fail/range/missing_arg.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(attr_literals)]
-
-#[macro_use] extern crate validator_derive;
-extern crate validator;
-use validator::Validate;
-
-#[derive(Validate)]
-//~^ ERROR: proc-macro derive panicked
-//~^^ HELP: Invalid attribute #[validate] on field `s`: Validator `range` requires 2 arguments: `min` and `max`
-struct Test {
- #[validate(range(min = 2.0))]
- s: i32,
-}
-
-fn main() {}
diff --git a/validator_derive/tests/compile-fail/range/no_args.rs b/validator_derive/tests/compile-fail/range/no_args.rs
index c2bdd03..b097b0a 100644
--- a/validator_derive/tests/compile-fail/range/no_args.rs
+++ b/validator_derive/tests/compile-fail/range/no_args.rs
@@ -4,7 +4,7 @@ use validator::Validate;
#[derive(Validate)]
//~^ ERROR: proc-macro derive panicked
-//~^^ HELP: Invalid attribute #[validate] on field `s`: Validator `range` requires 2 arguments: `min` and `max`
+//~^^ HELP: Invalid attribute #[validate] on field `s`: Validator `range` requires at least 1 argument out of `min` and `max`
struct Test {
#[validate(range())]
s: i32,
diff --git a/validator_derive/tests/run-pass/range.rs b/validator_derive/tests/run-pass/range.rs
index e35f3df..520dd64 100644
--- a/validator_derive/tests/run-pass/range.rs
+++ b/validator_derive/tests/run-pass/range.rs
@@ -24,6 +24,10 @@ struct Test {
s8: u8,
#[validate(range(min = 18.0, max = 22))]
s9: Option<u8>,
+ #[validate(range(min = 18.0))]
+ s10: Option<u8>,
+ #[validate(range(max = 18.0))]
+ s11: Option<u8>,
}
fn main() {}