From cbac1bced03fb365016fd6a2f766afa0f06c2f84 Mon Sep 17 00:00:00 2001 From: Sergey Potapov Date: Sun, 15 Oct 2023 15:34:52 +0200 Subject: [PATCH 1/4] Setup very first example with CI --- .github/workflows/ci.yml | 19 +++++++++++++++++ Cargo.lock | 7 ++++++ Cargo.toml | 1 + Justfile | 8 ++++++- examples/float_sortable/Cargo.toml | 8 +++++++ examples/float_sortable/src/main.rs | 33 +++++++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 examples/float_sortable/Cargo.toml create mode 100644 examples/float_sortable/src/main.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c25a476..a64c5a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,3 +91,22 @@ jobs: with: command: clippy args: -- -D warnings + + examples: + name: Examples + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: clippy + + - name: Run examples + run: | + for example in $(ls ./examples/); do + echo $example + done diff --git a/Cargo.lock b/Cargo.lock index e6c9a00..d6b9fa9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,6 +103,13 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" +[[package]] +name = "float_sortable" +version = "0.1.0" +dependencies = [ + "nutype", +] + [[package]] name = "glob" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index 116e41a..e56d3d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,5 @@ members = [ "nutype_macros", "test_suite", "dummy", + "examples/*", ] diff --git a/Justfile b/Justfile index 67d7150..e9dc7b6 100644 --- a/Justfile +++ b/Justfile @@ -1,4 +1,4 @@ -all: test-all clippy +all: fmt test-all clippy examples test-all: cargo test --features nutype_test @@ -14,6 +14,9 @@ test: test-ui: cargo test --features nutype_test,ui +fmt: + cargo fmt + watch: cargo watch -x test @@ -22,3 +25,6 @@ watch-dummy: clippy: cargo clippy -- -D warnings + +examples: + for example in `ls examples`; do cargo run --bin $example; done diff --git a/examples/float_sortable/Cargo.toml b/examples/float_sortable/Cargo.toml new file mode 100644 index 0000000..8b4b441 --- /dev/null +++ b/examples/float_sortable/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "float_sortable" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +nutype = { path = "../../nutype" } diff --git a/examples/float_sortable/src/main.rs b/examples/float_sortable/src/main.rs new file mode 100644 index 0000000..298adc3 --- /dev/null +++ b/examples/float_sortable/src/main.rs @@ -0,0 +1,33 @@ +use nutype::nutype; + +#[nutype(derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord), validate(finite))] +pub struct Width(f64); + +fn main() { + let raw_widths = vec![1.5, 1.4, 2.1, 1.8]; + + // NOTE: sorting raw_widths is not possible, because f64 does not implement Ord. + // raw_widths.sort(); + + // So instead we can wrap f64 into Width, which implements Ord. + // Ord is possible to safely derived, because there is `finite` validation in place, + // which excluded NaN values. + let mut widths: Vec = raw_widths + .into_iter() + .map(|w| Width::new(w).unwrap()) + .collect(); + + // Now we can sort + widths.sort(); + + // Verify + assert_eq!( + widths, + vec![ + Width::new(1.4).unwrap(), + Width::new(1.5).unwrap(), + Width::new(1.8).unwrap(), + Width::new(2.1).unwrap(), + ], + ) +} From 747f78053c18e20c09c8129382ec897efff3f64d Mon Sep 17 00:00:00 2001 From: Sergey Potapov Date: Sun, 15 Oct 2023 15:35:59 +0200 Subject: [PATCH 2/4] Fix CI to run example --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a64c5a5..d2e0a85 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -108,5 +108,5 @@ jobs: - name: Run examples run: | for example in $(ls ./examples/); do - echo $example + cargo run --bin $example done From 1b22ec719c2dbc6b1da714138b4a1965c35e838a Mon Sep 17 00:00:00 2001 From: Serhii Potapov Date: Sat, 18 Nov 2023 13:07:59 +0100 Subject: [PATCH 3/4] Add string_regex_email example --- Cargo.lock | 33 +++++++++++++---- examples/float_sortable/src/main.rs | 3 ++ examples/string_regex_email/Cargo.toml | 11 ++++++ examples/string_regex_email/src/main.rs | 48 +++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 examples/string_regex_email/Cargo.toml create mode 100644 examples/string_regex_email/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index d6b9fa9..45e35ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -151,9 +151,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "num-traits" @@ -215,9 +215,21 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -226,9 +238,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rmp" @@ -336,6 +348,15 @@ dependencies = [ "serde", ] +[[package]] +name = "string_regex_email" +version = "0.1.0" +dependencies = [ + "lazy_static", + "nutype", + "regex", +] + [[package]] name = "syn" version = "1.0.109" diff --git a/examples/float_sortable/src/main.rs b/examples/float_sortable/src/main.rs index 298adc3..bd1a193 100644 --- a/examples/float_sortable/src/main.rs +++ b/examples/float_sortable/src/main.rs @@ -1,3 +1,6 @@ +// This example shows how an f64 newtype can derive `Ord` and be sortable +// if it defines `finite` validation. + use nutype::nutype; #[nutype(derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord), validate(finite))] diff --git a/examples/string_regex_email/Cargo.toml b/examples/string_regex_email/Cargo.toml new file mode 100644 index 0000000..1aae745 --- /dev/null +++ b/examples/string_regex_email/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "string_regex_email" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nutype = { path = "../../nutype", features = ["regex"] } +regex = "1.10.2" +lazy_static = "1.4.0" diff --git a/examples/string_regex_email/src/main.rs b/examples/string_regex_email/src/main.rs new file mode 100644 index 0000000..c2f5c90 --- /dev/null +++ b/examples/string_regex_email/src/main.rs @@ -0,0 +1,48 @@ +use nutype::nutype; +use lazy_static::lazy_static; +use regex::Regex; + +lazy_static! { + // Note: this regex is very simplified. + // In reality you'd like to use a more sophisticated regex for email validation. + static ref EMAIL_REGEX: Regex = Regex::new("^\\w+@\\w+\\.\\w+$").unwrap(); +} + +// Note: technically the local part of email address is case-sensitive, but in practice all the +// popular email services (e.g. gmail) make it case-insensitive, so applying `lowercase` is OK. +#[nutype( + sanitize(trim, lowercase), + validate( + char_len_min = 5, + char_len_max = 20, + regex = EMAIL_REGEX, + ), + derive(Debug, PartialEq, AsRef), +)] +struct Email(String); + +fn main() { + // Too short + assert_eq!( + Email::new("a@b"), + Err(EmailError::CharLenMinViolated) + ); + + // Too long + assert_eq!( + Email::new("abcedfghijklmnopqrstuvwxyz@b.example"), + Err(EmailError::CharLenMaxViolated) + ); + + // Does not match the regex + assert_eq!( + Email::new("foo@barcom"), + Err(EmailError::RegexViolated) + ); + + // A valid email + let email: Email = Email::new("\t Nutype@Example.Com \n").unwrap(); + + // The underlying string that represents the email address is sanitized + assert_eq!(email.as_ref(), "nutype@example.com"); +} From 8700f150971aaef80aeb0ffbf2416e0005e4d371 Mon Sep 17 00:00:00 2001 From: Serhii Potapov Date: Sat, 18 Nov 2023 18:06:38 +0100 Subject: [PATCH 4/4] Fix CI --- examples/string_regex_email/src/main.rs | 12 +++--------- nutype_macros/src/any/gen/error.rs | 1 + nutype_macros/src/float/gen/error.rs | 1 + nutype_macros/src/integer/gen/error.rs | 1 + nutype_macros/src/string/gen/error.rs | 1 + 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/examples/string_regex_email/src/main.rs b/examples/string_regex_email/src/main.rs index c2f5c90..b228877 100644 --- a/examples/string_regex_email/src/main.rs +++ b/examples/string_regex_email/src/main.rs @@ -1,5 +1,5 @@ -use nutype::nutype; use lazy_static::lazy_static; +use nutype::nutype; use regex::Regex; lazy_static! { @@ -23,10 +23,7 @@ struct Email(String); fn main() { // Too short - assert_eq!( - Email::new("a@b"), - Err(EmailError::CharLenMinViolated) - ); + assert_eq!(Email::new("a@b"), Err(EmailError::CharLenMinViolated)); // Too long assert_eq!( @@ -35,10 +32,7 @@ fn main() { ); // Does not match the regex - assert_eq!( - Email::new("foo@barcom"), - Err(EmailError::RegexViolated) - ); + assert_eq!(Email::new("foo@barcom"), Err(EmailError::RegexViolated)); // A valid email let email: Email = Email::new("\t Nutype@Example.Com \n").unwrap(); diff --git a/nutype_macros/src/any/gen/error.rs b/nutype_macros/src/any/gen/error.rs index 3722102..8860913 100644 --- a/nutype_macros/src/any/gen/error.rs +++ b/nutype_macros/src/any/gen/error.rs @@ -35,6 +35,7 @@ fn gen_definition(error_type_name: &ErrorTypeName, validators: &[AnyValidator]) .collect(); quote! { + #[allow(clippy::enum_variant_names)] pub enum #error_type_name { #error_variants } diff --git a/nutype_macros/src/float/gen/error.rs b/nutype_macros/src/float/gen/error.rs index d05f71a..20614f1 100644 --- a/nutype_macros/src/float/gen/error.rs +++ b/nutype_macros/src/float/gen/error.rs @@ -55,6 +55,7 @@ fn gen_definition( .collect(); quote! { + #[allow(clippy::enum_variant_names)] pub enum #error_type_name { #error_variants } diff --git a/nutype_macros/src/integer/gen/error.rs b/nutype_macros/src/integer/gen/error.rs index b315cd0..a01ed38 100644 --- a/nutype_macros/src/integer/gen/error.rs +++ b/nutype_macros/src/integer/gen/error.rs @@ -51,6 +51,7 @@ fn gen_definition( .collect(); quote! { + #[allow(clippy::enum_variant_names)] pub enum #error_type_name { #error_variants } diff --git a/nutype_macros/src/string/gen/error.rs b/nutype_macros/src/string/gen/error.rs index 1201525..b550af9 100644 --- a/nutype_macros/src/string/gen/error.rs +++ b/nutype_macros/src/string/gen/error.rs @@ -50,6 +50,7 @@ fn gen_definition(error_type_name: &ErrorTypeName, validators: &[StringValidator .collect(); quote! { + #[allow(clippy::enum_variant_names)] pub enum #error_type_name { #error_variants }