Skip to content

Commit

Permalink
Merge pull request #24 from yassun7010/support
Browse files Browse the repository at this point in the history
feat: support closure.
  • Loading branch information
yassun7010 authored Jan 7, 2024
2 parents a5370d2 + a5db458 commit 52d0f6d
Show file tree
Hide file tree
Showing 9 changed files with 321 additions and 74 deletions.
62 changes: 62 additions & 0 deletions serde_valid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,26 @@ let s = SampleStruct { val: 1 };
assert!(s.validate().is_ok());
```

And you can also use closure.

```rust
use serde_valid::Validate;

fn user_validation(_val: &i32, param1: bool) -> Result<(), serde_valid::validation::Error> {
Ok(())
}

#[derive(Validate)]
struct SampleStruct {
#[validate(custom(|v| user_validation(v, true)))]
val: i32,
}

let s = SampleStruct { val: 1 };

assert!(s.validate().is_ok());
```

## Rules

If you want to check multi fields validation, can use `#[rule]`.
Expand Down Expand Up @@ -235,6 +255,48 @@ let s = SampleStruct(0, "1".to_owned());
assert!(s.validate().is_ok());
```

And you can also use closure.

```rust
use serde_json::json;
use serde_valid::Validate;

fn sample_rule(_val1: &i32, _val2: &str) -> Result<(), serde_valid::validation::Error> {
Ok(())
}

#[derive(Validate)]
#[rule(|val1, val2| sample_rule(val2, val1))]
struct SampleStruct {
val1: String,
val2: i32,
}

let s = SampleStruct {
val1: "val1".to_owned(),
val2: 1,
};

assert!(s.validate().is_ok());
```

```rust
use serde_json::json;
use serde_valid::Validate;

fn sample_rule(_val1: &i32, _val2: &str) -> Result<(), serde_valid::validation::Error> {
Ok(())
}

#[derive(Validate)]
#[rule(|_0, _1| sample_rule(_0, _1))]
struct SampleStruct(i32, String);

let s = SampleStruct(0, "1".to_owned());

assert!(s.validate().is_ok());
```

## Validate Traits

By implementing the validation trait, Your original type can uses Serde Valid validations.
Expand Down
42 changes: 42 additions & 0 deletions serde_valid/tests/custom_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,48 @@ fn custom_parenthesized_path_validation_is_ok() {
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<i32>,
}

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<i32>,
}

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> {
Expand Down
56 changes: 56 additions & 0 deletions serde_valid/tests/rule_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ fn sample_ok_rule2(_val1: &i32, _val2: &str) -> Result<(), serde_valid::validati
Ok(())
}

fn sample_ok_rule3(
_val1: &i32,
_val2: &str,
_val3: bool,
) -> Result<(), serde_valid::validation::Error> {
Ok(())
}

fn sample_err_rule(_val1: &i32, _val2: &str) -> Result<(), serde_valid::validation::Error> {
Err(serde_valid::validation::Error::Custom(
"Rule error.".to_owned(),
Expand Down Expand Up @@ -112,3 +120,51 @@ fn rule_enum_is_ok() {
let s4 = TestEnum::NoField;
assert!(s4.validate().is_ok());
}

#[test]
fn rule_closure_struct_named_fields_is_ok() {
#[derive(Validate)]
#[rule(|val| sample_ok_rule2(val, "abcd"))]
struct TestStruct {
val: i32,
}

let s = TestStruct { val: 5 };
assert!(s.validate().is_ok());
}

#[test]
fn rule_clousure2_struct_named_fields_is_ok() {
#[derive(Validate)]
#[rule(|val1, val2| sample_ok_rule3(val1, val2, true))]
struct TestStruct {
val1: i32,
val2: String,
}

let s = TestStruct {
val1: 5,
val2: "val2".to_owned(),
};
assert!(s.validate().is_ok());
}

#[test]
fn rule_closure_struct_unnamed_fields_is_ok() {
#[derive(Validate)]
#[rule(|_0| sample_ok_rule2(_0, "abcd"))]
struct TestStruct(i32);

let s = TestStruct(5);
assert!(s.validate().is_ok());
}

#[test]
fn rule_clousure2_struct_unnamed_fields_is_ok() {
#[derive(Validate)]
#[rule(|_0, _1| sample_ok_rule3(_0, _1, true))]
struct TestStruct(i32, String);

let s = TestStruct(5, "val2".to_owned());
assert!(s.validate().is_ok());
}
54 changes: 30 additions & 24 deletions serde_valid_derive/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::validate::{
MetaPathValidation,
};
use proc_macro2::TokenStream;
use quote::quote;
use quote::{quote, ToTokens};
use syn::spanned::Spanned;

use crate::validate::MetaListCustomMessage;
Expand Down Expand Up @@ -169,12 +169,12 @@ impl Error {
Self::new(input.span(), "#[derive(Validate)] does not support Union.")
}

pub fn rule_need_function(path: &syn::Path) -> Self {
Self::new(path.span(), "#[rule(???)] needs rule_fn.")
pub fn rule_allow_function_call_or_closure(span: impl Spanned) -> Self {
Self::new(span.span(), "#[rule(???)] allows function call or closure.")
}

pub fn rule_allow_single_function(meta: &syn::Meta) -> Self {
Self::new(meta.span(), "#[rule] allows single function.")
pub fn rule_allow_single_function(meta: &crate::types::NestedMeta) -> Self {
Self::new(meta.span(), "#[rule(???)] allows single function.")
}

pub fn rule_need_arguments(path: &syn::Path) -> Self {
Expand All @@ -188,25 +188,36 @@ impl Error {
)
}

pub fn rule_allow_path_arguments(
pub fn rule_args_allow_field_name(
rule_fn_name_path: &syn::Path,
meta: &syn::punctuated::Punctuated<syn::Path, syn::Token![,]>,
meta: &crate::types::NestedMeta,
) -> Self {
let rule_fn_name = quote!(#rule_fn_name_path).to_string();
Self::new(
meta.span(),
format!("#[rule({rule_fn_name}(???, ...))] allows field path only."),
format!("#[rule({rule_fn_name}(???, ...))] allows field name only."),
)
}

pub fn rule_allow_index_arguments(
pub fn rule_args_allow_field_index(
rule_fn_name_path: &syn::Path,
meta: &crate::types::NestedMeta,
) -> Self {
let rule_fn_name = quote!(#rule_fn_name_path).to_string();
Self::new(
meta.span(),
format!("#[rule({rule_fn_name}(???, ...))] allows index integer only."),
format!("#[rule({rule_fn_name}(???, ...))] allows field index only."),
)
}

pub fn rule_named_clousure_input(meta: &syn::Pat) -> Self {
Self::new(meta.span(), "Inputs of closure allows filed name only.")
}

pub fn rule_unnamed_clousure_input(meta: &syn::Pat) -> Self {
Self::new(
meta.span(),
"Inputs of closure allows field index (like _0, _1, etc...) only.",
)
}

Expand Down Expand Up @@ -328,8 +339,8 @@ impl Error {
Self::new(path.span(), "#[validate(enumerate(???))] needs items.")
}

pub fn validate_custom_need_function(path: &syn::Path) -> Self {
Self::new(path.span(), "#[validate(custom(???))] needs function.")
pub fn validate_custom_need_function(span: impl Spanned) -> Self {
Self::new(span.span(), "#[validate(custom(???))] needs function.")
}

pub fn validate_custom_tail_error(nested: &crate::types::NestedMeta) -> Self {
Expand Down Expand Up @@ -403,12 +414,8 @@ impl Error {
)
}

pub fn literal_only(expr: &syn::Expr) -> Self {
Self::new(expr.span(), "Allow literal only.")
}

pub fn literal_only_from_meta(meta: &syn::Meta) -> Self {
Self::new(meta.span(), "Allow literal only.")
pub fn literal_only(span: impl Spanned) -> Self {
Self::new(span.span(), "Allow literal only.")
}

pub fn numeric_literal_only(lit: &syn::Lit) -> Self {
Expand All @@ -423,12 +430,11 @@ impl Error {
Self::new(lit.span(), "Literal not support.")
}

pub fn meta_name_value_not_support(name_value: &syn::MetaNameValue) -> Self {
Self::new(name_value.span(), "Name value not support.")
}

pub fn meta_path_not_support(path: &syn::Path) -> Self {
Self::new(path.span(), "Path not support.")
pub fn closure_not_support(closure: &syn::ExprClosure) -> Self {
Self::new(
closure.or1_token.span(),
format!("Closure not support. {}", closure.to_token_stream()),
)
}

pub fn too_many_list_items(nested_meta: &syn::Meta) -> Self {
Expand Down
Loading

0 comments on commit 52d0f6d

Please sign in to comment.