Skip to content

Releases: jprochazk/garde

v0.18.0

28 Jan 12:17
Compare
Choose a tag to compare

There are quite a few changes in this release:

  • Length modes in #88
  • Adapters in #93
  • Remove default features, replace with full in #95
  • Serialize/deserialize Report in #90
  • Remove empty colon from display impl of Report in #91

Some of these are breaking changes. If you are only using the derive functionality and calling validate, updating should still be as simple as a version bump:

cargo add garde@0.18 -F full

If it isn't, please open an issue!

Length modes

You can now specify what kind of length you wish to validate by adding a new mode argument to your length rules. The argument is optional.

#[derive(garde::Validate)]
#[garde(transparent)]
struct Username(
    #[garde(
        length(bytes, min = 1, max = 100),
        length(graphemes, min = 1, max = 25)
    )]
    String
);

The above validates both bytes (via v.len()) and graphemes (via v.graphemes().count() using the unicode-segmentation crate. To understand why the distinction is important, consider the xΜ§Μ‘Μ¬Μ˜Ν“Μ–Μ²Μ»Μ»Μ²Μ ΜͺΜ»Ν“Ν™ΜœΜ‚Μ“ΜŠΜ”Μ€Μ€Ν—Μ‘Μ€Μ…Μ€Μ‚ΜšΝ˜Μ•ΜšΝ˜Ν’ΝœΝ  character, which occupies 73 bytes in memory, but is considered a single grapheme.

The available modes are:

  • simple, which is the default, and its behavior depends on the type. For strings, it measures the number of bytes, and for collections (such as Vec), it meaures the number of items.
  • bytes, which uses s.len(), measuring the number of bytes,
  • graphemes, which uses s.graphemes(true).count(), measuring the number of graphemes
  • chars, which uses s.chars().count(), measuring the number of unicode scalar values
  • utf16, which uses s.encode_utf16().count(), measuring the number of UTF-16 code units

The original Length and HasLength traits have been removed, and replaced by one trait per length mode.

Adapters

Using adapters, it is possible to implement validation rules for 3rd-party types directly in your own crates.

mod my_str_adapter {
    #![allow(unused_imports)]
    pub use garde::rules::*; // re-export garde's rules

    pub mod length {
        pub use garde::rules::length::*; // re-export `length` rules

        pub mod simple {
            // re-implement `simple`, but _only_ for the concrete type &str!
            pub fn apply(v: &str, (min, max): (usize, usize)) -> garde::Result {
                if !(min..=max).contains(&v.len()) {
                    Err(garde::Error::new("my custom error message"))
                } else {
                    Ok(())
                }
            }
        }
    }
}

Adapters are applied using the adapt field-level attribute:

#[derive(garde::Validate)]
struct Stuff<'a> {
    #[garde(
        adapt(my_str_adapter),
        length(min = 1),
        ascii,
    )]
    v: &'a str,
}

Now my_str_adapter::length::simple will be used instead of garde::rules::length::simple when validating the above type, removing the need for a newtype over str!

full feature

Having default features for a crate such as garde means that downstream users are more likely to end up with those default features in their lockfile with no way to turn them off, resulting in increased compile times in exchange for no benefit. Due to this, the default feature from garde has been removed, and we now have a new full feature which contains everything from the removed default feature.

To retain all the features previously in default, enable the full feature when you update:

cargo add garde@0.18 -F full

I urge you to consider if you really need all of full, though! There may be parts you're not using, and taking a few minutes to see what is the minimum feature set with which your project compiles is definitely worth it.

Miscellaneous

  • The Report type now has implementations of serde::Deserialize and serde::Serialize when the serde feature is enabled. Note that the implementation of Serialize has been updated to make it possible to implement a lossless serialize -> deserialize roundtrip, which is a breaking change if you were doing something with the serialized reports.

  • Validation errors on newtypes previously looked like this:

    : length is lower than 1
    

    This is because newtypes report their errors with an empty path, resulting in a lone : in the error message. This has now been fixed, and will report as:

    length is lower than 1
    

Full changelog

v0.17.0...v0.18.0

v0.17.0

04 Jan 23:18
Compare
Choose a tag to compare

What's Changed

  • fix: unsealed PathComponentKind to allow custom key types in garde. by @Wicpar in #81
  • Update axum to 0.7 by @dpytaylo in #85

New Contributors

Full Changelog: v0.16.3...v0.17.0

v0.16.3

26 Nov 15:55
Compare
Choose a tag to compare

Smaller Wasm bundles via js-sys

If the js-sys feature is enabled, #[garde(pattern)] will now use js_sys::RegExp instead of regex::Regex on the wasm32-unknown-unknown target. This usually means massive bundle size savings depending on which features you need. The two regex implementations aren't fully compatible, which is why it is opt-in via a feature.

Contributed by @aumetra in #77

Support for newtypes

#[derive(garde::Validate)]
#[garde(transparent)]
struct Username(#[garde(length(min = 3, max = 20))] String);

#[derive(garde::Validate)]
struct User {
    // later used with `dive`:
    #[garde(dive)]
    username: Username,
}

See README.md for more information.

Breaking changes

There were no breaking changes in this release.

Full Changelog: v0.16.2...v0.16.3

v0.16.2

28 Oct 23:05
Compare
Choose a tag to compare

What's Changed

Full Changelog: v0.16.1...v0.16.2

v0.16.1

26 Oct 12:22
Compare
Choose a tag to compare

Changes

  • Removed #[doc(hidden)] from garde::error::NoKey

Full Changelog: v0.16.0...v0.16.1

v0.16.0

18 Oct 07:23
Compare
Choose a tag to compare

What's Changed

Breaking changes

The garde::error::Kind enum has a new variant, None.

New Contributors

Full Changelog: v0.15.0...v0.16.0

v0.15.0

09 Sep 11:33
Compare
Choose a tag to compare

Breaking changes

  • garde::error has been completely overhauled.
  • garde::Validate has a new validate_into method, which is the primary entrypoint for custom implementations now.
  • garde::Validate::validate is now implemented by default by calling validate_into.

These changes should not have any significant effects on the usage of the library, if all you're doing is deriving Validate and serializing errors using the Display implementation on Errors (now called Report). If you're having trouble migrating, please open an issue.

New features

You can now easily select! errors for specific fields on a given Report:

#[derive(garde::Validate)]
struct Foo<'a> {
  #[garde(dive)]
  bar: Bar<'a>,
}

#[derive(garde::Validate)]
struct Bar<'a> {
  #[garde(length(min = 1))]
  value: &'a str,
}

let v = Foo { bar: Bar { value: "" } };
let report = v.validate(&()).unwrap_err();

println!("errors for `Foo.bar.value`");
for error in garde::error::select!(report, bar.value) {
  println!("{error}");
}

Pull requests

Full Changelog: v0.14.1...v0.15.0

v0.14.1

25 Aug 09:30
Compare
Choose a tag to compare

What's Changed

#65 by @aumetra

You can now bind the context to a variable, and the length and byte_length rules min and max values may now contain arbitrary expressions. This means the following is now possible:

struct Config {
    min_length: usize,
}

#[derive(garde::Validate)]
#[garde(context(Config as conf))]
struct Foo {
    #[garde(length(
        min = conf.min_length,
        max = self.baz.len()
    ))]
    bar: String,
    #[garde(skip)]
    baz: String,
}

New Contributors

Full Changelog: v0.14.0...v0.14.1

v0.14.0

01 Aug 15:35
Compare
Choose a tag to compare

New features

Thanks to @jirutka for contributing the following features.

Widening the scope of valid values for prefix, suffix, and contains

You can now use constants, functions, concat!, or any other expression in prefix, suffix, and contains:

const PREFIX: &str = "a";
const SUFFIX: &str = "b";
const INNER: &str = "c";

#[derive(garde::Validate)]
struct Test<'a> {
    #[garde(prefix(PREFIX), contains(INNER), suffix(SUFFIX))]
    v: &'a str,
}

Abstracting away regex

regex is now an optional feature, and you can bring your own Regex when using the pattern rule:

use once_cell::sync::Lazy;
use regex::Regex;

static PATTERN: Lazy<Regex> = Lazy::new(|| Regex::new(r"a|b").unwrap());

#[derive(garde::Validate)]
struct Test<'a> {
    #[garde(pattern(PATTERN))]
    v: &'a str,
}

Note that usage of pattern with a string literal requires the regex feature. It won't compile without it.

With the introduction of the Matcher trait, you can now use other regex engines, such as regex-lite. All you need to do is wrap the Regex type in a newtype, and implement Matcher on it.

Breaking changes

  • The pattern rule now accepts any expression which derefs to a Regex (such as once_cell::sync::Lazy<regex::Regex>). This change meant changing the Pattern trait, and introducing a new trait, Matcher, to abstract the specific regex engine used.

Pull requests

  • Allow pattern, contains, prefix and suffix accept expression by @jirutka in #56
  • Abstract from Regex in pattern validator and add support for regex-lite by @jirutka in #57

Full Changelog: v0.13.0...v0.14.0

v0.13.0

28 Jul 10:42
Compare
Choose a tag to compare

What's Changed

  • Fixed range rule on Option fields #55
  • Disable unnecessary/unused regex features by @jirutka in #54

New Contributors

Full Changelog: v0.12.0...v0.13.0