diff --git a/serde_valid/README.md b/serde_valid/README.md index c1b31f3..d2f1bd2 100644 --- a/serde_valid/README.md +++ b/serde_valid/README.md @@ -65,12 +65,12 @@ Serde Valid support standard validation based JSON Schema. In addition, [serde_valid::utils][module@crate::utils] provides a type of validation not described in the JSON schema specification. -| Type | Serde Valid (validate derive) | Serde Valid (validation function) | -| :------------------------------------------------------------------: | :-------------------------------------------------------- | :----------------------------------------------------------------------- | -| [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom(duration_maximum(SECOND)))]` | [duration_maximum][`crate::utils::duration_maximum`] | -| [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom(duration_minimum(ZERO)))]` | [duration_minimum][`crate::utils::duration_minimum`] | -| [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom(duration_exclusive_maximum(SECOND)))]` | [duration_exclusive_maximum][`crate::utils::duration_exclusive_maximum`] | -| [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom(duration_exclusive_minimum(ZERO)))]` | [duration_exclusive_minimum][`crate::utils::duration_exclusive_minimum`] | +| Type | Serde Valid (validate derive) | Serde Valid (validation function) | +| :------------------------------------------------------------------: | :--------------------------------------------------------- | :----------------------------------------------------------------------- | +| [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom = duration_maximum(SECOND))]` | [duration_maximum][`crate::utils::duration_maximum`] | +| [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom = duration_minimum(ZERO))]` | [duration_minimum][`crate::utils::duration_minimum`] | +| [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom = duration_exclusive_maximum(SECOND))]` | [duration_exclusive_maximum][`crate::utils::duration_exclusive_maximum`] | +| [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom = duration_exclusive_minimum(ZERO))]` | [duration_exclusive_minimum][`crate::utils::duration_exclusive_minimum`] | ## Complete Constructor (Deserialization) @@ -202,7 +202,7 @@ assert_eq!( ## Custom Validation ### Single Error Validation -You can use your custom validation using by `#[validate(custom)]`. +You can use your custom validation using by `#[validate(custom = ...)]`. ```rust use serde_valid::Validate; @@ -213,7 +213,7 @@ fn user_validation(_val: &i32) -> Result<(), serde_valid::validation::Error> { #[derive(Validate)] struct Data { - #[validate(custom(user_validation))] + #[validate(custom = user_validation)] val: i32, } @@ -233,7 +233,7 @@ fn user_validation(_val: &i32, param1: bool) -> Result<(), serde_valid::validati #[derive(Validate)] struct Data { - #[validate(custom(|v| user_validation(v, true)))] + #[validate(custom = |v| user_validation(v, true))] val: i32, } @@ -253,8 +253,8 @@ use serde_valid::utils::{duration_maximum, duration_minimum}; #[derive(Validate)] struct Data { - #[validate(custom(duration_maximum(std::time::Duration::from_micros(5))))] - #[validate(custom(duration_minimum(std::time::Duration::from_micros(0))))] + #[validate(custom = duration_maximum(std::time::Duration::from_micros(5)))] + #[validate(custom = duration_minimum(std::time::Duration::from_micros(0)))] val1: std::time::Duration, } @@ -266,7 +266,7 @@ assert!(s.validate().is_ok()); ``` ### Multi Errors Validation -If you want to return multiple errors in the use custom validation method, you can use `#[validate(custom)]` same as single error. +If you want to return multiple errors in the use custom validation method, you can use `#[validate(custom = ...)]` same as single error. ```rust use serde_valid::Validate; @@ -278,7 +278,7 @@ fn user_validation(_val: &i32) -> Result<(), Vec #[derive(Validate)] struct Data { - #[validate(custom(user_validation))] + #[validate(custom = user_validation)] val: i32, } @@ -288,7 +288,7 @@ assert!(s.validate().is_ok()); ``` ### Multi Fields Validation -Now, you can use `#[validate(custom)]` for multi fields validation. +Now, you can use `#[validate(custom = ...)]` for multi fields validation. ```rust use serde_json::json; @@ -299,7 +299,7 @@ fn sample_validation(val1: i32, val2: &str) -> Result<(), serde_valid::validatio } #[derive(Validate)] -#[validate(custom(|s| sample_validation(s.val1, &s.val2)))] +#[validate(custom = |s| sample_validation(s.val1, &s.val2))] struct Data { val1: i32, val2: String, diff --git a/serde_valid/src/lib.rs b/serde_valid/src/lib.rs index 988e7cf..eb2178f 100644 --- a/serde_valid/src/lib.rs +++ b/serde_valid/src/lib.rs @@ -65,12 +65,12 @@ //! //! In addition, [serde_valid::utils][module@crate::utils] provides a type of validation not described in the JSON schema specification. //! -//! | Type | Serde Valid (validate derive) | Serde Valid (validation function) | -//! | :------------------------------------------------------------------: | :-------------------------------------------------------- | :----------------------------------------------------------------------- | -//! | [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom(duration_maximum(SECOND)))]` | [duration_maximum][`crate::utils::duration_maximum`] | -//! | [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom(duration_minimum(ZERO)))]` | [duration_minimum][`crate::utils::duration_minimum`] | -//! | [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom(duration_exclusive_maximum(SECOND)))]` | [duration_exclusive_maximum][`crate::utils::duration_exclusive_maximum`] | -//! | [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom(duration_exclusive_minimum(ZERO)))]` | [duration_exclusive_minimum][`crate::utils::duration_exclusive_minimum`] | +//! | Type | Serde Valid (validate derive) | Serde Valid (validation function) | +//! | :------------------------------------------------------------------: | :--------------------------------------------------------- | :----------------------------------------------------------------------- | +//! | [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom = duration_maximum(SECOND))]` | [duration_maximum][`crate::utils::duration_maximum`] | +//! | [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom = duration_minimum(ZERO))]` | [duration_minimum][`crate::utils::duration_minimum`] | +//! | [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom = duration_exclusive_maximum(SECOND))]` | [duration_exclusive_maximum][`crate::utils::duration_exclusive_maximum`] | +//! | [Duration](https://doc.rust-lang.org/core/time/struct.Duration.html) | `#[validate(custom = duration_exclusive_minimum(ZERO))]` | [duration_exclusive_minimum][`crate::utils::duration_exclusive_minimum`] | //! //! ## Complete Constructor (Deserialization) //! @@ -212,7 +212,7 @@ //! //! ## Custom Validation //! ### Single Error Validation -//! You can use your custom validation using by `#[validate(custom)]`. +//! You can use your custom validation using by `#[validate(custom = ...)]`. //! //! ```rust //! use serde_valid::Validate; @@ -223,7 +223,7 @@ //! //! #[derive(Validate)] //! struct Data { -//! #[validate(custom(user_validation))] +//! #[validate(custom = user_validation)] //! val: i32, //! } //! @@ -243,7 +243,7 @@ //! //! #[derive(Validate)] //! struct Data { -//! #[validate(custom(|v| user_validation(v, true)))] +//! #[validate(custom = |v| user_validation(v, true))] //! val: i32, //! } //! @@ -263,8 +263,8 @@ //! //! #[derive(Validate)] //! struct Data { -//! #[validate(custom(duration_maximum(std::time::Duration::from_micros(5))))] -//! #[validate(custom(duration_minimum(std::time::Duration::from_micros(0))))] +//! #[validate(custom = duration_maximum(std::time::Duration::from_micros(5)))] +//! #[validate(custom = duration_minimum(std::time::Duration::from_micros(0)))] //! val1: std::time::Duration, //! } //! @@ -276,7 +276,7 @@ //! ``` //! //! ### Multi Errors Validation -//! If you want to return multiple errors in the use custom validation method, you can use `#[validate(custom)]` same as single error. +//! If you want to return multiple errors in the use custom validation method, you can use `#[validate(custom = ...)]` same as single error. //! //! ```rust //! use serde_valid::Validate; @@ -288,7 +288,7 @@ //! //! #[derive(Validate)] //! struct Data { -//! #[validate(custom(user_validation))] +//! #[validate(custom = user_validation)] //! val: i32, //! } //! @@ -298,7 +298,7 @@ //! ``` //! //! ### Multi Fields Validation -//! Now, you can use `#[validate(custom)]` for multi fields validation. +//! Now, you can use `#[validate(custom = ...)]` for multi fields validation. //! //! ```rust //! use serde_json::json; @@ -309,7 +309,7 @@ //! } //! //! #[derive(Validate)] -//! #[validate(custom(|s| sample_validation(s.val1, &s.val2)))] +//! #[validate(custom = |s| sample_validation(s.val1, &s.val2))] //! struct Data { //! val1: i32, //! val2: String, diff --git a/serde_valid/src/utils/duration.rs b/serde_valid/src/utils/duration.rs index e4a4036..63a0878 100644 --- a/serde_valid/src/utils/duration.rs +++ b/serde_valid/src/utils/duration.rs @@ -12,7 +12,7 @@ use std::time::Duration; /// /// #[derive(Validate)] /// struct TestStruct { -/// #[validate(custom(duration_maximum(Duration::from_micros(5))))] +/// #[validate(custom = duration_maximum(Duration::from_micros(5)))] /// val: Duration, /// } /// @@ -49,7 +49,7 @@ pub fn duration_maximum( /// /// #[derive(Validate)] /// struct TestStruct { -/// #[validate(custom(duration_minimum(Duration::from_micros(5))))] +/// #[validate(custom = duration_minimum(Duration::from_micros(5)))] /// val: Duration, /// } /// @@ -86,7 +86,7 @@ pub fn duration_minimum( /// /// #[derive(Validate)] /// struct TestStruct { -/// #[validate(custom(duration_exclusive_maximum(Duration::from_micros(5))))] +/// #[validate(custom = duration_exclusive_maximum(Duration::from_micros(5)))] /// val: Duration, /// } /// @@ -123,7 +123,7 @@ pub fn duration_exclusive_maximum( /// /// #[derive(Validate)] /// struct TestStruct { -/// #[validate(custom(duration_exclusive_minimum(Duration::from_micros(5))))] +/// #[validate(custom = duration_exclusive_minimum(Duration::from_micros(5)))] /// val: Duration, /// } /// diff --git a/serde_valid/src/validation/custom.rs b/serde_valid/src/validation/custom.rs index 1f1f3ee..16aa25a 100644 --- a/serde_valid/src/validation/custom.rs +++ b/serde_valid/src/validation/custom.rs @@ -1,4 +1,4 @@ -/// This function is used to avoid [rustc(E0282)](https://doc.rust-lang.org/error_codes/E0282.html) error in `#[validate(custom)]` validator on the struct. +/// This function is used to avoid [rustc(E0282)](https://doc.rust-lang.org/error_codes/E0282.html) error in `#[validate(custom = ...)]` validator on the struct. #[inline] pub fn wrap_closure_validation( data: &T, diff --git a/serde_valid/tests/array_test.rs b/serde_valid/tests/array_test.rs index 3e00eda..a56f160 100644 --- a/serde_valid/tests/array_test.rs +++ b/serde_valid/tests/array_test.rs @@ -18,7 +18,7 @@ fn items_err_message() { } #[derive(Validate)] - #[validate(custom(|s| rule_sample(s.val)))] + #[validate(custom = |s| rule_sample(s.val))] struct TestChildStruct { #[validate(minimum = 1)] #[validate(maximum = 10)] diff --git a/serde_valid/tests/complex_test.rs b/serde_valid/tests/complex_test.rs index 2311f86..a058b4e 100644 --- a/serde_valid/tests/complex_test.rs +++ b/serde_valid/tests/complex_test.rs @@ -5,7 +5,7 @@ fn sample_rule(_val: i32) -> Result<(), serde_valid::validation::Error> { } #[derive(Debug, Validate)] -#[validate(custom(|s| sample_rule(s.int_value)))] +#[validate(custom = |s| sample_rule(s.int_value))] struct TestStruct<'a> { // Generic validator #[validate(enumerate = [5, 10, 15])] diff --git a/serde_valid/tests/custom_duration_test.rs b/serde_valid/tests/custom_duration_test.rs index 82bb29e..9c7901a 100644 --- a/serde_valid/tests/custom_duration_test.rs +++ b/serde_valid/tests/custom_duration_test.rs @@ -8,7 +8,7 @@ use serde_valid::Validate; fn duration_maximum_is_ok() { #[derive(Validate)] struct TestStruct { - #[validate(custom(duration_maximum(Duration::from_micros(5))))] + #[validate(custom = duration_maximum(Duration::from_micros(5)))] val: Duration, } @@ -23,7 +23,7 @@ fn duration_maximum_is_ok() { fn duration_minimum_is_ok() { #[derive(Validate)] struct TestStruct { - #[validate(custom(duration_minimum(Duration::from_micros(5))))] + #[validate(custom = duration_minimum(Duration::from_micros(5)))] val: Duration, } @@ -38,7 +38,7 @@ fn duration_minimum_is_ok() { fn duration_maximum_is_err() { #[derive(Validate)] struct TestStruct { - #[validate(custom(duration_maximum(Duration::from_micros(5))))] + #[validate(custom = duration_maximum(Duration::from_micros(5)))] val: Duration, } @@ -66,7 +66,7 @@ fn duration_maximum_is_err() { fn duration_minimum_is_err() { #[derive(Validate)] struct TestStruct { - #[validate(custom(duration_minimum(Duration::from_micros(5))))] + #[validate(custom = duration_minimum(Duration::from_micros(5)))] val: Duration, } diff --git a/serde_valid/tests/custom_test.rs b/serde_valid/tests/custom_test.rs index 6ddf234..23cece6 100644 --- a/serde_valid/tests/custom_test.rs +++ b/serde_valid/tests/custom_test.rs @@ -15,7 +15,7 @@ fn custom_validation_is_ok() { #[derive(Validate)] struct TestStruct { - #[validate(custom(user_validation))] + #[validate(custom = user_validation)] val: i32, } @@ -27,7 +27,7 @@ fn custom_validation_is_ok() { fn custom_parenthesized_path_validation_is_ok() { #[derive(Validate)] struct TestStruct { - #[validate(custom(parenthesized::meta_path_validation))] + #[validate(custom = parenthesized::meta_path_validation)] val: Vec, } @@ -45,7 +45,7 @@ fn custom_clouser_validation_is_ok() { #[derive(Validate)] struct TestStruct { - #[validate(custom(|x| user_validation(x, 10)))] + #[validate(custom = |x| user_validation(x, 10))] val: Vec, } @@ -69,7 +69,7 @@ fn custom_clouser_validation_is_err() { #[derive(Validate)] struct TestStruct { - #[validate(custom(|x| user_validation(x, 10)))] + #[validate(custom = |x| user_validation(x, 10))] val: Vec, } @@ -89,7 +89,7 @@ fn custom_validation_error() { #[derive(Validate)] struct TestStruct { - #[validate(custom(user_validation))] + #[validate(custom = user_validation)] val: Vec, } @@ -119,7 +119,7 @@ fn named_struct_custom_is_ok() { } #[derive(Validate)] - #[validate(custom(sample_struct_validation))] + #[validate(custom = sample_struct_validation)] struct TestStruct { val: i32, } @@ -136,7 +136,7 @@ fn named_struct_custom_closure_is_ok() { } #[derive(Validate)] - #[validate(custom(|s| sample_struct_validation(s.val)))] + #[validate(custom = |s| sample_struct_validation(s.val))] struct TestStruct { val: i32, } @@ -153,7 +153,7 @@ fn unnamed_struct_custom_is_ok() { } #[derive(Validate)] - #[validate(custom(sample_struct_validation))] + #[validate(custom = sample_struct_validation)] struct TestStruct(i32); let s = TestStruct(5); @@ -168,7 +168,7 @@ fn unnamed_struct_custom_closure_is_ok() { } #[derive(Validate)] - #[validate(custom(|s| sample_struct_validation(s.0)))] + #[validate(custom = |s| sample_struct_validation(s.0))] struct TestStruct(i32); let s = TestStruct(5); @@ -185,7 +185,7 @@ fn unnamed_struct_custom_closure_is_err() { } #[derive(Validate)] - #[validate(custom(|s| sample_struct_validation(s.0)))] + #[validate(custom = |s| sample_struct_validation(s.0))] struct TestStruct(i32); let s = TestStruct(5); @@ -200,7 +200,7 @@ fn named_struct_custom_vec_errors_is_ok() { } #[derive(Validate)] - #[validate(custom(validation))] + #[validate(custom = validation)] struct TestStruct { val: i32, } @@ -220,7 +220,7 @@ fn named_struct_custom_vec_errors_is_err() { } #[derive(Validate)] - #[validate(custom(validation))] + #[validate(custom = validation)] struct TestStruct { val: i32, } @@ -245,7 +245,7 @@ fn named_struct_custom_closure_vec_errors_is_ok() { } #[derive(Validate)] - #[validate(custom(|s| sample_struct_validation(s.val)))] + #[validate(custom = |s| sample_struct_validation(s.val))] struct TestStruct { val: i32, } @@ -265,7 +265,7 @@ fn named_struct_custom_closure_vec_errors_is_err() { } #[derive(Validate)] - #[validate(custom(|s| sample_struct_validation(s.val)))] + #[validate(custom = |s| sample_struct_validation(s.val))] struct TestStruct { val: i32, } diff --git a/serde_valid/tests/deprecated_custom_test.rs b/serde_valid/tests/deprecated_custom_test.rs new file mode 100644 index 0000000..a0127c8 --- /dev/null +++ b/serde_valid/tests/deprecated_custom_test.rs @@ -0,0 +1,297 @@ +#[allow(deprecated)] +mod test { + use serde_json::json; + use serde_valid::Validate; + + mod parenthesized { + pub fn meta_path_validation(_val: &[i32]) -> Result<(), serde_valid::validation::Error> { + Ok(()) + } + } + + #[test] + fn custom_validation_is_ok() { + fn user_validation(_val: &i32) -> Result<(), serde_valid::validation::Error> { + Ok(()) + } + + #[derive(Validate)] + struct TestStruct { + #[validate(custom(user_validation))] + val: i32, + } + + let s = TestStruct { val: 1 }; + assert!(s.validate().is_ok()); + } + + #[test] + fn custom_parenthesized_path_validation_is_ok() { + #[derive(Validate)] + struct TestStruct { + #[validate(custom(parenthesized::meta_path_validation))] + val: Vec, + } + + let s = TestStruct { + val: vec![1, 2, 3, 4], + }; + assert!(s.validate().is_ok()); + } + + #[test] + fn custom_clouser_validation_is_ok() { + fn user_validation( + _val: &[i32], + _maximum: i32, + ) -> Result<(), serde_valid::validation::Error> { + Ok(()) + } + + #[derive(Validate)] + struct TestStruct { + #[validate(custom(|x| user_validation(x, 10)))] + val: Vec, + } + + let s = TestStruct { + val: vec![1, 2, 3, 4], + }; + assert!(s.validate().is_ok()); + } + + #[test] + fn custom_clouser_validation_is_err() { + fn user_validation( + val: &[i32], + maximum: i32, + ) -> Result<(), serde_valid::validation::Error> { + if val.iter().all(|v| v <= &maximum) { + Ok(()) + } else { + Err(serde_valid::validation::Error::Custom( + "this is custom message.".to_string(), + )) + } + } + + #[derive(Validate)] + struct TestStruct { + #[validate(custom(|x| user_validation(x, 10)))] + val: Vec, + } + + let s = TestStruct { + val: vec![1, 2, 3, 11], + }; + assert!(s.validate().is_err()); + } + + #[test] + fn custom_validation_error() { + fn user_validation(_val: &[i32]) -> Result<(), serde_valid::validation::Error> { + Err(serde_valid::validation::Error::Custom( + "this is custom message.".to_string(), + )) + } + + #[derive(Validate)] + struct TestStruct { + #[validate(custom(user_validation))] + val: Vec, + } + + let s = TestStruct { + val: vec![1, 2, 3, 4], + }; + + assert_eq!( + s.validate().unwrap_err().to_string(), + json!({ + "errors": [], + "properties": { + "val": { + "errors": [ + "this is custom message." + ] + } + } + }) + .to_string() + ); + } + + #[test] + fn named_struct_custom_is_ok() { + fn sample_struct_validation( + _val: &TestStruct, + ) -> Result<(), serde_valid::validation::Error> { + Ok(()) + } + + #[derive(Validate)] + #[validate(custom(sample_struct_validation))] + struct TestStruct { + val: i32, + } + + let s = TestStruct { val: 5 }; + assert_eq!(s.val, 5); + assert!(s.validate().is_ok()); + } + + #[test] + fn named_struct_custom_closure_is_ok() { + fn sample_struct_validation(_val: i32) -> Result<(), serde_valid::validation::Error> { + Ok(()) + } + + #[derive(Validate)] + #[validate(custom(|s| sample_struct_validation(s.val)))] + struct TestStruct { + val: i32, + } + + let s = TestStruct { val: 5 }; + assert_eq!(s.val, 5); + assert!(s.validate().is_ok()); + } + + #[test] + fn unnamed_struct_custom_is_ok() { + fn sample_struct_validation( + _val: &TestStruct, + ) -> Result<(), serde_valid::validation::Error> { + Ok(()) + } + + #[derive(Validate)] + #[validate(custom(sample_struct_validation))] + struct TestStruct(i32); + + let s = TestStruct(5); + assert_eq!(s.0, 5); + assert!(s.validate().is_ok()); + } + + #[test] + fn unnamed_struct_custom_closure_is_ok() { + fn sample_struct_validation(_val: i32) -> Result<(), serde_valid::validation::Error> { + Ok(()) + } + + #[derive(Validate)] + #[validate(custom(|s| sample_struct_validation(s.0)))] + struct TestStruct(i32); + + let s = TestStruct(5); + assert_eq!(s.0, 5); + assert!(s.validate().is_ok()); + } + + #[test] + fn unnamed_struct_custom_closure_is_err() { + fn sample_struct_validation(_val: i32) -> Result<(), serde_valid::validation::Error> { + Err(serde_valid::validation::Error::Custom( + "Struct Validation Error.".to_owned(), + )) + } + + #[derive(Validate)] + #[validate(custom(|s| sample_struct_validation(s.0)))] + struct TestStruct(i32); + + let s = TestStruct(5); + assert_eq!(s.0, 5); + assert!(s.validate().is_err()); + } + + #[test] + fn named_struct_custom_vec_errors_is_ok() { + fn validation(_val: &TestStruct) -> Result<(), Vec> { + Ok(()) + } + + #[derive(Validate)] + #[validate(custom(validation))] + struct TestStruct { + val: i32, + } + + let s = TestStruct { val: 5 }; + assert_eq!(s.val, 5); + assert!(s.validate().is_ok()); + } + + #[test] + fn named_struct_custom_vec_errors_is_err() { + fn validation(_val: &TestStruct) -> Result<(), Vec> { + Err(vec![ + serde_valid::validation::Error::Custom("Error 1".to_owned()), + serde_valid::validation::Error::Custom("Error 2".to_owned()), + ]) + } + + #[derive(Validate)] + #[validate(custom(validation))] + struct TestStruct { + val: i32, + } + + let s = TestStruct { val: 5 }; + + assert_eq!(s.val, 5); + assert_eq!( + s.validate().unwrap_err().to_string(), + json!({ + "errors": ["Error 1", "Error 2"], + "properties": {} + }) + .to_string() + ); + } + + #[test] + fn named_struct_custom_closure_vec_errors_is_ok() { + fn sample_struct_validation(_val: i32) -> Result<(), Vec> { + Ok(()) + } + + #[derive(Validate)] + #[validate(custom(|s| sample_struct_validation(s.val)))] + struct TestStruct { + val: i32, + } + + let s = TestStruct { val: 5 }; + assert_eq!(s.val, 5); + assert!(s.validate().is_ok()); + } + + #[test] + fn named_struct_custom_closure_vec_errors_is_err() { + fn sample_struct_validation(_val: i32) -> Result<(), Vec> { + Err(vec![ + serde_valid::validation::Error::Custom("Error 1".to_owned()), + serde_valid::validation::Error::Custom("Error 2".to_owned()), + ]) + } + + #[derive(Validate)] + #[validate(custom(|s| sample_struct_validation(s.val)))] + struct TestStruct { + val: i32, + } + + let s = TestStruct { val: 5 }; + assert_eq!(s.val, 5); + assert_eq!( + s.validate().unwrap_err().to_string(), + json!({ + "errors": ["Error 1", "Error 2"], + "properties": {} + }) + .to_string() + ); + } +} diff --git a/serde_valid/tests/enum_test.rs b/serde_valid/tests/enum_test.rs index 54d8bb2..09644c9 100644 --- a/serde_valid/tests/enum_test.rs +++ b/serde_valid/tests/enum_test.rs @@ -7,7 +7,7 @@ fn enum_named_enum_validation_is_ok() { Ok(()) } #[derive(Validate)] - #[validate(custom(ok_enum))] + #[validate(custom = ok_enum)] enum TestEnum { Named { #[validate] @@ -78,7 +78,7 @@ fn enum_named_enum_validation_is_err() { } #[derive(Validate)] - #[validate(custom(err_rule))] + #[validate(custom = err_rule)] enum TestEnum { Named { #[validate] @@ -135,7 +135,7 @@ fn enum_unnamed_enum_validation_is_err() { } #[derive(Validate)] - #[validate(custom(err_rule))] + #[validate(custom = err_rule)] enum TestEnum { Named(#[validate] TestStruct, #[validate] TestStruct), } @@ -185,7 +185,7 @@ fn enum_newtype_variant_validation_is_err() { } #[derive(Validate)] - #[validate(custom(err_rule))] + #[validate(custom = err_rule)] enum TestEnum { NewType(#[validate(minimum = 5)] u32), } diff --git a/serde_valid/tests/specific_test.rs b/serde_valid/tests/specific_test.rs index 65e3bae..7b23f18 100644 --- a/serde_valid/tests/specific_test.rs +++ b/serde_valid/tests/specific_test.rs @@ -3,7 +3,7 @@ use serde_valid::Validate; #[test] fn test_raw_type_field() { #[derive(Validate)] - #[validate(custom(|s| sample_rule(s.r#type)))] + #[validate(custom = |s| sample_rule(s.r#type))] struct MyStruct { #[validate(maximum = 10)] pub r#type: i32, diff --git a/serde_valid_derive/src/attribute.rs b/serde_valid_derive/src/attribute.rs index 971812f..4858522 100644 --- a/serde_valid_derive/src/attribute.rs +++ b/serde_valid_derive/src/attribute.rs @@ -88,6 +88,7 @@ enum_str! { enum_str! { pub enum MetaNameValueStructValidation { + Custom = "custom", } } @@ -119,6 +120,7 @@ enum_str! { MultipleOf = "multiple_of", Pattern = "pattern", Enumerate = "enumerate", + Custom = "custom", } } diff --git a/serde_valid_derive/src/attribute/field_validate/generic.rs b/serde_valid_derive/src/attribute/field_validate/generic.rs index 26edc17..fbfae0a 100644 --- a/serde_valid_derive/src/attribute/field_validate/generic.rs +++ b/serde_valid_derive/src/attribute/field_validate/generic.rs @@ -2,7 +2,10 @@ mod custom; mod enumerate; mod validate; -pub use custom::extract_generic_custom_validator; +pub use custom::{ + extract_generic_custom_validator_from_meta_list, + extract_generic_custom_validator_from_meta_name_value, +}; pub use enumerate::{ extract_generic_enumerate_validator_from_list, extract_generic_enumerate_validator_from_name_value, diff --git a/serde_valid_derive/src/attribute/field_validate/generic/custom.rs b/serde_valid_derive/src/attribute/field_validate/generic/custom.rs index eb8ad72..526ef66 100644 --- a/serde_valid_derive/src/attribute/field_validate/generic/custom.rs +++ b/serde_valid_derive/src/attribute/field_validate/generic/custom.rs @@ -5,7 +5,7 @@ use crate::types::{CommaSeparatedNestedMetas, Field, SingleIdentPath}; use proc_macro2::TokenStream; use quote::quote; -pub fn extract_generic_custom_validator( +pub fn extract_generic_custom_validator_from_meta_list( field: &impl Field, meta_list: &syn::MetaList, _message_format: MessageFormat, @@ -14,17 +14,16 @@ pub fn extract_generic_custom_validator( let path = &meta_list.path; let path_ident = SingleIdentPath::new(path).ident(); let field_name = field.name(); - let field_ident = field.ident(); let field_key = field.key(); - let rename = rename_map.get(field_name).unwrap_or(&field_key); - let errors = field.errors_variable(); let nested = meta_list .parse_args_with(CommaSeparatedNestedMetas::parse_terminated) .map_err(|error| vec![crate::Error::custom_message_parse_error(path_ident, &error)])?; + let field_ident = field.ident(); + let rename = rename_map.get(field_name).unwrap_or(&field_key); let custom_fn_name = match nested.len() { 0 => Err(vec![ - crate::Error::validate_custom_need_function_or_closure(path), + crate::Error::validate_custom_meta_list_need_function_or_closure(path), ]), 1 => extract_custom_fn_name(&nested[0]), _ => Err(nested @@ -33,7 +32,43 @@ pub fn extract_generic_custom_validator( .map(crate::Error::validate_custom_tail_error) .collect()), }?; + inner_extract_generic_custom_validator( + field_ident, + rename, + &custom_fn_name, + &field.errors_variable(), + ) +} +pub fn extract_generic_custom_validator_from_meta_name_value( + field: &impl Field, + meta_name_value: &syn::MetaNameValue, + _message_format: MessageFormat, + rename_map: &RenameMap, +) -> Result { + let field_name = field.name(); + let field_key = field.key(); + + let field_ident = field.ident(); + let rename = rename_map.get(field_name).unwrap_or(&field_key); + let fn_name = match &meta_name_value.value { + syn::Expr::Path(path) => Ok(quote!(#path)), + syn::Expr::Call(func_call) => Ok(quote!(#func_call)), + syn::Expr::Closure(closure) => Ok(quote!((#closure))), + _ => Err(vec![ + crate::Error::validate_custom_meta_name_value_need_function_or_closure(meta_name_value), + ]), + }?; + + inner_extract_generic_custom_validator(field_ident, rename, &fn_name, &field.errors_variable()) +} + +fn inner_extract_generic_custom_validator( + field_ident: &syn::Ident, + rename: &TokenStream, + custom_fn_name: &TokenStream, + errors: &TokenStream, +) -> Result { Ok(quote!( if let Err(__errors) = serde_valid::validation::custom::wrap_into_vec_errors(#custom_fn_name(#field_ident)) { #errors @@ -52,7 +87,7 @@ fn extract_custom_fn_name( crate::types::NestedMeta::Meta(syn::Meta::List(closure)) => Ok(quote!(#closure)), crate::types::NestedMeta::Closure(closure) => Ok(quote!((#closure))), _ => Err(vec![ - crate::Error::validate_custom_need_function_or_closure(nested_meta), + crate::Error::validate_custom_meta_list_need_function_or_closure(nested_meta), ]), } } diff --git a/serde_valid_derive/src/attribute/field_validate/meta/meta_list.rs b/serde_valid_derive/src/attribute/field_validate/meta/meta_list.rs index a4359f0..746d0d5 100644 --- a/serde_valid_derive/src/attribute/field_validate/meta/meta_list.rs +++ b/serde_valid_derive/src/attribute/field_validate/meta/meta_list.rs @@ -2,7 +2,7 @@ use syn::spanned::Spanned; use crate::attribute::common::message_format::MessageFormat; use crate::attribute::field_validate::generic::{ - extract_generic_custom_validator, extract_generic_enumerate_validator_from_list, + extract_generic_custom_validator_from_meta_list, extract_generic_enumerate_validator_from_list, }; use crate::attribute::{MetaListFieldValidation, Validator}; use crate::serde::rename::RenameMap; @@ -26,14 +26,17 @@ pub fn extract_field_validator_from_meta_list( ) .map(|data| WithWarnings { data, - warnings: vec![Warning::new_enumerate_path_deprecated( + warnings: vec![Warning::new_enumerate_meta_list_deprecated( field.ident(), validation.span(), )], }), - MetaListFieldValidation::Custom => { - extract_generic_custom_validator(field, validation, message_format, rename_map) - .map(WithWarnings::new) - } + MetaListFieldValidation::Custom => extract_generic_custom_validator_from_meta_list( + field, + validation, + message_format, + rename_map, + ) + .map(WithWarnings::new), } } diff --git a/serde_valid_derive/src/attribute/field_validate/meta/meta_name_value.rs b/serde_valid_derive/src/attribute/field_validate/meta/meta_name_value.rs index cd638de..0385cca 100644 --- a/serde_valid_derive/src/attribute/field_validate/meta/meta_name_value.rs +++ b/serde_valid_derive/src/attribute/field_validate/meta/meta_name_value.rs @@ -3,7 +3,10 @@ use crate::attribute::common::message_format::MessageFormat; use crate::attribute::field_validate::array::{ extract_array_max_items_validator, extract_array_min_items_validator, }; -use crate::attribute::field_validate::generic::extract_generic_enumerate_validator_from_name_value; +use crate::attribute::field_validate::generic::{ + extract_generic_custom_validator_from_meta_name_value, + extract_generic_enumerate_validator_from_name_value, +}; use crate::attribute::field_validate::numeric::{ extract_numeric_exclusive_maximum_validator, extract_numeric_exclusive_minimum_validator, extract_numeric_maximum_validator, extract_numeric_minimum_validator, @@ -110,5 +113,13 @@ pub fn extract_field_validator_from_meta_name_value( rename_map, ) } + MetaNameValueFieldValidation::Custom => { + extract_generic_custom_validator_from_meta_name_value( + field, + validation, + message_format, + rename_map, + ) + } } } diff --git a/serde_valid_derive/src/attribute/struct_validate.rs b/serde_valid_derive/src/attribute/struct_validate.rs index b471bd5..eda8468 100644 --- a/serde_valid_derive/src/attribute/struct_validate.rs +++ b/serde_valid_derive/src/attribute/struct_validate.rs @@ -1,4 +1,4 @@ -mod generic; +pub mod generic; mod meta; use crate::{attribute::Validator, warning::WithWarnings}; diff --git a/serde_valid_derive/src/attribute/struct_validate/generic.rs b/serde_valid_derive/src/attribute/struct_validate/generic.rs index 20dc85a..b437e6a 100644 --- a/serde_valid_derive/src/attribute/struct_validate/generic.rs +++ b/serde_valid_derive/src/attribute/struct_validate/generic.rs @@ -1,3 +1,6 @@ mod custom; -pub use custom::extract_generic_struct_custom_validator; +pub use custom::{ + extract_generic_struct_custom_validator_from_meta_list, + extract_generic_struct_custom_validator_from_meta_name_value, +}; diff --git a/serde_valid_derive/src/attribute/struct_validate/generic/custom.rs b/serde_valid_derive/src/attribute/struct_validate/generic/custom.rs index 0a8a8e8..d119df3 100644 --- a/serde_valid_derive/src/attribute/struct_validate/generic/custom.rs +++ b/serde_valid_derive/src/attribute/struct_validate/generic/custom.rs @@ -3,7 +3,7 @@ use crate::attribute::Validator; use crate::types::CommaSeparatedNestedMetas; use quote::quote; -pub fn extract_generic_struct_custom_validator( +pub fn extract_generic_struct_custom_validator_from_meta_list( meta_list: &syn::MetaList, _message_format: MessageFormat, ) -> Result { @@ -15,7 +15,7 @@ pub fn extract_generic_struct_custom_validator( match nested.len() { 0 => Err(vec![ - crate::Error::validate_custom_need_function_or_closure(meta_list), + crate::Error::validate_custom_meta_list_need_function_or_closure(meta_list), ])?, 2.. => nested .iter() @@ -33,7 +33,7 @@ pub fn extract_generic_struct_custom_validator( } crate::types::NestedMeta::Closure(closure) => extract_struct_custom_from_closure(closure), _ => Err(vec![ - crate::Error::validate_custom_need_function_or_closure(&nested[0]), + crate::Error::validate_custom_meta_list_need_function_or_closure(&nested[0]), ]), }; @@ -49,6 +49,20 @@ pub fn extract_generic_struct_custom_validator( } } +pub fn extract_generic_struct_custom_validator_from_meta_name_value( + meta_name_value: &syn::MetaNameValue, + _message_format: MessageFormat, +) -> Result { + match &meta_name_value.value { + syn::Expr::Path(syn::ExprPath { path, .. }) => extract_struct_custom_from_meta_path(path), + syn::Expr::Call(call) => extract_struct_custom_from_call(call), + syn::Expr::Closure(closure) => extract_struct_custom_from_closure(closure), + _ => Err(vec![ + crate::Error::validate_custom_meta_name_value_need_function_or_closure(meta_name_value), + ]), + } +} + fn extract_struct_custom_from_meta_path(meta_path: &syn::Path) -> Result { let rule_fn_name = &meta_path; @@ -69,6 +83,14 @@ fn extract_struct_custom_from_meta_list( )) } +fn extract_struct_custom_from_call(call: &syn::ExprCall) -> Result { + Ok(quote!( + if let Err(__errors) = serde_valid::validation::custom::wrap_call_validation(self, #call) { + __rule_vec_errors.extend(__errors); + }; + )) +} + fn extract_struct_custom_from_closure( closure: &syn::ExprClosure, ) -> Result { diff --git a/serde_valid_derive/src/attribute/struct_validate/meta.rs b/serde_valid_derive/src/attribute/struct_validate/meta.rs index 7636781..b4eb9e5 100644 --- a/serde_valid_derive/src/attribute/struct_validate/meta.rs +++ b/serde_valid_derive/src/attribute/struct_validate/meta.rs @@ -25,9 +25,7 @@ pub fn extract_struct_validator( ) -> Result, crate::Errors> { match &attribute.meta { syn::Meta::Path(_) => Ok(WithWarnings::new(quote!())), - syn::Meta::List(list) => { - inner_extract_struct_validator(attribute, list).map(WithWarnings::new) - } + syn::Meta::List(list) => inner_extract_struct_validator(attribute, list), syn::Meta::NameValue(name_value) => { Err(vec![crate::Error::validate_meta_name_value_not_supported( name_value, @@ -39,7 +37,7 @@ pub fn extract_struct_validator( fn inner_extract_struct_validator( attribute: &syn::Attribute, meta_list: &syn::MetaList, -) -> Result { +) -> Result, crate::Errors> { let mut errors = vec![]; let nested = meta_list .parse_args_with(crate::types::CommaSeparatedMetas::parse_terminated) diff --git a/serde_valid_derive/src/attribute/struct_validate/meta/meta_list.rs b/serde_valid_derive/src/attribute/struct_validate/meta/meta_list.rs index fe65d16..883debc 100644 --- a/serde_valid_derive/src/attribute/struct_validate/meta/meta_list.rs +++ b/serde_valid_derive/src/attribute/struct_validate/meta/meta_list.rs @@ -1,17 +1,32 @@ -use crate::attribute::{ - common::message_format::MessageFormat, - struct_validate::generic::extract_generic_struct_custom_validator, MetaListStructValidation, - Validator, +use syn::spanned::Spanned; + +use crate::{ + attribute::{ + common::message_format::MessageFormat, + struct_validate::generic::extract_generic_struct_custom_validator_from_meta_list, + MetaListStructValidation, Validator, + }, + warning::{Warning, WithWarnings}, }; pub fn extract_struct_validator_from_meta_list( validation_type: MetaListStructValidation, validation: &syn::MetaList, message_format: MessageFormat, -) -> Result { +) -> Result, crate::Errors> { match validation_type { MetaListStructValidation::Custom => { - extract_generic_struct_custom_validator(validation, message_format) + extract_generic_struct_custom_validator_from_meta_list(validation, message_format).map( + |validator| { + WithWarnings::new_with_warnings( + validator, + vec![Warning::new_custom_meta_list_deprecated( + validation.path.get_ident().unwrap(), + validation.span(), + )], + ) + }, + ) } } } diff --git a/serde_valid_derive/src/attribute/struct_validate/meta/meta_name_value.rs b/serde_valid_derive/src/attribute/struct_validate/meta/meta_name_value.rs index 2dec887..f216b6c 100644 --- a/serde_valid_derive/src/attribute/struct_validate/meta/meta_name_value.rs +++ b/serde_valid_derive/src/attribute/struct_validate/meta/meta_name_value.rs @@ -1,12 +1,22 @@ -use crate::attribute::{ - common::message_format::MessageFormat, MetaNameValueStructValidation, Validator, +use crate::{ + attribute::{ + common::message_format::MessageFormat, + struct_validate::generic::extract_generic_struct_custom_validator_from_meta_name_value, + MetaNameValueStructValidation, Validator, + }, + warning::WithWarnings, }; #[inline] pub fn extract_struct_validator_from_meta_name_value( validation_type: MetaNameValueStructValidation, - _validation: &syn::MetaNameValue, - _message_format: MessageFormat, -) -> Result { - match validation_type {} + validation: &syn::MetaNameValue, + message_format: MessageFormat, +) -> Result, crate::Errors> { + match validation_type { + MetaNameValueStructValidation::Custom => { + extract_generic_struct_custom_validator_from_meta_name_value(validation, message_format) + } + } + .map(WithWarnings::new) } diff --git a/serde_valid_derive/src/attribute/struct_validate/meta/meta_path.rs b/serde_valid_derive/src/attribute/struct_validate/meta/meta_path.rs index 32ee315..600fe22 100644 --- a/serde_valid_derive/src/attribute/struct_validate/meta/meta_path.rs +++ b/serde_valid_derive/src/attribute/struct_validate/meta/meta_path.rs @@ -1,5 +1,6 @@ -use crate::attribute::{ - common::message_format::MessageFormat, MetaPathStructValidation, Validator, +use crate::{ + attribute::{common::message_format::MessageFormat, MetaPathStructValidation, Validator}, + warning::WithWarnings, }; #[inline] @@ -7,6 +8,6 @@ pub fn extract_struct_validator_from_meta_path( validation_type: MetaPathStructValidation, _validation: &syn::Path, _message_format: MessageFormat, -) -> Result { +) -> Result, crate::Errors> { match validation_type {} } diff --git a/serde_valid_derive/src/attribute/variant_validate.rs b/serde_valid_derive/src/attribute/variant_validate.rs index 1e46ec2..29ee9b4 100644 --- a/serde_valid_derive/src/attribute/variant_validate.rs +++ b/serde_valid_derive/src/attribute/variant_validate.rs @@ -1,21 +1,24 @@ -mod generic; mod meta; -use crate::attribute::Validator; +use crate::{attribute::Validator, warning::WithWarnings}; use self::meta::extract_variant_validator; pub fn collect_variant_custom_from_variant( attributes: &[syn::Attribute], -) -> Result { +) -> Result, crate::Errors> { let mut errors = vec![]; + let mut warnings = vec![]; let validations = attributes .iter() .filter_map(|attribute| { if attribute.path().is_ident("validate") { match extract_variant_validator(attribute) { - Ok(validator) => Some(validator), + Ok(validator) => { + warnings.extend(validator.warnings); + Some(validator.data) + } Err(validator_error) => { errors.extend(validator_error); None @@ -28,7 +31,10 @@ pub fn collect_variant_custom_from_variant( .collect::>(); if errors.is_empty() { - Ok(Validator::from_iter(validations)) + Ok(WithWarnings::new_with_warnings( + Validator::from_iter(validations), + warnings, + )) } else { Err(errors) } diff --git a/serde_valid_derive/src/attribute/variant_validate/generic.rs b/serde_valid_derive/src/attribute/variant_validate/generic.rs deleted file mode 100644 index 49e6c40..0000000 --- a/serde_valid_derive/src/attribute/variant_validate/generic.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod custom; - -pub use custom::extract_generic_variant_custom_validator; diff --git a/serde_valid_derive/src/attribute/variant_validate/generic/custom.rs b/serde_valid_derive/src/attribute/variant_validate/generic/custom.rs deleted file mode 100644 index d3f5fe1..0000000 --- a/serde_valid_derive/src/attribute/variant_validate/generic/custom.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::attribute::common::message_format::MessageFormat; -use crate::attribute::Validator; -use crate::types::CommaSeparatedNestedMetas; -use quote::quote; - -pub fn extract_generic_variant_custom_validator( - meta_list: &syn::MetaList, - _message_format: MessageFormat, -) -> Result { - let mut errors = vec![]; - - let nested = meta_list - .parse_args_with(CommaSeparatedNestedMetas::parse_terminated) - .map_err(|error| vec![crate::Error::rule_args_parse_error(meta_list, &error)])?; - - match nested.len() { - 0 => Err(vec![ - crate::Error::validate_custom_need_function_or_closure(meta_list), - ])?, - 2.. => nested - .iter() - .skip(1) - .for_each(|error| errors.push(crate::Error::rule_allow_single_function(error))), - _ => {} - } - - let rule = match &nested[0] { - crate::types::NestedMeta::Meta(syn::Meta::Path(path)) => { - extract_variant_custom_from_meta_path(path) - } - crate::types::NestedMeta::Meta(syn::Meta::List(list)) => { - extract_variant_custom_from_meta_list(list) - } - crate::types::NestedMeta::Closure(closure) => extract_variant_custom_from_closure(closure), - _ => Err(vec![ - crate::Error::validate_custom_need_function_or_closure(&nested[0]), - ]), - }; - - match rule { - Ok(_) => { - if errors.is_empty() { - rule - } else { - Err(errors) - } - } - Err(rule_errors) => Err(errors.into_iter().chain(rule_errors).collect()), - } -} - -fn extract_variant_custom_from_meta_path( - meta_path: &syn::Path, -) -> Result { - let rule_fn_name = &meta_path; - - Ok(quote!( - if let Err(__errors) = serde_valid::validation::custom::wrap_into_vec_errors(#rule_fn_name(self)) { - __rule_vec_errors.extend(__errors); - }; - )) -} - -fn extract_variant_custom_from_meta_list( - meta_list: &syn::MetaList, -) -> Result { - Ok(quote!( - if let Err(__errors) = serde_valid::validation::custom::wrap_closure_validation(self, #meta_list) { - __rule_vec_errors.extend(__errors); - }; - )) -} - -fn extract_variant_custom_from_closure( - closure: &syn::ExprClosure, -) -> Result { - Ok(quote!( - if let Err(__errors) = serde_valid::validation::custom::wrap_closure_validation(self, #closure) { - __rule_vec_errors.extend(__errors); - }; - )) -} diff --git a/serde_valid_derive/src/attribute/variant_validate/meta.rs b/serde_valid_derive/src/attribute/variant_validate/meta.rs index 972b326..fc10b99 100644 --- a/serde_valid_derive/src/attribute/variant_validate/meta.rs +++ b/serde_valid_derive/src/attribute/variant_validate/meta.rs @@ -9,6 +9,7 @@ use crate::{ Validator, }, types::SingleIdentPath, + warning::WithWarnings, }; use quote::quote; use std::str::FromStr; @@ -19,9 +20,11 @@ use self::{ meta_path::extract_variant_validator_from_meta_path, }; -pub fn extract_variant_validator(attribute: &syn::Attribute) -> Result { +pub fn extract_variant_validator( + attribute: &syn::Attribute, +) -> Result, crate::Errors> { match &attribute.meta { - syn::Meta::Path(_) => Ok(quote!()), + syn::Meta::Path(_) => Ok(WithWarnings::new(quote!())), syn::Meta::List(list) => inner_extract_variant_validator(attribute, list), syn::Meta::NameValue(name_value) => { Err(vec![crate::Error::validate_meta_name_value_not_supported( @@ -34,7 +37,7 @@ pub fn extract_variant_validator(attribute: &syn::Attribute) -> Result Result { +) -> Result, crate::Errors> { let mut errors = vec![]; let nested = meta_list .parse_args_with(crate::types::CommaSeparatedMetas::parse_terminated) diff --git a/serde_valid_derive/src/attribute/variant_validate/meta/meta_list.rs b/serde_valid_derive/src/attribute/variant_validate/meta/meta_list.rs index 6608771..de447e6 100644 --- a/serde_valid_derive/src/attribute/variant_validate/meta/meta_list.rs +++ b/serde_valid_derive/src/attribute/variant_validate/meta/meta_list.rs @@ -1,17 +1,32 @@ -use crate::attribute::{ - common::message_format::MessageFormat, - variant_validate::generic::extract_generic_variant_custom_validator, MetaListStructValidation, - Validator, +use syn::spanned::Spanned; + +use crate::{ + attribute::{ + common::message_format::MessageFormat, + struct_validate::generic::extract_generic_struct_custom_validator_from_meta_list, + MetaListStructValidation, Validator, + }, + warning::{Warning, WithWarnings}, }; pub fn extract_variant_validator_from_meta_list( validation_type: MetaListStructValidation, validation: &syn::MetaList, message_format: MessageFormat, -) -> Result { +) -> Result, crate::Errors> { match validation_type { MetaListStructValidation::Custom => { - extract_generic_variant_custom_validator(validation, message_format) + extract_generic_struct_custom_validator_from_meta_list(validation, message_format).map( + |validator| { + WithWarnings::new_with_warnings( + validator, + vec![Warning::new_custom_meta_list_deprecated( + validation.path.get_ident().unwrap(), + validation.span(), + )], + ) + }, + ) } } } diff --git a/serde_valid_derive/src/attribute/variant_validate/meta/meta_name_value.rs b/serde_valid_derive/src/attribute/variant_validate/meta/meta_name_value.rs index 3b52bd3..3fca084 100644 --- a/serde_valid_derive/src/attribute/variant_validate/meta/meta_name_value.rs +++ b/serde_valid_derive/src/attribute/variant_validate/meta/meta_name_value.rs @@ -1,12 +1,22 @@ -use crate::attribute::{ - common::message_format::MessageFormat, MetaNameValueStructValidation, Validator, +use crate::{ + attribute::{ + common::message_format::MessageFormat, + struct_validate::generic::extract_generic_struct_custom_validator_from_meta_name_value, + MetaNameValueStructValidation, Validator, + }, + warning::WithWarnings, }; #[inline] pub fn extract_variant_validator_from_meta_name_value( validation_type: MetaNameValueStructValidation, - _validation: &syn::MetaNameValue, - _message_format: MessageFormat, -) -> Result { - match validation_type {} + validation: &syn::MetaNameValue, + message_format: MessageFormat, +) -> Result, crate::Errors> { + match validation_type { + MetaNameValueStructValidation::Custom => { + extract_generic_struct_custom_validator_from_meta_name_value(validation, message_format) + } + } + .map(WithWarnings::new) } diff --git a/serde_valid_derive/src/attribute/variant_validate/meta/meta_path.rs b/serde_valid_derive/src/attribute/variant_validate/meta/meta_path.rs index bec8f8c..a047b02 100644 --- a/serde_valid_derive/src/attribute/variant_validate/meta/meta_path.rs +++ b/serde_valid_derive/src/attribute/variant_validate/meta/meta_path.rs @@ -1,5 +1,6 @@ -use crate::attribute::{ - common::message_format::MessageFormat, MetaPathStructValidation, Validator, +use crate::{ + attribute::{common::message_format::MessageFormat, MetaPathStructValidation, Validator}, + warning::WithWarnings, }; #[inline] @@ -7,6 +8,6 @@ pub fn extract_variant_validator_from_meta_path( validation_type: MetaPathStructValidation, _validation: &syn::Path, _message_format: MessageFormat, -) -> Result { +) -> Result, crate::Errors> { match validation_type {} } diff --git a/serde_valid_derive/src/derive/enum_derive.rs b/serde_valid_derive/src/derive/enum_derive.rs index 2099a70..f9a6511 100644 --- a/serde_valid_derive/src/derive/enum_derive.rs +++ b/serde_valid_derive/src/derive/enum_derive.rs @@ -102,7 +102,7 @@ fn expand_enum_variant_named_fields_validation( rule_fields, WithWarnings { data: rules, - warnings, + mut warnings, }, ) = match collect_rules_from_named_struct(&variant.ident, &variant.attrs) { Ok(field_rules) => field_rules, @@ -113,7 +113,10 @@ fn expand_enum_variant_named_fields_validation( }; let enum_validates = match collect_variant_custom_from_variant(&input.attrs) { - Ok(validations) => TokenStream::from_iter(validations), + Ok(validations) => { + warnings.extend(validations.warnings); + TokenStream::from_iter(validations.data) + } Err(rule_errors) => { errors.extend(rule_errors); quote!() @@ -184,7 +187,7 @@ fn expand_enum_variant_unnamed_fields_varidation( rule_fields, WithWarnings { data: rules, - warnings, + mut warnings, }, ) = match collect_rules_from_unnamed_struct(&variant.ident, &variant.attrs) { Ok(field_rules) => field_rules, @@ -195,7 +198,10 @@ fn expand_enum_variant_unnamed_fields_varidation( }; let enum_validates = match collect_variant_custom_from_variant(&input.attrs) { - Ok(validations) => TokenStream::from_iter(validations), + Ok(validations) => { + warnings.extend(validations.warnings); + TokenStream::from_iter(validations.data) + } Err(rule_errors) => { errors.extend(rule_errors); quote!() diff --git a/serde_valid_derive/src/error.rs b/serde_valid_derive/src/error.rs index 7c764f5..03df7c8 100644 --- a/serde_valid_derive/src/error.rs +++ b/serde_valid_derive/src/error.rs @@ -377,7 +377,7 @@ impl Error { ) } - pub fn validate_custom_need_function_or_closure(span: impl Spanned) -> Self { + pub fn validate_custom_meta_list_need_function_or_closure(span: impl Spanned) -> Self { Self::new( span.span(), "#[validate(custom(???))] needs function or closure.", @@ -391,6 +391,13 @@ impl Error { ) } + pub fn validate_custom_meta_name_value_need_function_or_closure(span: impl Spanned) -> Self { + Self::new( + span.span(), + "#[validate(custom = ???)] needs function or closure.", + ) + } + pub fn custom_message_parse_error(ident: &syn::Ident, error: &syn::Error) -> Self { Self::new( ident.span(), diff --git a/serde_valid_derive/src/warning.rs b/serde_valid_derive/src/warning.rs index b634cc6..29579f9 100644 --- a/serde_valid_derive/src/warning.rs +++ b/serde_valid_derive/src/warning.rs @@ -18,6 +18,10 @@ impl WithWarnings { } } + pub fn new_with_warnings(data: T, warnings: Vec) -> Self { + Self { data, warnings } + } + pub fn from_iter(data: impl IntoIterator>) -> WithWarnings> { let mut warnings = vec![]; let data = data @@ -103,7 +107,7 @@ impl Warning { } } - pub fn new_enumerate_path_deprecated(ident: &syn::Ident, span: Span) -> Self { + pub fn new_enumerate_meta_list_deprecated(ident: &syn::Ident, span: Span) -> Self { Self::Deprecated { ident: ident.clone(), note: "#[validate(enumerate(...))] is deprecated, please use #[validate(enumerate = [...])] instead." @@ -112,6 +116,15 @@ impl Warning { } } + pub fn new_custom_meta_list_deprecated(ident: &syn::Ident, span: Span) -> Self { + Self::Deprecated { + ident: ident.clone(), + note: "#[validate(custom(...))] is deprecated, please use #[validate(custom = ...)] instead." + .to_string(), + span, + } + } + pub fn add_index(&self, index: usize) -> Self { match self { Self::Deprecated { ident, note, span } => Self::Deprecated {