Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Implement Matcher for std::sync::LazyLock<T> #131

Merged
merged 3 commits into from
Dec 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,6 @@ Contributing to `garde` only requires a somewhat recent version of [`Rust`](http

This repository also makes use of the following tools, but they are optional:
- [`insta`](https://insta.rs/) for snapshot testing ([tests/rules](./garde_derive_tests/tests/rules/)).
- [`just`](https://just.systems/) for running recipes defined in the [`justfile`](./justfile).
Run `just -l` to see what recipes are available.

### License

Expand Down
39 changes: 32 additions & 7 deletions garde/src/rules/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,22 @@
//! ```
//!
//! Alternatively, it can be an expression of type implementing [`Matcher`] or one that dereferences to a [`Matcher`].
//! [`Matcher`] is implemented for `regex::Regex` (if the `regex` feature is enabled) and `once_cell::sync::Lazy<T>` with any `T: Matcher`.
//! [`Matcher`] is implemented for `regex::Regex` (if the `regex` feature is enabled) and `std::sync::LazyLock<T>` / `once_cell::sync::Lazy<T>` with any `T: Matcher`.
//! Please note that the expression will be evaluated each time `validate` is called, so avoid doing any expensive work in the expression.
//! If the work is unavoidable, at least try to amortize it, such as by using `once_cell::Lazy` or the nightly-only `std::sync::LazyLock`.
//! If the work is unavoidable, at least try to amortize it, such as by using `std::sync::LazyLock` or `once_cell::Lazy`.
//!
//! ```rust
//! use std::sync::LazyLock;
//! use regex::Regex;
//!
//! static LAZY_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"[a-zA-Z0-9][a-zA-Z0-9_]+").unwrap());
//!
//! #[derive(garde::Validate)]
//! struct Test {
//! #[garde(pattern(LAZY_RE))]
//! v: String,
//! }
//! ```
//!
//! ```rust
//! use once_cell::sync::Lazy;
Expand Down Expand Up @@ -50,6 +63,18 @@ pub trait Matcher: AsStr {
fn is_match(&self, haystack: &str) -> bool;
}

impl<T: Matcher> Matcher for std::sync::LazyLock<T> {
fn is_match(&self, haystack: &str) -> bool {
std::sync::LazyLock::force(self).is_match(haystack)
}
}

impl<T: AsStr> AsStr for std::sync::LazyLock<T> {
fn as_str(&self) -> &str {
std::sync::LazyLock::force(self).as_str()
}
}

pub trait Pattern {
fn validate_pattern<M: Matcher>(&self, matcher: &M) -> bool;
}
Expand Down Expand Up @@ -77,7 +102,7 @@ impl<T: Pattern> Pattern for Option<T> {
))]
#[doc(hidden)]
pub mod regex_js_sys {
pub use ::js_sys::RegExp;
pub use js_sys::RegExp;

use super::*;

Expand Down Expand Up @@ -117,7 +142,7 @@ pub mod regex_js_sys {
unsafe impl<T> Send for SyncWrapper<T> {}
unsafe impl<T> Sync for SyncWrapper<T> {}

pub type StaticPattern = once_cell::sync::Lazy<SyncWrapper<RegExp>>;
pub type StaticPattern = std::sync::LazyLock<SyncWrapper<RegExp>>;

#[macro_export]
macro_rules! __init_js_sys_pattern {
Expand All @@ -134,9 +159,9 @@ pub mod regex_js_sys {
#[cfg(feature = "regex")]
#[doc(hidden)]
pub mod regex {
pub use ::regex::Regex;
pub use regex::Regex;

use super::*;
use super::{AsStr, Matcher};

impl Matcher for Regex {
fn is_match(&self, haystack: &str) -> bool {
Expand All @@ -162,7 +187,7 @@ pub mod regex {
}
}

pub type StaticPattern = once_cell::sync::Lazy<Regex>;
pub type StaticPattern = std::sync::LazyLock<Regex>;

#[macro_export]
macro_rules! __init_pattern {
Expand Down
12 changes: 11 additions & 1 deletion garde/tests/rules/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ use regex::Regex;
use super::util;

mod sub {
use std::sync::LazyLock;

use once_cell::sync::Lazy;

use super::*;

pub static LAZY_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^abcd|efgh$").unwrap());
pub static LAZY_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"^abcd|efgh$").unwrap());
pub static LAZY_RE_ONCE_CELL: Lazy<Regex> = Lazy::new(|| Regex::new(r"^abcd|efgh$").unwrap());
}

#[derive(Debug, garde::Validate)]
Expand All @@ -18,6 +21,9 @@ struct Test<'a> {
#[garde(pattern(sub::LAZY_RE))]
field_path: &'a str,

#[garde(pattern(sub::LAZY_RE_ONCE_CELL))]
field_path_once_cell: &'a str,

#[garde(pattern(create_regex()))]
field_call: &'a str,

Expand Down Expand Up @@ -46,12 +52,14 @@ fn pattern_valid() {
Test {
field: "abcd",
field_path: "abcd",
field_path_once_cell: "abcd",
field_call: "abcd",
inner: &["abcd"],
},
Test {
field: "efgh",
field_path: "efgh",
field_path_once_cell: "abcd",
field_call: "efgh",
inner: &["efgh"],
},
Expand All @@ -68,12 +76,14 @@ fn pattern_invalid() {
Test {
field: "dcba",
field_path: "dcba",
field_path_once_cell: "abcd",
field_call: "dcba",
inner: &["dcba"]
},
Test {
field: "hgfe",
field_path: "hgfe",
field_path_once_cell: "abcd",
field_call: "hgfe",
inner: &["hgfe"]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ expression: snapshot
Test {
field: "dcba",
field_path: "dcba",
field_path_once_cell: "abcd",
field_call: "dcba",
inner: [
"dcba",
Expand All @@ -18,6 +19,7 @@ inner[0]: does not match pattern /^abcd|efgh$/
Test {
field: "hgfe",
field_path: "hgfe",
field_path_once_cell: "abcd",
field_call: "hgfe",
inner: [
"hgfe",
Expand All @@ -27,5 +29,3 @@ field: does not match pattern /^abcd|efgh$/
field_call: does not match pattern /^abcd|efgh$/
field_path: does not match pattern /^abcd|efgh$/
inner[0]: does not match pattern /^abcd|efgh$/


Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ error[E0277]: the trait bound `&str: Matcher` is not satisfied
| ^^^ the trait `Matcher` is not implemented for `&str`
|
= help: the following other types implement trait `Matcher`:
LazyLock<T>
Regex
once_cell::sync::Lazy<T>
note: required by a bound in `garde::rules::pattern::apply`
Expand Down
Loading