Skip to content

Commit

Permalink
Improve generics with lifetimes
Browse files Browse the repository at this point in the history
  • Loading branch information
greyblake committed Jun 1, 2024
1 parent 7aa7a8a commit 6aa60e0
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 10 deletions.
6 changes: 3 additions & 3 deletions dummy/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use nutype::nutype;
use std::borrow::Cow;

#[nutype(
sanitize(with = |v| v),
validate(predicate = |v| !v.is_empty() )
validate(predicate = |s| s.len() >= 3),
)]
struct NonEmptyVec<T>(Vec<T>);
struct Clarabelle<'a>(Cow<'a, str>);

fn main() {}
7 changes: 2 additions & 5 deletions examples/any_generics/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ use std::borrow::Cow;
)]
struct NotEmpty<T>(Vec<T>);

#[nutype(
derive(Debug),
validate(predicate = |s| s.len() >= 3),
)]
#[nutype(derive(Debug))]
struct Clarabelle<'b>(Cow<'b, str>);

fn main() {
Expand All @@ -24,7 +21,7 @@ fn main() {
}

{
let c1 = Clarabelle::new(Cow::Borrowed("Muu")).unwrap();
let c1 = Clarabelle::new(Cow::Borrowed("Muu"));
assert_eq!(c1.into_inner(), Cow::Borrowed("Muu"));
}
}
17 changes: 15 additions & 2 deletions nutype_macros/src/any/gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl GenerateNewtype for AnyNewtype {
.map(|validator| match validator {
AnyValidator::Predicate(predicate) => {
let inner_type_ref: syn::Type = parse_quote!(
&'a #inner_type
&'nutype_a #inner_type
);
let typed_predicate: TypedCustomFunction = predicate
.clone()
Expand All @@ -88,7 +88,20 @@ impl GenerateNewtype for AnyNewtype {
.collect();

quote!(
fn __validate__<'a>(val: &'a #inner_type) -> ::core::result::Result<(), #error_name> {
// NOTE 1: we're using a unique lifetime name `nutype_a` in a hope that it will not clash
// with any other lifetimes in the user's code.
//
// NOTE 2:
// When inner type is Cow<'a, str>, the generated code will look like this (with 2
// lifetimes):
//
// fn __validate__<'nutype_a>(val: &'nutype_a Cow<'a, str>)
//
// Clippy does not like passing a reference to a Cow. So we need to ignore the `clippy::ptr_arg` warning.
// Since this code is generic which is used for different inner types (not only Cow), we cannot easily fix it to make
// clippy happy.
#[allow(clippy::ptr_arg)]
fn __validate__<'nutype_a>(val: &'nutype_a #inner_type) -> ::core::result::Result<(), #error_name> {
#validations
Ok(())
}
Expand Down
20 changes: 20 additions & 0 deletions test_suite/tests/any.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use nutype::nutype;
use std::borrow::Cow;
use test_suite::test_helpers::traits::*;

// Inner custom type, which is unknown to nutype
Expand Down Expand Up @@ -482,4 +483,23 @@ mod with_generics {
// assert_eq!(err, NonEmptyVecError::PredicateViolated);
// }
// }

#[test]
fn test_generic_with_lifetime_cow() {
#[nutype(
validate(predicate = |s| s.len() >= 3),
derive(Debug)
)]
struct Clarabelle<'a>(Cow<'a, str>);

{
let clarabelle = Clarabelle::new(Cow::Borrowed("Clarabelle")).unwrap();
assert_eq!(clarabelle.into_inner(), Cow::Borrowed("Clarabelle"));
}

{
let err = Clarabelle::new(Cow::Borrowed("Mu")).unwrap_err();
assert_eq!(err, ClarabelleError::PredicateViolated);
}
}
}

0 comments on commit 6aa60e0

Please sign in to comment.