Skip to content

Commit

Permalink
Merge pull request #143 from lasantosr/dive-context
Browse files Browse the repository at this point in the history
Allow an optional context when using dive
  • Loading branch information
jprochazk authored Jan 19, 2025
2 parents e030e5b + ecd9bac commit 395a85d
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 8 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ if let Err(e) = data.validate() {

Additional notes:
- `required` is only available for `Option` fields.
- `dive` accepts an optional context: `#[garde(dive(self.other_field))]`
- The `<mode>` argument for `length` is [explained here](#length-modes)
- For `length` and `range`:
- If `equal` is defined, `min` and `max` must be omitted.
Expand Down
53 changes: 53 additions & 0 deletions garde/tests/rules/dive_with_ctx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use super::util;

#[derive(Clone, Copy, Debug, garde::Validate)]
#[garde(context((usize, usize) as ctx))]
struct Inner<'a> {
#[garde(length(min = ctx.0, max = ctx.1))]
field: &'a str,
}

#[derive(Debug, garde::Validate)]
struct Test<'a> {
#[garde(skip)]
min: usize,
#[garde(skip)]
max: usize,
#[garde(dive((self.min, self.max)))]
inner: Inner<'a>,
}

#[derive(Debug, garde::Validate)]
#[garde(context((usize, usize)))]
struct Test2<'a> {
#[garde(dive)]
inner: Inner<'a>,
}

#[test]
fn valid() {
let inner = Inner { field: "asdf" };
util::check_ok(&[Test2 { inner }], &(1, 5));
util::check_ok(
&[Test {
min: 1,
max: 5,
inner,
}],
&(),
);
}

#[test]
fn invalid() {
let inner = Inner { field: "asdfgh" };
util::check_fail!(&[Test2 { inner }], &(1, 5));
util::check_fail!(
&[Test {
min: 1,
max: 5,
inner,
}],
&(),
);
}
1 change: 1 addition & 0 deletions garde/tests/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod contains;
mod credit_card;
mod custom;
mod dive;
mod dive_with_ctx;
mod dive_with_rules;
mod email;
mod inner;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
source: garde/tests/./rules/dive_with_ctx.rs
expression: snapshot
snapshot_kind: text
---
Test {
min: 1,
max: 5,
inner: Inner {
field: "asdfgh",
},
}
inner.field: length is greater than 5
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
source: garde/tests/./rules/dive_with_ctx.rs
expression: snapshot
snapshot_kind: text
---
Test2 {
inner: Inner {
field: "asdfgh",
},
}
inner.field: length is greater than 5
4 changes: 2 additions & 2 deletions garde_derive/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ fn check_field(field: model::Field, options: &model::Options) -> syn::Result<mod
}
}

if let Some(span) = field.dive {
if let Some((span, _)) = field.dive {
if field.rule_set.inner.is_some() {
error.maybe_fold(syn::Error::new(
span,
Expand Down Expand Up @@ -339,7 +339,7 @@ fn check_rule(
Rename(alias) => apply!(alias = alias.value, span),
// Message(message) => apply!(message = message, span),
Code(code) => apply!(code = code.value, span),
Dive => apply!(dive = span, span),
Dive(ctx) => apply!(dive = (span, ctx), span),
Custom(custom) => rule_set.custom_rules.push(custom),
Required => apply!(Required(), span),
Ascii => apply!(Ascii(), span),
Expand Down
10 changes: 9 additions & 1 deletion garde_derive/src/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,14 +381,22 @@ where
false => None,
};
let inner = match (&field.dive, &field.rule_set.inner) {
(Some(..), None) => Some(quote! {
(Some((_, None)), None) => Some(quote! {
::garde::validate::Validate::validate_into(
&*__garde_binding,
__garde_user_ctx,
&mut __garde_path,
__garde_report,
);
}),
(Some((_, Some(ctx))), None) => Some(quote! {
::garde::validate::Validate::validate_into(
&*__garde_binding,
&#ctx,
&mut __garde_path,
__garde_report,
);
}),
(None, Some(inner)) => Some(
Inner {
rules_mod,
Expand Down
4 changes: 2 additions & 2 deletions garde_derive/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub enum RawRuleKind {
Rename(Str),
// Message(Message),
Code(Str),
Dive,
Dive(Option<Expr>),
Required,
Ascii,
Alphanumeric,
Expand Down Expand Up @@ -184,7 +184,7 @@ pub struct ValidateField {
// pub message: Option<Message>,
pub code: Option<String>,

pub dive: Option<Span>,
pub dive: Option<(Span, Option<Expr>)>,
pub rule_set: RuleSet,
}

Expand Down
20 changes: 17 additions & 3 deletions garde_derive/src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,18 +251,32 @@ impl Parse for model::RawRule {

macro_rules! rules {
(($input:ident, $ident:ident) {
$($name:literal => $rule:ident $(($content:ident))?,)*
$($name:literal => $rule:ident $(($content:ident))? $(( ? $content_opt:ident))?,)*
}) => {
match $ident.to_string().as_str() {
$(
$name => {
$(
let $content;
syn::parenthesized!($content in $input);
let $content = $content.parse()?;
)?
$(
let $content_opt = if $input.peek(syn::token::Paren) {
let $content_opt;
syn::parenthesized!($content_opt in $input);
if $content_opt.is_empty() {
None
} else {
Some($content_opt.parse()?)
}
} else {
None
};
)?
Ok(model::RawRule {
span: $ident.span(),
kind: model::RawRuleKind::$rule $(($content.parse()?))?
kind: model::RawRuleKind::$rule $(($content))? $(($content_opt))?
})
}
)*
Expand All @@ -278,7 +292,7 @@ impl Parse for model::RawRule {
"rename" => Rename(content),
// "message" => Message(content),
"code" => Code(content),
"dive" => Dive,
"dive" => Dive(? content),
"required" => Required,
"ascii" => Ascii,
"alphanumeric" => Alphanumeric,
Expand Down

0 comments on commit 395a85d

Please sign in to comment.