From 2346b804f29f24ffd317ed92a0bec26d6a7b8e37 Mon Sep 17 00:00:00 2001 From: Sebastien Rousseau Date: Tue, 26 Dec 2023 19:08:13 +0000 Subject: [PATCH 1/5] feat(mini-functions): :sparkles: minor updates, refactoring and documentation --- Cargo.toml | 2 +- README.md | 2 +- cjwt/Cargo.toml | 2 - cjwt/benches/cjwt.rs | 13 +++--- cjwt/src/lib.rs | 2 +- cjwt/tests/cjwt.rs | 4 +- examples/example_constants.rs | 6 ++- examples/example_date.rs | 4 +- examples/example_errors.rs | 6 +-- examples/example_hash.rs | 79 ++++++++++++++++++++++++----------- examples/example_jwt.rs | 33 +++++++++++---- examples/example_logs.rs | 2 +- examples/example_md5.rs | 6 ++- examples/example_qr.rs | 39 ++++++++++++----- examples/example_random.rs | 2 +- idk/Cargo.toml | 6 --- mdg/Cargo.toml | 1 - mdg/tests/lib.rs | 12 +++--- qrc/tests/qr.rs | 13 +++--- src/common.rs | 2 +- src/hash.rs | 2 +- src/jwt.rs | 2 +- src/lib.rs | 58 +++++++++++++------------ src/random.rs | 2 +- 24 files changed, 179 insertions(+), 121 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 81794e79..f2985e4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ name = "mini-functions" readme = "README.md" repository = "https://github.com/sebastienrousseau/mini-functions.git" rust-version = "1.67" -version = "0.0.9" +version = "0.0.10" [dependencies] cclm = "0.0.1" diff --git a/README.md b/README.md index 20d6131c..780e779e 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ To use the `mini-functions` library in your project, add the following to your ` ```toml [dependencies] -mini-functions = "0.0.8" +mini-functions = "0.0.10" ``` Add the following to your `main.rs` file: diff --git a/cjwt/Cargo.toml b/cjwt/Cargo.toml index af7d81de..29757164 100644 --- a/cjwt/Cargo.toml +++ b/cjwt/Cargo.toml @@ -39,10 +39,8 @@ cclm = "0.0.1" dtt = "0.0.5" hmac = "0.12.1" idk = "0.0.1" -jsonwebtoken = "9.2.0" jwt = "0.16.0" serde = { version = "1.0.193", features = ["derive"] } -serde_derive = "1.0.193" serde_json = "1.0.108" sha2 = "0.10.8" diff --git a/cjwt/benches/cjwt.rs b/cjwt/benches/cjwt.rs index 2a856941..55274e57 100644 --- a/cjwt/benches/cjwt.rs +++ b/cjwt/benches/cjwt.rs @@ -21,12 +21,13 @@ fn bench_decode_benchmark(c: &mut Criterion) { let claims = Claims::default(); let token = JWT::encode(header, claims, secret).unwrap(); - let mut jwt = JWT { - header: Header::default(), - claims: Claims::default(), - signature: vec![], - token, - }; + let mut jwt = + JWT { + header: Header::default(), + claims: Claims::default(), + signature: vec![], + token, + }; c.bench_function("decode", move |b| b.iter(|| jwt.decode(secret))); } diff --git a/cjwt/src/lib.rs b/cjwt/src/lib.rs index c404ba97..6a2ac062 100644 --- a/cjwt/src/lib.rs +++ b/cjwt/src/lib.rs @@ -81,7 +81,7 @@ pub struct JWT { pub token: String, } /// The Header struct contains the header of the JWT. -#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, PartialOrd)] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, PartialOrd)] pub struct Header { /// Indicates the algorithm used to sign the JWT. Defaults to HS256. /// See the Algorithm enum for a list of supported algorithms. diff --git a/cjwt/tests/cjwt.rs b/cjwt/tests/cjwt.rs index 5a1f809c..6aa288e1 100644 --- a/cjwt/tests/cjwt.rs +++ b/cjwt/tests/cjwt.rs @@ -1,10 +1,10 @@ #[cfg(test)] mod tests { - extern crate cjwt; extern crate cclm; + extern crate cjwt; - use self::cjwt::{Algorithm, Header, JWT}; use self::cclm::Claims; + use self::cjwt::{Algorithm, Header, JWT}; #[test] fn test_default_algorithm_is_hs256() { diff --git a/examples/example_constants.rs b/examples/example_constants.rs index 540465ab..8cbc9ae0 100644 --- a/examples/example_constants.rs +++ b/examples/example_constants.rs @@ -1,10 +1,12 @@ // Copyright Š 2023 Mini Functions library. All rights reserved. // SPDX-License-Identifier: Apache-2.0 OR MIT -use cmn::{constants::{Constant,ConstantValue}, cmn_constants}; +use cmn::{ + cmn_constants, + constants::{Constant, ConstantValue}, +}; use mini_functions::common::*; - fn main() { // Create a Constants instance let c = Constants::new(); diff --git a/examples/example_date.rs b/examples/example_date.rs index 9903f15e..080957ac 100644 --- a/examples/example_date.rs +++ b/examples/example_date.rs @@ -5,7 +5,7 @@ use mini_functions::date::DateTime; use std::str::FromStr; /// This is the main function for the build script. -pub fn main() { +pub fn main() { // Create a new DateTime object with a custom timezone (e.g., CET) let paris_time = DateTime::new_with_tz("CET").now; println!("đŸĻ€ Paris time: ✅ {}", paris_time); @@ -105,4 +105,4 @@ pub fn main() { println!("đŸĻ€ Rd month:(05) ✅ {}", new_dt.month); println!("đŸĻ€ Rd second:(00) ✅ {}", new_dt.second); println!("đŸĻ€ Rd year:(1975) ✅ {}", new_dt.year); -} \ No newline at end of file +} diff --git a/examples/example_errors.rs b/examples/example_errors.rs index bc293229..b650160d 100644 --- a/examples/example_errors.rs +++ b/examples/example_errors.rs @@ -7,8 +7,8 @@ fn main() { let error_type = ErrorType::new("illegal_argument"); let error_type_new_subtype = error_type.new_subtype("subtype"); - println!("đŸĻ€ Error::error_type_new(): ✅ {error_type:?}\n",); + println!( + "đŸĻ€ Error::error_type_new(): ✅ {error_type:?}\n", + ); println!("đŸĻ€ Error::error_type_new_subtype(): ✅ {error_type_new_subtype:?}\n",); } - - diff --git a/examples/example_hash.rs b/examples/example_hash.rs index 1eb84c3c..a804ee48 100644 --- a/examples/example_hash.rs +++ b/examples/example_hash.rs @@ -1,15 +1,20 @@ // Copyright Š 2023 Mini Functions library. All rights reserved. // SPDX-License-Identifier: Apache-2.0 OR MIT -use mini_functions::hash::{models::{hash::Hash, hash_algorithm::HashAlgorithm}, new_hash}; +use mini_functions::hash::{ + models::{hash::Hash, hash_algorithm::HashAlgorithm}, + new_hash, +}; use std::str::FromStr; /// This function demonstrates how to create and verify password hashes using Argon2i, Bcrypt, and Scrypt algorithms. fn create_and_verify_hash() { // Create new hashes for Argon2i, Bcrypt, and Scrypt - let hash_argon2i = Hash::new_argon2i("password", "salt1234".into()).unwrap(); + let hash_argon2i = + Hash::new_argon2i("password", "salt1234".into()).unwrap(); let hash_bcrypt = Hash::new_bcrypt("password", 16).unwrap(); - let hash_scrypt = Hash::new_scrypt("password", "salt1234".into()).unwrap(); + let hash_scrypt = + Hash::new_scrypt("password", "salt1234".into()).unwrap(); // Verify these hashes verify_password(&hash_argon2i, "password", "Argon2i"); @@ -18,13 +23,19 @@ fn create_and_verify_hash() { // Update the hashes let mut new_hash_argon2i = hash_argon2i.clone(); - new_hash_argon2i.set_password("new_password", "salt1234", "argon2i").unwrap(); + new_hash_argon2i + .set_password("new_password", "salt1234", "argon2i") + .unwrap(); let mut new_hash_bcrypt = hash_bcrypt.clone(); - new_hash_bcrypt.set_password("new_password", "salt1234", "bcrypt").unwrap(); + new_hash_bcrypt + .set_password("new_password", "salt1234", "bcrypt") + .unwrap(); let mut new_hash_scrypt = hash_scrypt.clone(); - new_hash_scrypt.set_password("new_password", "salt1234", "scrypt").unwrap(); + new_hash_scrypt + .set_password("new_password", "salt1234", "scrypt") + .unwrap(); // Verify the updated hashes verify_password(&new_hash_argon2i, "new_password", "Argon2i"); @@ -35,18 +46,33 @@ fn create_and_verify_hash() { // Function to verify the password fn verify_password(hash: &Hash, password: &str, algorithm: &str) { // Print header - println!("\n===[ Verifying Password with {} Algorithm ]===\n", algorithm); + println!( + "\n===[ Verifying Password with {} Algorithm ]===\n", + algorithm + ); let is_valid = hash.verify(password); match is_valid { Ok(valid) => { println!("Algorithm: {}", algorithm); - println!("Provided password for verification: {}", password); - println!("Salt used for verification: {}", String::from_utf8_lossy(hash.salt())); - println!("đŸĻ€ Password verification result for {}: ✅ {:?}", algorithm, valid); - }, + println!( + "Provided password for verification: {}", + password + ); + println!( + "Salt used for verification: {}", + String::from_utf8_lossy(hash.salt()) + ); + println!( + "đŸĻ€ Password verification result for {}: ✅ {:?}", + algorithm, valid + ); + } Err(e) => { - eprintln!("đŸĻ€ Error during password verification for {}: ❌ {}", algorithm, e); + eprintln!( + "đŸĻ€ Error during password verification for {}: ❌ {}", + algorithm, e + ); } } @@ -77,18 +103,21 @@ fn parse_and_display_hash() { let bcrypt_hash = new_hash!("password", "salt12345", "bcrypt"); let scrypt_hash = new_hash!("password", "salt12345", "scrypt"); - let argon2i_hash_string = match argon2i_hash { - Ok(hash) => hash.to_string_representation(), - Err(e) => format!("Error: {}", e), - }; - let bcrypt_hash_string = match bcrypt_hash { - Ok(hash) => hash.to_string_representation(), - Err(e) => format!("Error: {}", e), - }; - let scrypt_hash_string = match scrypt_hash { - Ok(hash) => hash.to_string_representation(), - Err(e) => format!("Error: {}", e), - }; + let argon2i_hash_string = + match argon2i_hash { + Ok(hash) => hash.to_string_representation(), + Err(e) => format!("Error: {}", e), + }; + let bcrypt_hash_string = + match bcrypt_hash { + Ok(hash) => hash.to_string_representation(), + Err(e) => format!("Error: {}", e), + }; + let scrypt_hash_string = + match scrypt_hash { + Ok(hash) => hash.to_string_representation(), + Err(e) => format!("Error: {}", e), + }; println!("đŸĻ€ Argon2i Hash to a string: {}", argon2i_hash_string); println!("đŸĻ€ Bcrypt Hash to a string: {}", bcrypt_hash_string); @@ -102,4 +131,4 @@ fn parse_and_display_hash() { fn main() { create_and_verify_hash(); parse_and_display_hash(); -} \ No newline at end of file +} diff --git a/examples/example_jwt.rs b/examples/example_jwt.rs index f9e8c4b0..5889406b 100644 --- a/examples/example_jwt.rs +++ b/examples/example_jwt.rs @@ -18,10 +18,14 @@ fn main() { // Create a Header struct with default method and replace values. let mut hdrv: Header = Header::default(); - Header::default().alg = std::mem::replace(&mut hdrv.alg, Some(HD_ALG)); - Header::default().kid = std::mem::replace(&mut hdrv.kid, Some(HD_KID.to_string())); - Header::default().typ = std::mem::replace(&mut hdrv.typ, Some(HD_TYP.to_string())); - Header::default().cty = std::mem::replace(&mut hdrv.cty, Some(HD_CTY.to_string())); + Header::default().alg = + std::mem::replace(&mut hdrv.alg, Some(HD_ALG)); + Header::default().kid = + std::mem::replace(&mut hdrv.kid, Some(HD_KID.to_string())); + Header::default().typ = + std::mem::replace(&mut hdrv.typ, Some(HD_TYP.to_string())); + Header::default().cty = + std::mem::replace(&mut hdrv.cty, Some(HD_CTY.to_string())); println!("đŸĻ€ Header::default(): ✅ {hdrv:?}\n"); // Create a JWT struct with default method. @@ -30,14 +34,25 @@ fn main() { // Create a JWT struct with default method and replace values. let mut jdrv: JWT = JWT::default(); - JWT::default().header.alg = std::mem::replace(&mut jdrv.header.alg, Some(HD_ALG)); - JWT::default().header.kid = std::mem::replace(&mut jdrv.header.kid, Some(HD_KID.to_string())); - JWT::default().header.typ = std::mem::replace(&mut jdrv.header.typ, Some(HD_TYP.to_string())); - JWT::default().header.cty = std::mem::replace(&mut jdrv.header.cty, Some(HD_CTY.to_string())); + JWT::default().header.alg = + std::mem::replace(&mut jdrv.header.alg, Some(HD_ALG)); + JWT::default().header.kid = std::mem::replace( + &mut jdrv.header.kid, + Some(HD_KID.to_string()), + ); + JWT::default().header.typ = std::mem::replace( + &mut jdrv.header.typ, + Some(HD_TYP.to_string()), + ); + JWT::default().header.cty = std::mem::replace( + &mut jdrv.header.cty, + Some(HD_CTY.to_string()), + ); println!("đŸĻ€ JWT::default(): ✅ {jdrv:?}\n"); // Encode a JWT struct. - let encoded: String = JWT::encode(hdrv, Claims::default(), b"secret").unwrap(); + let encoded: String = + JWT::encode(hdrv, Claims::default(), b"secret").unwrap(); println!("đŸĻ€ encode(): ✅ {encoded:?}\n"); // Extract the token field from the passed JWT struct and return it. diff --git a/examples/example_logs.rs b/examples/example_logs.rs index 0750f4e5..a3456f67 100644 --- a/examples/example_logs.rs +++ b/examples/example_logs.rs @@ -27,4 +27,4 @@ fn main() { ); println!("đŸĻ€ Log::new(): ✅ {log}"); } -} \ No newline at end of file +} diff --git a/examples/example_md5.rs b/examples/example_md5.rs index 365c8db8..9d572b93 100644 --- a/examples/example_md5.rs +++ b/examples/example_md5.rs @@ -11,7 +11,8 @@ fn main() { // Expected 6cd3556deb0da54bca060b4c39479839 // Example using MD5::hexdigest() for a byte array input - let input = [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]; // "Hello, world!" + let input = + [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]; // "Hello, world!" let input_str = String::from_utf8(input.to_vec()).unwrap(); let digest = MD5::hexdigest(&input_str); println!("đŸĻ€ MD5::hexdigest() for a byte array input: ✅ {digest}",); @@ -25,7 +26,8 @@ fn main() { // Example using MD5::update() for a byte array input let mut mdg = MD5::new(); let input = [ - 67, 111, 117, 99, 111, 117, 44, 32, 108, 101, 32, 109, 111, 110, 100, 101, 33, + 67, 111, 117, 99, 111, 117, 44, 32, 108, 101, 32, 109, 111, + 110, 100, 101, 33, ]; // "Coucou, le monde!" mdg.update(&input); let digest = mdg.finalize(); diff --git a/examples/example_qr.rs b/examples/example_qr.rs index cbe3eb71..7afbd9ef 100644 --- a/examples/example_qr.rs +++ b/examples/example_qr.rs @@ -1,21 +1,24 @@ // Copyright Š 2023 Mini Functions library. All rights reserved. // SPDX-License-Identifier: Apache-2.0 OR MIT -use image::{Rgba,RgbaImage}; +use image::{Rgba, RgbaImage}; use mini_functions::qr::QRCode; -use mini_functions::qr::{qr_code_to,add_image_watermark}; +use mini_functions::qr::{add_image_watermark, qr_code_to}; extern crate image; use std::fs; const URL: &str = "https://minifunctions.com/"; -fn add_watermark_to_qrcode(qrcode: &mut RgbaImage, watermark_path: &str) -> Result<(), String> { +fn add_watermark_to_qrcode( + qrcode: &mut RgbaImage, + watermark_path: &str, +) -> Result<(), String> { match image::open(watermark_path) { Ok(watermark_img) => { let watermark_rgba = watermark_img.into_rgba8(); add_image_watermark!(qrcode, &watermark_rgba); Ok(()) - }, + } Err(e) => Err(format!("Failed to open watermark image: {}", e)), } } @@ -32,21 +35,27 @@ where fn save_image(image: &RgbaImage, file_name: &str) { match image.save(file_name) { Ok(_) => println!("đŸĻ€ File created: ✅ {}", file_name), - Err(e) => println!("đŸĻ€ File creation failed: ❌ {}: {}", file_name, e), + Err(e) => { + println!("đŸĻ€ File creation failed: ❌ {}: {}", file_name, e) + } } } fn save_svg(data: &str, file_name: &str) { match fs::write(file_name, data) { Ok(_) => println!("đŸĻ€ File created: ✅ {}", file_name), - Err(e) => println!("đŸĻ€ File creation failed: ❌ {}: {}", file_name, e), + Err(e) => { + println!("đŸĻ€ File creation failed: ❌ {}: {}", file_name, e) + } } } fn remove_file(file_name: &str) { match fs::remove_file(file_name) { Ok(_) => println!("đŸĻ€ File removed: ✅ {}", file_name), - Err(e) => println!("đŸĻ€ File removal failed: ❌ {}: {}", file_name, e), + Err(e) => { + println!("đŸĻ€ File removal failed: ❌ {}: {}", file_name, e) + } } } @@ -56,11 +65,19 @@ fn main() { remove_file("qrcode.png"); // Generate QR colorized QR Code, save it as a PNG file and remove it after. - process_qrcode(URL, |qrcode| qrcode.colorize(Rgba([255, 0, 0, 255])), "qrcode_colorized.png"); + process_qrcode( + URL, + |qrcode| qrcode.colorize(Rgba([255, 0, 0, 255])), + "qrcode_colorized.png", + ); remove_file("qrcode_colorized.png"); // Generate QR Code, resize it and save it as a PNG file and remove it after. - process_qrcode(URL, |qrcode| qrcode.resize(512, 512), "qrcode_resized.png"); + process_qrcode( + URL, + |qrcode| qrcode.resize(512, 512), + "qrcode_resized.png", + ); remove_file("qrcode_resized.png"); // SVG creation with decoupled functions @@ -91,7 +108,9 @@ fn main() { let mut watermark_qr_img = watermark_qrcode.to_png(512); match add_watermark_to_qrcode(&mut watermark_qr_img, "bubba.ico") { - Ok(_) => save_image(&watermark_qr_img, "qrcode_watermarked.png"), + Ok(_) => { + save_image(&watermark_qr_img, "qrcode_watermarked.png") + } Err(e) => println!("đŸĻ€ Error adding watermark: {}", e), } diff --git a/examples/example_random.rs b/examples/example_random.rs index bc5bf6eb..61fa6467 100644 --- a/examples/example_random.rs +++ b/examples/example_random.rs @@ -121,4 +121,4 @@ fn main() { "đŸĻ€ Random u32 after twisting the PRNG state: {}", rand_twist ); -} \ No newline at end of file +} diff --git a/idk/Cargo.toml b/idk/Cargo.toml index b6627efe..d8d87c86 100644 --- a/idk/Cargo.toml +++ b/idk/Cargo.toml @@ -31,14 +31,8 @@ include = [ [dependencies] base64 = "0.21.5" hmac = "0.12.1" -jsonwebtoken = "9.2.0" jwt = "0.16.0" -once_cell = "1.18.0" -serde = { version = "1.0.193", features = ["derive"] } -# openssl = "0.10.45" -serde_derive = "1.0.193" serde_json = "1.0.108" -sha2 = "0.10.8" [dev-dependencies] criterion = "0.5.1" diff --git a/mdg/Cargo.toml b/mdg/Cargo.toml index 5f0d57b2..584d55ac 100644 --- a/mdg/Cargo.toml +++ b/mdg/Cargo.toml @@ -28,7 +28,6 @@ harness = false path = "benches/mdg.rs" [dependencies] -cclm = "0.0.1" cjwt = "0.0.1" [dev-dependencies] diff --git a/mdg/tests/lib.rs b/mdg/tests/lib.rs index 4add796a..c854a63b 100644 --- a/mdg/tests/lib.rs +++ b/mdg/tests/lib.rs @@ -96,11 +96,12 @@ mod tests { } #[test] fn reset_file() { - let digest = MD5::new() - .update_file("update.txt") - .reset() - .finalize() - .to_string(); + let digest = + MD5::new() + .update_file("update.txt") + .reset() + .finalize() + .to_string(); assert_eq!(digest, "d41d8cd98f00b204e9800998ecf8427e"); } #[test] @@ -312,5 +313,4 @@ mod tests { // assert_eq!(i, NBYTES); // assert_eq!(md5.count, [63, 0]); // } - } diff --git a/qrc/tests/qr.rs b/qrc/tests/qr.rs index 96f7a420..def353bb 100644 --- a/qrc/tests/qr.rs +++ b/qrc/tests/qr.rs @@ -102,12 +102,13 @@ mod tests { // Convert the QR code to a PNG image and assert that all of the dark cells are red. let image: RgbaImage = red_qrcode; for (x, y, pixel) in image.enumerate_pixels() { - let expected_color = - if qrcode.to_qrcode()[(x as usize, y as usize)] == qrcode::Color::Dark { - Rgba([255, 0, 0, 255]) - } else { - Rgba([255, 255, 255, 255]) - }; + let expected_color = if qrcode.to_qrcode()[(x as usize, y as usize)] + == qrcode::Color::Dark + { + Rgba([255, 0, 0, 255]) + } else { + Rgba([255, 255, 255, 255]) + }; assert_eq!(*pixel, expected_color); } } diff --git a/src/common.rs b/src/common.rs index 10ebf442..5dd56e34 100644 --- a/src/common.rs +++ b/src/common.rs @@ -18,4 +18,4 @@ pub use cmn::Words; pub use cmn::run; /// Re-exported macros from cmn providing access to common macros. -pub use cmn::macros as cmn_macros; \ No newline at end of file +pub use cmn::macros as cmn_macros; diff --git a/src/hash.rs b/src/hash.rs index d5ee9e95..69c02db0 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -5,5 +5,5 @@ //! //! Provides access to hash functions and types. +pub use hsh::macros as hsh_macros; pub use hsh::*; -pub use hsh::macros as hsh_macros; \ No newline at end of file diff --git a/src/jwt.rs b/src/jwt.rs index 6e0daaa2..3473781c 100644 --- a/src/jwt.rs +++ b/src/jwt.rs @@ -5,4 +5,4 @@ //! //! Provides access to JSON Web Token (JWT) functions. -pub use cjwt::*; \ No newline at end of file +pub use cjwt::*; diff --git a/src/lib.rs b/src/lib.rs index 5e8960e0..8a39172c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,22 +22,20 @@ //! //! ## Overview //! -//! Mini-Functions is a modern Rust library that prioritizes performance -//! , security, and modularity. It provides a low-overhead access to -//! functions for common programming tasks. +//! Mini-Functions is a modern Rust library that prioritizes performance, security, and modularity. It provides a low-overhead access to functions for common programming tasks. //! //! ## Features //! -//! - **[Claims](Claims/index.html)** - Provides access to the claims of a JSON Web Token (JWT). -//! - **[Common](Common/index.html)** - Provides access to functions for accessing a collection of mathematical and cryptographic constants. -//! - **[Date](Date/index.html)** - Provides access to functions for parsing, validating, manipulating, and formatting dates and times. -//! - **[Errors](Errors/index.html)** - Provides access to error handling functions. -//! - **[Hash](Hash/index.html)** - Provides access to a Quantum-Resistant Cryptographic Hash Library for Password Hashing and Verification. -//! - **[Logs](Logs/index.html)** - Provides access to functions for application-level logging with a simple, readable output format. -//! - **[JWT](JWT/index.html)** - Provides access to JSON Web Token (JWT) functions. -//! - **[MD5](MD5/index.html)** - Provides access to MD5 functions. -//! - **[QR](QR/index.html)** - Provides access to QR code functions. -//! - **[Random](Random/index.html)** - Provides access to functions for generating high-quality random numbers based on the Mersenne Twister algorithm. +//! - **[Claims](#Modules/Claims/index.html)** - Provides robust functionalities for handling various types of claims in JSON Web Tokens (JWT), including standard, custom, and private claims. Ideal for authentication and authorization processes in Rust applications. +//! - **[Common](#Modules/Common/index.html)** - Offers a comprehensive collection of mathematical and cryptographic constants, such as prime numbers, Pi, cryptographic keys, and more. Essential for applications requiring high-level mathematical computations and secure cryptographic operations. +//! - **[Date](#Modules/Date/index.html)** - Features an extensive suite of functions for parsing, validating, manipulating, and formatting dates and times. Supports a wide range of date/time formats and is tailored for time-sensitive Rust applications. +//! - **[Errors](#Modules/Errors/index.html)** - Delivers advanced error handling functions with support for custom error types, integration with logging systems, and streamlined error propagation. Enhances the reliability and maintainability of Rust applications through robust error management. +//! - **[Hash](#Modules/Hash/index.html)** - Specializes in Quantum-Resistant Cryptographic Hashing, offering a library tailored for password hashing and verification. Includes modern algorithms designed to withstand quantum-computing threats, ensuring long-term security. +//! - **[JWT](#Modules/JWT/index.html)** - Provides a full range of JSON Web Token (JWT) functionalities, including secure token generation, decoding, and validation. Facilitates secure and efficient user authentication processes in Rust-based systems. +//! - **[Logs](#Modules/Logs/index.html)** - Enables application-level logging with a focus on simplicity and readability. Features customizable log formats, multiple log levels, and easy integration with Rust applications, making debugging and monitoring more efficient. +//! - **[MD5](#Modules/MD5/index.html)** - Offers MD5 hash functions, suitable for legacy systems compatibility. Includes a clear advisory on MD5's vulnerabilities and guidance on secure alternatives for modern applications. +//! - **[QR](#Modules/QR/index.html)** - Allows for comprehensive QR code operations, including generation, customization, and scanning capabilities. Supports a variety of formats and use-cases, making it a versatile tool for Rust applications involving QR code integration. +//! - **[Random](Random/index.html)** - Features high-quality random number generation using the Mersenne Twister algorithm. Ideal for applications requiring random data generation, including simulations, gaming, and cryptographic operations. //! //! These components provide a comprehensive set of functionality and offer powerful new capabilities to help you build better applications and services in the Rust programming language. //! @@ -52,7 +50,7 @@ //! Add the following to your `Cargo.toml` file: //! ```toml //! [dependencies] -//! mini_functions = "0.0.8" +//! mini_functions = "0.0.10" //! ``` //! Then, add the following to your crate root: //! ```rust @@ -81,45 +79,45 @@ /// Provides access to the claims of a JSON Web Token (JWT). pub mod claims; -/// Provides access to functions for accessing a collection of mathematical and cryptographic constants. +/// Offers a comprehensive collection of mathematical and cryptographic constants. pub mod common; -/// Provides access to functions for parsing, validating, manipulating, and formatting dates and times. +/// Features an extensive suite of functions for handling dates and times. pub mod date; -/// Provides access to error handling functions. +/// Delivers advanced error handling functionalities. pub mod errors; -/// Provides access to hash functions. +/// Specializes in Quantum-Resistant Cryptographic Hashing. pub mod hash; -/// Provides access to functions for application-level logging with a simple, readable output format. +/// Enables application-level logging with customizable features. pub mod logs; -/// Provides access to JSON Web Token (JWT) functions. +/// Provides a full range of JSON Web Token (JWT) functionalities. pub mod jwt; -/// Provides access to MD5 functions. +/// Offers MD5 hash functions with advisories on usage. pub mod md5; -/// Provides access to functions for generating high-quality random numbers based on the Mersenne Twister algorithm. +/// Features high-quality random number generation using the Mersenne Twister algorithm. pub mod random; -/// Provides access to QR code functions. +/// Allows for comprehensive QR code operations. pub mod qr; /// Re-exports public contents of key modules pub mod mini_functions { pub use crate::{ claims::*, - common::{self,cmn_macros}, - date::{self,dtt_macros}, + common::{self, cmn_macros}, + date::{self, dtt_macros}, errors::*, - hash::{self,hsh_macros}, + hash::{self, hsh_macros}, jwt::*, - logs::{self,rlg_macros}, - md5::{self,mdg_constants}, + logs::{self, rlg_macros}, + md5::{self, mdg_constants}, qr::*, - random::{self,vrd_macros}, + random::{self, vrd_macros}, }; -} \ No newline at end of file +} diff --git a/src/random.rs b/src/random.rs index f9072482..056d17ab 100644 --- a/src/random.rs +++ b/src/random.rs @@ -5,5 +5,5 @@ //! //! Provides access to functions for generating high-quality random numbers based on the Mersenne Twister algorithm. +pub use vrd::macros as vrd_macros; pub use vrd::*; -pub use vrd::macros as vrd_macros; \ No newline at end of file From 566b20371006a49847fd8b0bfcc69547b76fb67b Mon Sep 17 00:00:00 2001 From: Sebastien Rousseau Date: Fri, 29 Dec 2023 02:03:32 +0000 Subject: [PATCH 2/5] feat(mini-functions): :sparkles: 0.0.10 --- Cargo.toml | 8 +- README.md | 37 +++--- TEMPLATE.md | 2 +- cclm/src/lib.rs | 2 +- cjwt/src/lib.rs | 2 +- mdg/src/lib.rs | 2 +- qrc/Cargo.toml | 45 ------- qrc/README.md | 147 --------------------- qrc/benches/qrc.rs | 67 ---------- qrc/bubba.ico | Bin 414950 -> 0 bytes qrc/build.rs | 4 - qrc/deny.toml | 66 ---------- qrc/examples/qrc.rs | 152 ---------------------- qrc/rustfmt.toml | 1 - qrc/src/lib.rs | 302 -------------------------------------------- qrc/tests/qr.rs | 147 --------------------- src/claims.rs | 3 - src/lib.rs | 2 +- 18 files changed, 25 insertions(+), 964 deletions(-) delete mode 100644 qrc/Cargo.toml delete mode 100644 qrc/README.md delete mode 100644 qrc/benches/qrc.rs delete mode 100644 qrc/bubba.ico delete mode 100644 qrc/build.rs delete mode 100644 qrc/deny.toml delete mode 100644 qrc/examples/qrc.rs delete mode 100644 qrc/rustfmt.toml delete mode 100644 qrc/src/lib.rs delete mode 100644 qrc/tests/qr.rs diff --git a/Cargo.toml b/Cargo.toml index f2985e4a..50848f86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,6 @@ include = [ "/LICENSE-APACHE", "/LICENSE-MIT", "/mdg/**", - "/qrc/**", "/README.md", "/src/**", "/tests/**", @@ -37,7 +36,7 @@ license = "Apache-2.0 OR MIT" name = "mini-functions" readme = "README.md" repository = "https://github.com/sebastienrousseau/mini-functions.git" -rust-version = "1.67" +rust-version = "1.71.1" version = "0.0.10" [dependencies] @@ -48,7 +47,7 @@ dtt = "0.0.5" hsh = "0.0.7" idk = "0.0.1" mdg = "0.0.1" -qrc = "0.0.2" +qrc = "0.0.5" rlg = "0.0.2" vrd = "0.0.5" serde_json = "1.0.108" @@ -62,11 +61,10 @@ members = [ "cjwt", "idk", "mdg", - "qrc", ] # List of workspace members [workspace.package] -rust-version = "1.67" +rust-version = "1.71.1" [badges] maintenance = { status = "actively-developed" } diff --git a/README.md b/README.md index 780e779e..830a23fc 100644 --- a/README.md +++ b/README.md @@ -101,8 +101,7 @@ It takes just a few minutes to get up and running with `mini-functions`. ### Requirements -The minimum supported Rust toolchain version is currently Rust -**1.56.0** or later (stable). +The minimum supported Rust toolchain version is currently Rust **1.71.1** or later (stable). ### Installation @@ -207,6 +206,7 @@ cmn_constants! { println!("Euler's constant: {euler}"); println!("Pi: {PI}"); ``` + This allows convenient access to mathematical constants. To run the constants example: @@ -291,8 +291,8 @@ The `mini_functions` crate provides password hashing and verification functions It contains the following functions: -- `Hash::new_{algo}` - Generate a hash for a password -- `set_password` - Update password for a hash +- `Hash::new_{algo}` - Generate a hash for a password +- `set_password` - Update password for a hash - `verify` - Verify a password against a hash - `to_string` - Convert hash to a string @@ -367,7 +367,7 @@ The `mini_functions` crate provides MD5 hash generation functionality through th It contains functions like: -- `MD5::hexdigest` - Generate MD5 hash for input +- `MD5::hexdigest` - Generate MD5 hash for input - `MD5::new` - Create MD5 hasher instance - `update` - Update hasher with new input - `finalize` - Obtain final hash @@ -403,7 +403,7 @@ It contains functions like: - `QRCode::from_string` - Generate QR code from text - `to_png` - Convert to PNG image - `colorize` - Colorize the QR code -- `resize` - Resize image +- `resize` - Resize image And macros like: @@ -540,7 +540,6 @@ A big thank you to all the awesome contributors of [mini-functions ⧉][05] for A special thank you goes to the [Rust Reddit ⧉][24] community for providing a lot of useful suggestions on how to improve this project. [00]: https://minifunctions.com "Mini Functions - Highly performant utility and wrapper functions library for Rust" -[01]: http://www.apache.org/licenses/LICENSE-2.0 "Apache License, Version 2.0" [02]: http://opensource.org/licenses/MIT "MIT license" [03]: https://github.com/sebastienrousseau/mini-functions/issues "Mini Functions Issues" [04]: https://raw.githubusercontent.com/sebastienrousseau/mini-functions/main/.github/CONTRIBUTING.md "Mini Functions Contributing Guidelines" @@ -551,27 +550,25 @@ A special thank you goes to the [Rust Reddit ⧉][24] community for providing a [09]: https://lib.rs/crates/mini-functions "Mini Functions on Lib.rs" [10]: https://www.rust-lang.org/ "The Rust Programming Language" [11]: https://codecov.io/github/sebastienrousseau/mini-functions "Mini Functions Codecov" -[12]: https://docs.rs/mini-functions/0.0.8/mini_functions/claims/index.html "Mini Functions Claims" -[13]: https://docs.rs/mini-functions/0.0.8/mini_functions/common/index.html "Mini Functions Common" -[14]: https://docs.rs/mini-functions/0.0.8/mini_functions/date/index.html "Mini Functions Date" -[15]: https://docs.rs/mini-functions/0.0.8/mini_functions/errors/index.html "Mini Functions Errors" -[16]: https://docs.rs/mini-functions/0.0.8/mini_functions/hash/index.html "Mini Functions Hash" -[17]: https://docs.rs/mini-functions/0.0.8/mini_functions/logs/index.html "Mini Functions Logs" -[18]: https://docs.rs/mini-functions/0.0.8/mini_functions/jwt/index.html "Mini Functions JWT" -[19]: https://docs.rs/mini-functions/0.0.8/mini_functions/md5/index.html "Mini Functions MD5" -[20]: https://docs.rs/mini-functions/0.0.8/mini_functions/qr/index.html "Mini Functions QR" -[21]: https://docs.rs/mini-functions/0.0.8/mini_functions/random/index.html "Mini Functions Random" +[12]: https://docs.rs/mini-functions/0.0.10/mini_functions/claims/index.html "Mini Functions Claims" +[13]: https://docs.rs/mini-functions/0.0.10/mini_functions/common/index.html "Mini Functions Common" +[14]: https://docs.rs/mini-functions/0.0.10/mini_functions/date/index.html "Mini Functions Date" +[15]: https://docs.rs/mini-functions/0.0.10/mini_functions/errors/index.html "Mini Functions Errors" +[16]: https://docs.rs/mini-functions/0.0.10/mini_functions/hash/index.html "Mini Functions Hash" +[17]: https://docs.rs/mini-functions/0.0.10/mini_functions/logs/index.html "Mini Functions Logs" +[18]: https://docs.rs/mini-functions/0.0.10/mini_functions/jwt/index.html "Mini Functions JWT" +[19]: https://docs.rs/mini-functions/0.0.10/mini_functions/md5/index.html "Mini Functions MD5" +[20]: https://docs.rs/mini-functions/0.0.10/mini_functions/qr/index.html "Mini Functions QR" +[21]: https://docs.rs/mini-functions/0.0.10/mini_functions/random/index.html "Mini Functions Random" [22]: https://github.com/sebastienrousseau/mini-functions/actions "Mini Functions on GitHub Actions" [23]: https://www.rust-lang.org/policies/code-of-conduct "Rust Code of Conduct" [24]: https://www.reddit.com/r/rust/ "Reddit" -[banner]: https://kura.pro/mini-functions/images/v2/banners/banner-mini-functions.svg "Mini Functions Banner" [codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/mini-functions?style=for-the-badge&token=M1REIC3QCK 'Codecov' [crates-badge]: https://img.shields.io/crates/v/mini-functions.svg?style=for-the-badge 'Crates.io' [divider]: https://kura.pro/common/images/elements/divider.svg "divider" [docs-badge]: https://img.shields.io/docsrs/mini-functions.svg?style=for-the-badge 'Docs.rs' -[libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.8-orange.svg?style=for-the-badge 'Lib.rs' +[libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.10-orange.svg?style=for-the-badge 'Lib.rs' [license-badge]: https://img.shields.io/crates/l/mini-functions.svg?style=for-the-badge 'License' -[logo]: https://kura.pro/mini-functions/images/v2/logos/mini-functions.svg "Mini Functions Logo" [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' [title]: https://kura.pro/mini-functions/images/v2/titles/title-mini-functions.svg "Mini Functions Logo" diff --git a/TEMPLATE.md b/TEMPLATE.md index e76f23d0..95a27656 100644 --- a/TEMPLATE.md +++ b/TEMPLATE.md @@ -57,7 +57,7 @@ These utility functions serve as an essential toolkit for any Rust developer, an [crates-badge]: https://img.shields.io/crates/v/mini-functions.svg?style=for-the-badge 'Crates.io' [divider]: https://kura.pro/common/images/elements/divider.svg "divider" [docs-badge]: https://img.shields.io/docsrs/mini-functions.svg?style=for-the-badge 'Docs.rs' -[libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.8-orange.svg?style=for-the-badge 'Lib.rs' +[libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.10-orange.svg?style=for-the-badge 'Lib.rs' [license-badge]: https://img.shields.io/crates/l/mini-functions.svg?style=for-the-badge 'License' [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' [title]: https://kura.pro/mini-functions/images/v2/titles/title-mini-functions.svg "Mini Functions Logo" diff --git a/cclm/src/lib.rs b/cclm/src/lib.rs index d95f743b..18f929a4 100644 --- a/cclm/src/lib.rs +++ b/cclm/src/lib.rs @@ -10,7 +10,7 @@ //! //! [![Rust](https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust)](https://www.rust-lang.org) //! [![Crates.io](https://img.shields.io/crates/v/mini-functions.svg?style=for-the-badge&color=success&labelColor=27A006)](https://crates.io/crates/mini-functions) -//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.8-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/mini-functions) +//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.10-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/mini-functions) //! [![GitHub](https://img.shields.io/badge/github-555555?style=for-the-badge&labelColor=000000&logo=github)](https://github.com/sebastienrousseau/mini-functions/tree/main/claims) //! [![License](https://img.shields.io/crates/l/mini-functions.svg?style=for-the-badge&color=007EC6&labelColor=03589B)](http://opensource.org/licenses/MIT) //! diff --git a/cjwt/src/lib.rs b/cjwt/src/lib.rs index 6a2ac062..7c0fdb0c 100644 --- a/cjwt/src/lib.rs +++ b/cjwt/src/lib.rs @@ -10,7 +10,7 @@ //! //! [![Rust](https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust)](https://www.rust-lang.org) //! [![Crates.io](https://img.shields.io/crates/v/mini-functions.svg?style=for-the-badge&color=success&labelColor=27A006)](https://crates.io/crates/mini-functions) -//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.8-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/mini-functions) +//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.10-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/mini-functions) //! [![GitHub](https://img.shields.io/badge/github-555555?style=for-the-badge&labelColor=000000&logo=github)](https://github.com/sebastienrousseau/mini-functions) //! [![License](https://img.shields.io/crates/l/mini-functions.svg?style=for-the-badge&color=007EC6&labelColor=03589B)](http://opensource.org/licenses/MIT) //! diff --git a/mdg/src/lib.rs b/mdg/src/lib.rs index 508683b2..5b25be6e 100644 --- a/mdg/src/lib.rs +++ b/mdg/src/lib.rs @@ -10,7 +10,7 @@ //! //! [![Rust](https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust)](https://www.rust-lang.org) //! [![Crates.io](https://img.shields.io/crates/v/mini-functions.svg?style=for-the-badge&color=success&labelColor=27A006)](https://crates.io/crates/mini-functions) -//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.8-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/mini-functions) +//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.10-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/mini-functions) //! [![GitHub](https://img.shields.io/badge/github-555555?style=for-the-badge&labelColor=000000&logo=github)](https://github.com/sebastienrousseau/mini-functions) //! [![License](https://img.shields.io/crates/l/mini-functions.svg?style=for-the-badge&color=007EC6&labelColor=03589B)](http://opensource.org/licenses/MIT) //! diff --git a/qrc/Cargo.toml b/qrc/Cargo.toml deleted file mode 100644 index 98c0a46d..00000000 --- a/qrc/Cargo.toml +++ /dev/null @@ -1,45 +0,0 @@ -[package] -name = "qrc" -edition = "2021" -rust-version = "1.66.1" -version = "0.0.2" -authors = ["Sebastian Rousseau -
- -**[Website][0] -â€ĸ [Documentation][9] -â€ĸ [Report Bug][3] -â€ĸ [Request Feature][3] -â€ĸ [Contributing Guidelines][4]** - -
- - - -## Overview 📖 - -The QR Code Library (QRC) is a versatile tool for generating and -manipulating QR code images in various formats. - -With this library, you can easily convert your data into a QR code, -whether it be in the form of a string or a vector of bytes. - -Choose from popular image formats like PNG, JPG, GIF and SVG, and even -customize the size and color of your QR code. - -## Features ✨ - -`QRC` features a `QRCode` struct that can be constructed with a -`Vec` of data or a `String` of data that will be converted to -a `Vec`. - -The QR code can be generated using the `to_qrcode`method, and specific -image formats can be generated using the`to_png`,`to_jpg`, and`to_gif` -methods. - -Each of these methods takes a `width` parameter and returns an -`ImageBuffer` containing the QR code image. - -The library uses the qrcode and image crates to generate the QR code -images. - -## Installation đŸ“Ļ - -It takes just a few minutes to get up and running with `qrc`. - -### Requirements - -`qrc` requires Rust **1.67.0** or later. - -### Documentation - -> ℹī¸ **Info:** Please check out our [website][0] for more information -and find our documentation on [docs.rs][9], [lib.rs][10] and -[crates.io][8]. - -## Usage 📖 - -To use `qrc` in your project, add the following to your -`Cargo.toml` file: - -```toml -[dependencies] -qrc = "0.0.2" -``` - -Add the following to your `main.rs` file: - -```rust -extern crate qrc; -use qrc::*; -``` - -then you can use the functions in your application code. - -### Examples - -`QRC` comes with a set of examples that you can use to get started. The -examples are located in the `examples` directory of the project. To run -the examples, clone the repository and run the following command in your -terminal from the project root directory. - -```shell -cargo run --example qrc -``` - -## Semantic Versioning Policy đŸšĨ - -For transparency into our release cycle and in striving to maintain -backward compatibility, `QRC` follows [semantic versioning][7]. - -## License 📝 - -The project is licensed under the terms of both the MIT license and the -Apache License (Version 2.0). - -- [Apache License, Version 2.0][1] -- [MIT license][2] - -## Contribution 🤝 - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms -or conditions. - -![divider][divider] - -## Acknowledgements 💙 - -A big thank you to all the awesome contributors of [Mini Functions][6] -for their help and support. A special thank you goes to the -[Rust Reddit](https://www.reddit.com/r/rust/) community for providing a -lot of useful suggestions on how to improve this project. - -[0]: https://minifunctions.com -[1]: http://www.apache.org/licenses/LICENSE-2.0 -[2]: http://opensource.org/licenses/MIT -[3]: https://github.com/sebastienrousseau/mini-functions/issues -[4]: https://raw.githubusercontent.com/sebastienrousseau/mini-functions/main/.github/CONTRIBUTING.md -[6]: https://github.com/sebastienrousseau/mini-functions/graphs/contributors -[7]: http://semver.org/ -[8]: https://crates.io/crates/qrc -[9]: https://docs.rs/qrc -[10]: https://lib.rs/crates/qrc - -[banner]: https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/banners/banner-qrc-1597x377.svg "QRC Banner" -[crates-badge]: https://img.shields.io/crates/v/qrc.svg?style=for-the-badge 'Crates.io' -[divider]: https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/elements/divider.svg "divider" -[docs-badge]: https://img.shields.io/docsrs/qrc.svg?style=for-the-badge 'Docs.rs' -[libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.2-orange.svg?style=for-the-badge 'Lib.rs' -[license-badge]: https://img.shields.io/crates/l/qrc.svg?style=for-the-badge 'License' -[made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' diff --git a/qrc/benches/qrc.rs b/qrc/benches/qrc.rs deleted file mode 100644 index bb75b937..00000000 --- a/qrc/benches/qrc.rs +++ /dev/null @@ -1,67 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use image::Rgba; -extern crate qrc; -use self::qrc::QRCode; - -// Benchmark for QRCode::new -fn new_benchmark(c: &mut Criterion) { - c.bench_function("QRCode::new", |b| { - b.iter(|| QRCode::new(black_box(vec![1, 2, 3]))) - }); -} -// Benchmark for QRCode::to_png -fn to_png_benchmark(c: &mut Criterion) { - let qrcode = QRCode::new(vec![1, 2, 3]); - c.bench_function("QRCode::to_png", |b| b.iter(|| qrcode.to_png(512))); -} - -// Benchmark for QRCode::from_string -fn from_string_benchmark(c: &mut Criterion) { - c.bench_function("QRCode::from_string", |b| { - b.iter(|| QRCode::from_string(black_box("Hello, world!".to_string()))) - }); -} - -// Benchmark for QRCode::from_bytes -fn from_bytes_benchmark(c: &mut Criterion) { - c.bench_function("QRCode::from_bytes", |b| { - b.iter(|| QRCode::from_bytes(black_box(vec![1, 2, 3]))) - }); -} - -// Benchmark for QRCode::to_svg -fn to_svg_benchmark(c: &mut Criterion) { - let qrcode = QRCode::new(vec![1, 2, 3]); - c.bench_function("QRCode::to_svg", |b| { - b.iter(|| qrcode.to_svg(black_box(100))) - }); -} - -// Benchmark for QRCode::colorize -fn colorize_benchmark(c: &mut Criterion) { - let qrcode = QRCode::new(vec![1, 2, 3]); - let color = Rgba([0, 0, 0, 0]); - c.bench_function("QRCode::colorize", |b| { - b.iter(|| qrcode.colorize(black_box(color))) - }); -} - -// Benchmark for QRCode::resize -fn resize_benchmark(c: &mut Criterion) { - let qrcode = QRCode::new(vec![1, 2, 3]); - c.bench_function("QRCode::resize", |b| { - b.iter(|| qrcode.resize(black_box(100), black_box(100))) - }); -} - -criterion_group!( - benches, - colorize_benchmark, - from_bytes_benchmark, - from_string_benchmark, - new_benchmark, - resize_benchmark, - to_png_benchmark, - to_svg_benchmark, -); -criterion_main!(benches); diff --git a/qrc/bubba.ico b/qrc/bubba.ico deleted file mode 100644 index a1c64d1a31dc9c824e393be871876179462276af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 414950 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 z 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�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 A761SM diff --git a/qrc/build.rs b/qrc/build.rs deleted file mode 100644 index 78835927..00000000 --- a/qrc/build.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - // println!("cargo:rerun-if-changed=src/lib.rs"); - // println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/qrc/deny.toml b/qrc/deny.toml deleted file mode 100644 index 403a345e..00000000 --- a/qrc/deny.toml +++ /dev/null @@ -1,66 +0,0 @@ -[licenses] -# The lint level for crates which do not have a detectable license -unlicensed = "deny" - -# List of explicitly allowed licenses -# See https://spdx.org/licenses/ for list of possible licenses -# [possible values: any SPDX 3.7 short identifier (+ optional exception)]. -allow = ["MPL-2.0"] - -# List of explicitly disallowed licenses -# See https://spdx.org/licenses/ for list of possible licenses -# [possible values: any SPDX 3.7 short identifier (+ optional exception)]. -deny = [] - -# The lint level for licenses considered copyleft -copyleft = "deny" - -# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses -# * both - The license will only be approved if it is both OSI-approved *AND* FSF/Free -# * either - The license will be approved if it is either OSI-approved *OR* FSF/Free -# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF/Free -# * fsf-only - The license will be approved if is FSF/Free *AND NOT* OSI-approved -# * neither - The license will be denied if is FSF/Free *OR* OSI-approved -allow-osi-fsf-free = "either" - -# The confidence threshold for detecting a license from license text. -# The higher the value, the more closely the license text must be to the -# canonical license text of a valid SPDX license file. -# [possible values: any between 0.0 and 1.0]. -confidence-threshold = 0.8 - -[bans] -# Lint level for when multiple versions of the same crate are detected -multiple-versions = "warn" - -# The graph highlighting used when creating dotgraphs for crates -# with multiple versions -# * lowest-version - The path to the lowest versioned duplicate is highlighted -# * simplest-path - The path to the version with the fewest edges is highlighted -# * all - Both lowest-version and simplest-path are used -highlight = "all" - -# List of crates that are allowed. Use with care! -allow = [ -] - -# List of crates to deny -deny = [ - # Each entry the name of a crate and a version range. If version is - # not specified, all versions will be matched. -] - -# Certain crates/versions that will be skipped when doing duplicate detection. -skip = [ -] - -# Similarly to `skip` allows you to skip certain crates during duplicate detection, -# unlike skip, it also includes the entire tree of transitive dependencies starting at -# the specified crate, up to a certain depth, which is by default infinite -skip-tree = [ -] - - -[advisories] -ignore = [ -] diff --git a/qrc/examples/qrc.rs b/qrc/examples/qrc.rs deleted file mode 100644 index 2e7b58cd..00000000 --- a/qrc/examples/qrc.rs +++ /dev/null @@ -1,152 +0,0 @@ -extern crate image; -use image::{imageops, ImageBuffer, Rgba, RgbaImage}; -extern crate qrc; -use self::qrc::{add_image_watermark, qr_code, qr_code_to, QRCode}; -use std::fs; // Import the fs module from the standard library // Import the QRCode struct from the mini_functions crate - -const URL: &str = "https://minifunctions.com/"; // Define a constant for the URL to be encoded - -fn main() { - // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation - let qrcode = QRCode::from_string(URL.to_string()); // Create a new QRCode using the QRCode::from_string() function - let png = qrcode.to_png(512); // Convert the QRCode into a PNG representation - let png_data = png.into_raw(); // Convert the PNG representation of the QRCode into a vector of bytes - let png_image = ImageBuffer::, Vec>::from_raw(21, 21, png_data).unwrap(); - println!( - "đŸĻ€ fn to_png(): ✅ {:?}", - png_image.save("qrcode.png") - ); // Print the PNG representation of the QRCode - match png_image.save("qrcode.png") { - Ok(_) => println!("đŸĻ€ png file created: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - Err(e) => println!("đŸĻ€ png file created: ❌ qrcode.png: {e}"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - } - match fs::remove_file("qrcode.png") { - Ok(_) => println!("đŸĻ€ png file removed: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - Err(e) => println!("đŸĻ€ png file removed: ❌ qrcode.png: {e}"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - } - - // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom color - let qrcode = QRCode::from_string(URL.to_string()); - let red = Rgba([255, 0, 0, 255]); - let red_qrcode = qrcode.colorize(red); // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom color - let img: RgbaImage = red_qrcode; // Convert the colorized QR code to a PNG image. - let new_width = 512; - let new_height = 512; - let resized_img = imageops::resize(&img, new_width, new_height, imageops::FilterType::Nearest); - let image: ImageBuffer, Vec> = resized_img; // Convert the colorized QR code to a PNG image. - println!( - "đŸĻ€ fn colorize(): ✅ {:?}", - image.save("qrcode_colorized.png") - ); // Print the PNG representation of the QRCode - match image.save("qrcode_colorized.png") { - Ok(_) => println!("đŸĻ€ colorized png file created: ✅ qrcode_colorized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ colorized png file created: ❌ qrcode_colorized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - match fs::remove_file("qrcode_colorized.png") { - Ok(_) => println!("đŸĻ€ colorized png file removed: ✅ qrcode_colorized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ colorized png file removed: ❌ qrcode_colorized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - - // Create a new QRCode using the QRCode::from_string() function and convert it to an SVG representation - let qrcode = QRCode::from_string(URL.to_string()); - let qrcode_svg = qrcode.to_svg(512); // Convert the QRCode into an SVG representation - match fs::write("qrcode.svg", qrcode_svg) { - Ok(_) => println!("đŸĻ€ svg file created: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - Err(e) => println!("đŸĻ€ svg file created: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - } - match fs::remove_file("qrcode.svg") { - Ok(_) => println!("đŸĻ€ svg file removed: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - Err(e) => println!("đŸĻ€ svg file removed: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - } - - // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom size - let qrcode = QRCode::new(vec![0x61, 0x62, 0x63]); - let resized_image: RgbaImage = qrcode.resize(512, 512); - println!( - "đŸĻ€ fn resize(): ✅ {:?}", - resized_image.save("qrcode_resized.png") - ); // Print the PNG representation of the QRCode - match resized_image.save("qrcode_resized.png") { - Ok(_) => println!("đŸĻ€ resized file created: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ resized file created: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - match fs::remove_file("qrcode_resized.png") { - Ok(_) => println!("đŸĻ€ resized file removed: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ resized file removed: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - - // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom size - let qrcode = QRCode::new(vec![0x61, 0x62, 0x63]); - let resized_image: RgbaImage = qrcode.resize(512, 512); - println!( - "đŸĻ€ fn resize(): ✅ {:?}", - resized_image.save("qrcode_resized.png") - ); // Print the PNG representation of the QRCode with a custom size of 512x512 - match resized_image.save("qrcode_resized.png") { - Ok(_) => println!("đŸĻ€ resized file created: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ resized file created: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - match fs::remove_file("qrcode_resized.png") { - Ok(_) => println!("đŸĻ€ resized file removed: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ resized file removed: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - // Create a new QRCode using the macro qr_code and convert it to an SVG representation with a custom size of 512x512 - let qrcode = qr_code!(URL.into()); - let qrcode_svg = qrcode.to_svg(512); // Convert the QRCode into an SVG representation with a custom size of 512x512 - match fs::write("qrcode.svg", qrcode_svg) { - Ok(_) => println!("đŸĻ€ svg file created: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - Err(e) => println!("đŸĻ€ svg file created: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - } - match fs::remove_file("qrcode.svg") { - Ok(_) => println!("đŸĻ€ svg file removed: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - Err(e) => println!("đŸĻ€ svg file removed: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - } - // Create a new QRCode using the macro qr_code_to into a PNG representation with a custom size of 512x512 - let qrcode = qr_code_to!(URL.into(), "png", 512); - match qrcode.save("qrcode.png") { - Ok(_) => println!("đŸĻ€ png file created: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ png file created: ❌ qrcode.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - match fs::remove_file("qrcode.png") { - Ok(_) => println!("đŸĻ€ png file removed: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ png file removed: ❌ qrcode.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - // Create a new QRCode using the macro qr_code_from into a GIF representation with a custom size of 512x512 - let qrcode = qr_code_to!(URL.into(), "gif", 512); - match qrcode.save("qrcode.gif") { - Ok(_) => println!("đŸĻ€ gif file created: ✅ qrcode.gif"), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" - Err(e) => println!("đŸĻ€ gif file created: ❌ qrcode.gif: {e}",), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" - } - match fs::remove_file("qrcode.gif") { - Ok(_) => println!("đŸĻ€ gif file removed: ✅ qrcode.gif"), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" - Err(e) => println!("đŸĻ€ gif file removed: ❌ qrcode.gif: {e}",), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" - } - // Create a new QRCode using the macro qr_code_to into a JPEG representation with a custom size of 512x512 - let qrcode = qr_code_to!(URL.into(), "jpg", 512); - match qrcode.save("qrcode.jpg") { - Ok(_) => println!("đŸĻ€ jpg file created: ✅ qrcode.jpg"), // Print the path to the JPG representation of the QRCode that was saved to a file called "qrcode.jpg" - Err(e) => println!("đŸĻ€ jpg file created: ❌ qrcode.jpg: {e}",), // Print the path to the JPEG representation of the QRCode that was saved to a file called "qrcode.jpg" - } - match fs::remove_file("qrcode.jpg") { - Ok(_) => println!("đŸĻ€ jpg file removed: ✅ qrcode.jpg"), // Print the path to the JPG representation of the QRCode that was saved to a file called "qrcode.jpg" - Err(e) => println!("đŸĻ€ jpg file removed: ❌ qrcode.jpg: {e}",), // Print the path to the JPEG representation of the QRCode that was saved to a file called "qrcode.jpg" - } - - // Create a new QRCode add a watermark to it and save it as a PNG file - let qrcode = QRCode::from_string(URL.to_string()); - let mut qrcode_img = qrcode.to_png(512); - let watermark_img = image::open("bubba.ico").unwrap().into_rgba8(); - add_image_watermark!(&mut qrcode_img, &watermark_img); - match qrcode_img.save("qrcode_watermarked.png") { - Ok(_) => println!("đŸĻ€ png file with watermark: ✅ qrcode_watermarked.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - Err(e) => println!("đŸĻ€ png file with watermark: ❌ qrcode_watermarked.png: {e}"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - } - match fs::remove_file("qrcode_watermarked.png") { - Ok(_) => { - println!("đŸĻ€ png file with watermark removed: ✅ qrcode_watermarked.png") - } // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - Err(e) => { - println!("đŸĻ€ png file with watermark removed: ❌ qrcode_watermarked.png: {e}") - } // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - } -} diff --git a/qrc/rustfmt.toml b/qrc/rustfmt.toml deleted file mode 100644 index 19c37103..00000000 --- a/qrc/rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -# default \ No newline at end of file diff --git a/qrc/src/lib.rs b/qrc/src/lib.rs deleted file mode 100644 index 1ad4aca7..00000000 --- a/qrc/src/lib.rs +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright Š 2022-2023 Mini Functions. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT -//! -//! # A Rust library for generating and manipulating QR code images in various formats -//! -//! [![Rust](https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/logo/logo-qrc.svg)](https://minifunctions.com) -//! -//!
-//! -//! [![Rust](https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust)](https://www.rust-lang.org) -//! [![Crates.io](https://img.shields.io/crates/v/qrc.svg?style=for-the-badge&color=success&labelColor=27A006)](https://crates.io/crates/qrc/) -//! [![Docs.rs](https://img.shields.io/badge/docs.rs-v0.0.1-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://docs.rs/qrc) -//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.1-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/qrc) -//! [![GitHub](https://img.shields.io/badge/github-555555?style=for-the-badge&labelColor=000000&logo=github)](https://github.com/sebastienrousseau/mini-functions/tree/main/qrc) -//! [![License](https://img.shields.io/crates/l/qrc.svg?style=for-the-badge&color=007EC6&labelColor=03589B)](http://opensource.org/licenses/MIT) -//! -//!
-//! -//! ## Overview -//! -//! The QR Code Library (QRC) is a versatile tool for generating and -//! manipulating QR code images in various formats. -//! -//! With this library, you can easily convert your data into a QR code, -//! whether it be in the form of a string or a vector of bytes. -//! -//! Choose from popular image formats like PNG, JPG, GIF and SVG, and -//! even customize the size and color of your QR code. -//! -//! ## Features -//! -//! `QRC` features a `QRCode` struct that can be constructed with a -//! `Vec` of data or a `String` of data that will be converted to -//! a `Vec`. -//! -//! The QR code can be generated using the zto_qrcode` method, and -//! specific image formats can be generated using the `to_png`, -//! `to_jpg`, and `to_gif` methods. -//! -//! Each of these methods takes a `width` parameter and returns an -//! `ImageBuffer` containing the QR code image. -//! -//! The library uses the qrcode and image crates to generate the QR -//! code images. -//! -//! As of the current version, the library supports the following -//! features with the following status: -//! -//! | Feature | Description | -//! | ------- | ----------- | -//! | Library license | Apache-2.0 OR MIT | -//! | Library version | 0.0.1 | -//! | Mode Numeric | not specified | -//! | Mode Alphanumeric | not specified | -//! | Mode Byte | not specified | -//! | Mode Kanji | not specified | -//! | Mode ECI | not specified | -//! | Mode FNC1 | not specified | -//! | Mode Structured Append | not specified | -//! | Mode Hanzi | not specified | -//! | Mixing modes | not specified | -//! | QR Codes version 1 - 40 | not specified | -//! | Micro QR Codes version M1 - M4 | not specified | -//! | Find maximal error correction level | not specified | -//! | Optimize QR Codes | not specified | -//! | PNG output | supported | -//! | JPG output | supported | -//! | GIF output | supported | -//! | SVG output | supported | -//! | EPS output | not specified | -//! | PDF output | not specified | -//! | BMP output | not specified | -//! | TIFF output | not specified | -//! | WebP output | not specified | -//! | Black and white QR Codes | Yes | -//! | Colorized QR code | Yes | -//! | Animated QR Codes (GIF, APNG, WebP) | not specified | -//! | Changing size of modules (scaling factor) | not specified | -//! | Command line script | not specified | -//! | QR code resizing | supported | -//! | QR code watermarking | supported | -//! | QR code with logo | supported | -//! -//! ## Usage -//! -//! - [`serde`][]: Enable serialization/deserialization via serde -//! -//! [`serde`]: https://github.com/serde-rs/serde -//! -#![cfg_attr(feature = "bench", feature(test))] -#![deny(dead_code)] -#![deny(missing_debug_implementations)] -#![deny(missing_docs)] -#![forbid(unsafe_code)] -#![warn(unreachable_pub)] -#![doc( - html_favicon_url = "https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/icons/ico-qrc.svg", - html_logo_url = "https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/icons/ico-qrc.svg", - html_root_url = "https://docs.rs/mini-functions" -)] -#![crate_name = "qrc"] -#![crate_type = "lib"] - -extern crate image; -extern crate qrcode; - -use image::{ImageBuffer, Rgba, RgbaImage}; -use qrcode::render::svg; -use qrcode::QrCode; - -#[non_exhaustive] -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] -/// QRCode is a structure that contains data in the form of a vector of -/// bytes. -pub struct QRCode { - /// The `data` field holds the data to be encoded in the QR code. - pub data: Vec, -} -/// Implementation of QRCode structure. -impl QRCode { - /// Creates a new QRCode structure with the given data. - pub fn new(data: Vec) -> Self { - QRCode { data } - } - - /// The `from_string` method creates a new instance of the QRCode - /// struct by converting the given string data into a vector of - /// bytes - pub fn from_string(data: String) -> Self { - QRCode { - data: data.into_bytes(), - } - } - - /// Creates a new QRCode structure from a vector of bytes. - pub fn from_bytes(data: Vec) -> Self { - QRCode { data } - } - - /// Converts the QRCode structure to a QrCode structure. - pub fn to_qrcode(&self) -> QrCode { - QrCode::new(&self.data).unwrap() - } - - /// Converts the QRCode structure to a PNG image. - pub fn to_png(&self, width: u32) -> ImageBuffer, Vec> { - let qrcode = self.to_qrcode(); - let height = width; - let mut img = ImageBuffer::new(width, height); - for (x, y, pixel) in img.enumerate_pixels_mut() { - let x_index = (x as f32 / width as f32) * qrcode.width() as f32; - let y_index = (y as f32 / height as f32) * qrcode.width() as f32; - *pixel = match qrcode[(x_index as usize, y_index as usize)] { - qrcode::Color::Dark => Rgba([0, 0, 0, 0]), - qrcode::Color::Light => Rgba([255, 255, 255, 255]), - }; - } - img - } - /// Converts the QRCode structure to a JPG image. - pub fn to_jpg(&self, width: u32) -> ImageBuffer, Vec> { - let qrcode = self.to_qrcode(); - let height = width; - let mut img = ImageBuffer::new(width, height); - for (x, y, pixel) in img.enumerate_pixels_mut() { - let x_index = (x as f32 / width as f32) * qrcode.width() as f32; - let y_index = (y as f32 / height as f32) * qrcode.width() as f32; - *pixel = match qrcode[(x_index as usize, y_index as usize)] { - qrcode::Color::Dark => Rgba([0, 0, 0, 0]), - qrcode::Color::Light => Rgba([255, 255, 255, 255]), - }; - } - img - } - /// Converts the QRCode structure to a GIF image. - pub fn to_gif(&self, width: u32) -> ImageBuffer, Vec> { - let qrcode = self.to_qrcode(); - let height = width; - let mut img = ImageBuffer::new(width, height); - for (x, y, pixel) in img.enumerate_pixels_mut() { - let x_index = (x as f32 / width as f32) * qrcode.width() as f32; - let y_index = (y as f32 / height as f32) * qrcode.width() as f32; - *pixel = match qrcode[(x_index as usize, y_index as usize)] { - qrcode::Color::Dark => Rgba([0, 0, 0, 0]), - qrcode::Color::Light => Rgba([255, 255, 255, 255]), - }; - } - img - } - - /// Converts the QRCode structure to an SVG image. - pub fn to_svg(&self, width: u32) -> String { - let qrcode = self.to_qrcode(); - let svg_string = qrcode - .render::() - .min_dimensions(width, width) - .dark_color(svg::Color("#000000")) - .light_color(svg::Color("#FFFFFF")) - .build(); - svg_string - } - - /// The `colorize` method creates a new PNG image of the QR code - /// using the data stored in the QRCode and the given color value to - /// colorize the QR code. - pub fn colorize(&self, color: Rgba) -> RgbaImage { - let qrcode = self.to_qrcode(); - let mut img: RgbaImage = ImageBuffer::new(qrcode.width() as u32, qrcode.width() as u32); - for (x, y, pixel) in img.enumerate_pixels_mut() { - let c = if qrcode[(x as usize, y as usize)] == qrcode::Color::Dark { - color - } else { - Rgba([255, 255, 255, 255]) - }; - *pixel = c; - } - img - } - - /// The `resize` method creates a new PNG image of the QR code using - /// the data stored in the QRCode and the given width and height - /// values to resize the QR code. - pub fn resize(&self, width: u32, height: u32) -> RgbaImage { - let qrcode = self.to_qrcode(); - let mut img: RgbaImage = ImageBuffer::new(width, height); - for y in 0..height { - for x in 0..width { - let x_index = (x as f32 / width as f32) * qrcode.width() as f32; - let y_index = (y as f32 / height as f32) * qrcode.width() as f32; - let c = match qrcode[(x_index as usize, y_index as usize)] { - qrcode::Color::Dark => Rgba([0, 0, 0, 0]), - qrcode::Color::Light => Rgba([255, 255, 255, 255]), - }; - img.put_pixel(x, y, c); - } - } - img - } - /// The `add_image_watermark` method adds a watermark to the given image. - pub fn add_image_watermark(img: &mut RgbaImage, watermark: &RgbaImage) { - let (width, height) = img.dimensions(); - let (watermark_width, watermark_height) = watermark.dimensions(); - - // position the watermark in the bottom right corner - let x = width - watermark_width; - let y = height - watermark_height; - - // draw the watermark on the QR code image - for (dx, dy, watermark_pixel) in watermark.enumerate_pixels() { - let x = x + dx; - let y = y + dy; - let qr_pixel = img.get_pixel(x, y); - - let alpha = (watermark_pixel[3] as f32) / 255.0; - let new_r = (1.0 - alpha) * (qr_pixel[0] as f32) + alpha * (watermark_pixel[0] as f32); - let new_g = (1.0 - alpha) * (qr_pixel[1] as f32) + alpha * (watermark_pixel[1] as f32); - let new_b = (1.0 - alpha) * (qr_pixel[2] as f32) + alpha * (watermark_pixel[2] as f32); - let new_a = (qr_pixel[3] as f32) + alpha * (255.0 - qr_pixel[3] as f32); - - let new_pixel = [new_r as u8, new_g as u8, new_b as u8, new_a as u8]; - img.put_pixel(x, y, image::Rgba(new_pixel)); - } - } -} - -#[macro_export] -/// The `add_emoji_watermark` macro creates a new instance of the QRCode struct -/// with the given data. -macro_rules! add_image_watermark { - ($img:expr, $watermark:expr) => { - QRCode::add_image_watermark($img, $watermark) - }; -} - -#[macro_export] -/// The `qr_code` macro creates a new instance of the QRCode struct -/// with the given data. -macro_rules! qr_code { - ($data:expr) => { - QRCode::new($data) - }; -} - -#[macro_export] -/// Define a macro named `qr_code_to` -macro_rules! qr_code_to { - // This macro takes two expressions: `$data` and `$format` - ($data:expr, $format:expr, $width:expr) => { - // Match the value of `$format` - match $format { - // If `$format` is equal to "png", generate a PNG format QR code using `QRCode::from_bytes` - "png" => QRCode::from_bytes($data).to_png($width), - // If `$format` is equal to "jpg", generate a JPG format QR code using `QRCode::from_bytes` - "jpg" => QRCode::from_bytes($data).to_jpg($width), - // If `$format` is equal to "gif", generate a "gif" format QR code using `QRCode::from_bytes` - "gif" => QRCode::from_bytes($data).to_gif($width), - // For any other value, panic with the message "Invalid format" - _ => panic!("Invalid format"), - } - }; -} diff --git a/qrc/tests/qr.rs b/qrc/tests/qr.rs deleted file mode 100644 index def353bb..00000000 --- a/qrc/tests/qr.rs +++ /dev/null @@ -1,147 +0,0 @@ -#[cfg(test)] -mod tests { - extern crate image; - use image::{Rgba, RgbaImage}; - - extern crate qrc; - use qrc::{add_image_watermark, qr_code, qr_code_to, QRCode}; - - const URL: &str = "https://minifunctions.com/"; // Define a constant for the URL to be encoded - - #[test] - fn test_new() { - let data = vec![0x61, 0x62, 0x63]; - let qrcode = QRCode::new(data.clone()); - assert_eq!(qrcode.data, data); - } - - #[test] - fn test_from_string() { - let data = "abc".to_string(); - let qrcode = QRCode::from_string(data.clone()); - assert_eq!(qrcode.data, data.into_bytes()); - } - - #[test] - fn test_from_bytes() { - let data = vec![0x61, 0x62, 0x63]; - let qrcode = QRCode::from_bytes(data.clone()); - assert_eq!(qrcode.data, data); - } - - #[test] - fn test_to_qrcode() { - let data = vec![0x61, 0x62, 0x63]; - let qrcode = QRCode::from_bytes(data.clone()); - assert_eq!(qrcode.data, data); - } - - #[test] - fn test_to_png() { - let data = vec![0x61, 0x62, 0x63]; - let qrcode = QRCode::from_bytes(data.clone()); - assert_eq!(qrcode.data, data); - - let qrcode = QRCode::from_string("Hello, world!".to_string()); - let png = qrcode.to_png(21); - assert_eq!(png.dimensions(), (21, 21)); - - let png_data = png.into_raw(); - assert_eq!(png_data.len(), 1764); - } - #[test] - fn test_to_svg() { - let data = vec![0x61, 0x62, 0x63]; - let qrcode = QRCode::from_bytes(data.clone()); - assert_eq!(qrcode.data, data); - - let qrcode = QRCode::from_string(URL.to_string()); - let qrcode_svg = qrcode.to_svg(512); - assert_eq!(qrcode_svg.len(), 6918); - } - #[test] - fn test_to_gif() { - let data = vec![0x61, 0x62, 0x63]; - let qrcode = QRCode::from_bytes(data.clone()); - assert_eq!(qrcode.data, data); - - let qrcode = QRCode::from_string(URL.to_string()); - let qrcode_gif = qrcode.to_gif(512); - assert_eq!(qrcode_gif.len(), 1048576); - } - #[test] - fn test_to_jpg() { - let data = vec![0x61, 0x62, 0x63]; - let qrcode = QRCode::from_bytes(data.clone()); - assert_eq!(qrcode.data, data); - - let qrcode = QRCode::from_string(URL.to_string()); - let qrcode_jpg = qrcode.to_jpg(512); - assert_eq!(qrcode_jpg.len(), 1048576); - } - #[test] - fn test_add_image_watermark() { - let data = vec![0x61, 0x62, 0x63]; - let qrcode = QRCode::from_bytes(data.clone()); - assert_eq!(qrcode.data, data); - - let qrcode = QRCode::from_string(URL.to_string()); - let mut qrcode_img = qrcode.to_png(512); - let watermark_img = image::open("bubba.ico").unwrap().into_rgba8(); - add_image_watermark!(&mut qrcode_img, &watermark_img); - assert_eq!(qrcode_img.dimensions(), (512, 512)); - } - #[test] - fn test_colorize() { - // Create a new QR code with some data. - let qrcode = QRCode::new(vec![0, 1, 2, 3]); - - // Colorize the QR code with a red color. - let red_qrcode = qrcode.colorize(Rgba([255, 0, 0, 255])); - - // Convert the QR code to a PNG image and assert that all of the dark cells are red. - let image: RgbaImage = red_qrcode; - for (x, y, pixel) in image.enumerate_pixels() { - let expected_color = if qrcode.to_qrcode()[(x as usize, y as usize)] - == qrcode::Color::Dark - { - Rgba([255, 0, 0, 255]) - } else { - Rgba([255, 255, 255, 255]) - }; - assert_eq!(*pixel, expected_color); - } - } - #[test] - fn test_resize() { - // Create a new QR code with some data. - let qrcode = QRCode::new(vec![0, 1, 2, 3]); - - // Resize the QR code to 42x42 pixels. - let resized_qrcode = qrcode.resize(42, 42); - - // Convert the QR code to a PNG image and assert that the dimensions are correct. - let image: RgbaImage = resized_qrcode; - assert_eq!(image.dimensions(), (42, 42)); - } - - #[test] - fn test_qr_code() { - let data = vec![0x61, 0x62, 0x63]; - let qrcode = qr_code!(data.clone()); - assert_eq!(qrcode.data, data); - } - #[test] - fn test_qr_code_from_png() { - let data = vec![0x61, 0x62, 0x63]; - let result = qr_code_to!(data.clone(), "png", 512); - let expected = QRCode::from_bytes(data).to_png(512); - assert_eq!(result, expected); - } - #[test] - #[should_panic(expected = "Invalid format")] - fn test_qr_code_from_invalid_format() { - let data = vec![0u8, 1, 2, 3]; - let _result = qr_code_to!(data, "jpeg", 512); - } -} diff --git a/src/claims.rs b/src/claims.rs index 1d5f63bf..da4439e0 100644 --- a/src/claims.rs +++ b/src/claims.rs @@ -5,8 +5,5 @@ //! //! Provides access to JWT claims functions and types. -/// Re-exported module containing JWT claim related types. -pub use cclm::*; - /// Re-exported [`Claims`] struct from cclm for accessing JWT claims. pub use cclm::Claims; diff --git a/src/lib.rs b/src/lib.rs index 8a39172c..6adb2616 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ //! [![GitHub](https://img.shields.io/badge/github-555555?style=for-the-badge&labelColor=000000&logo=github)](https://github.com/sebastienrousseau/mini-functions) //! [![Rust](https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust)](https://www.rust-lang.org) //! [![Crates.io](https://img.shields.io/crates/v/mini-functions.svg?style=for-the-badge&color=success&labelColor=27A006)](https://crates.io/crates/mini-functions) -//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.8-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/mini-functions) +//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.10-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/mini-functions) //! [![License](https://img.shields.io/crates/l/mini-functions.svg?style=for-the-badge&color=007EC6&labelColor=03589B)](http://opensource.org/licenses/MIT) //! //! From b0acf56bb833485db24adc6001a59d28a792aa26 Mon Sep 17 00:00:00 2001 From: Sebastien Rousseau Date: Fri, 29 Dec 2023 02:07:00 +0000 Subject: [PATCH 3/5] fix(mini-functions): :ambulance: added missing examples for qrc --- examples/example_qr.rs | 237 ++++++++++++++++++++++++----------------- 1 file changed, 137 insertions(+), 100 deletions(-) diff --git a/examples/example_qr.rs b/examples/example_qr.rs index 7afbd9ef..0e0e2483 100644 --- a/examples/example_qr.rs +++ b/examples/example_qr.rs @@ -1,118 +1,155 @@ // Copyright Š 2023 Mini Functions library. All rights reserved. // SPDX-License-Identifier: Apache-2.0 OR MIT -use image::{Rgba, RgbaImage}; -use mini_functions::qr::QRCode; -use mini_functions::qr::{add_image_watermark, qr_code_to}; extern crate image; -use std::fs; +use image::{imageops, ImageBuffer, Rgba, RgbaImage}; +extern crate qrc; +use self::qrc::{add_image_watermark, qr_code, qr_code_to, QRCode}; +use std::fs; // Import the fs module from the standard library // Import the QRCode struct from the mini_functions crate -const URL: &str = "https://minifunctions.com/"; +const URL: &str = "https://minifunctions.com/"; // Define a constant for the URL to be encoded -fn add_watermark_to_qrcode( - qrcode: &mut RgbaImage, - watermark_path: &str, -) -> Result<(), String> { - match image::open(watermark_path) { - Ok(watermark_img) => { - let watermark_rgba = watermark_img.into_rgba8(); - add_image_watermark!(qrcode, &watermark_rgba); - Ok(()) - } - Err(e) => Err(format!("Failed to open watermark image: {}", e)), - } -} - -fn process_qrcode(url: &str, process_fn: F, file_name: &str) -where - F: FnOnce(&QRCode) -> RgbaImage, -{ - let qrcode = QRCode::from_string(url.to_string()); - let image = process_fn(&qrcode); - save_image(&image, file_name); -} - -fn save_image(image: &RgbaImage, file_name: &str) { - match image.save(file_name) { - Ok(_) => println!("đŸĻ€ File created: ✅ {}", file_name), - Err(e) => { - println!("đŸĻ€ File creation failed: ❌ {}: {}", file_name, e) - } +fn main() { + // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation + let qrcode = QRCode::from_string(URL.to_string()); // Create a new QRCode using the QRCode::from_string() function + let png = qrcode.to_png(512); // Convert the QRCode into a PNG representation + let png_data = png.into_raw(); // Convert the PNG representation of the QRCode into a vector of bytes + let png_image = ImageBuffer::, Vec>::from_raw(21, 21, png_data).unwrap(); + println!( + "đŸĻ€ fn to_png(): ✅ {:?}", + png_image.save("qrcode.png") + ); // Print the PNG representation of the QRCode + match png_image.save("qrcode.png") { + Ok(_) => println!("đŸĻ€ png file created: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" + Err(e) => println!("đŸĻ€ png file created: ❌ qrcode.png: {e}"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" } -} - -fn save_svg(data: &str, file_name: &str) { - match fs::write(file_name, data) { - Ok(_) => println!("đŸĻ€ File created: ✅ {}", file_name), - Err(e) => { - println!("đŸĻ€ File creation failed: ❌ {}: {}", file_name, e) - } + match fs::remove_file("qrcode.png") { + Ok(_) => println!("đŸĻ€ png file removed: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" + Err(e) => println!("đŸĻ€ png file removed: ❌ qrcode.png: {e}"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" } -} -fn remove_file(file_name: &str) { - match fs::remove_file(file_name) { - Ok(_) => println!("đŸĻ€ File removed: ✅ {}", file_name), - Err(e) => { - println!("đŸĻ€ File removal failed: ❌ {}: {}", file_name, e) - } + // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom color + let qrcode = QRCode::from_string(URL.to_string()); + let red = Rgba([255, 0, 0, 255]); + let red_qrcode = qrcode.colorize(red); // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom color + let img: RgbaImage = red_qrcode; // Convert the colorized QR code to a PNG image. + let new_width = 512; + let new_height = 512; + let resized_img = imageops::resize(&img, new_width, new_height, imageops::FilterType::Nearest); + let image: ImageBuffer, Vec> = resized_img; // Convert the colorized QR code to a PNG image. + println!( + "đŸĻ€ fn colorize(): ✅ {:?}", + image.save("qrcode_colorized.png") + ); // Print the PNG representation of the QRCode + match image.save("qrcode_colorized.png") { + Ok(_) => println!("đŸĻ€ colorized png file created: ✅ qrcode_colorized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + Err(e) => println!("đŸĻ€ colorized png file created: ❌ qrcode_colorized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + } + match fs::remove_file("qrcode_colorized.png") { + Ok(_) => println!("đŸĻ€ colorized png file removed: ✅ qrcode_colorized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + Err(e) => println!("đŸĻ€ colorized png file removed: ❌ qrcode_colorized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" } -} - -fn main() { - // Generate QR Code, save it as a PNG file and remove it after. - process_qrcode(URL, |qrcode| qrcode.to_png(512), "qrcode.png"); - remove_file("qrcode.png"); - - // Generate QR colorized QR Code, save it as a PNG file and remove it after. - process_qrcode( - URL, - |qrcode| qrcode.colorize(Rgba([255, 0, 0, 255])), - "qrcode_colorized.png", - ); - remove_file("qrcode_colorized.png"); - - // Generate QR Code, resize it and save it as a PNG file and remove it after. - process_qrcode( - URL, - |qrcode| qrcode.resize(512, 512), - "qrcode_resized.png", - ); - remove_file("qrcode_resized.png"); - // SVG creation with decoupled functions + // Create a new QRCode using the QRCode::from_string() function and convert it to an SVG representation let qrcode = QRCode::from_string(URL.to_string()); - let qrcode_svg = qrcode.to_svg(512); - save_svg(&qrcode_svg, "qrcode.svg"); - remove_file("qrcode.svg"); + let qrcode_svg = qrcode.to_svg(512); // Convert the QRCode into an SVG representation + match fs::write("qrcode.svg", qrcode_svg) { + Ok(_) => println!("đŸĻ€ svg file created: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" + Err(e) => println!("đŸĻ€ svg file created: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" + } + match fs::remove_file("qrcode.svg") { + Ok(_) => println!("đŸĻ€ svg file removed: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" + Err(e) => println!("đŸĻ€ svg file removed: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" + } - // QRCode with custom data - let custom_qrcode = QRCode::new(vec![0x61, 0x62, 0x63]); - let custom_qr_image = custom_qrcode.resize(512, 512); - save_image(&custom_qr_image, "qrcode_custom.png"); - remove_file("qrcode_custom.png"); + // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom size + let qrcode = QRCode::new(vec![0x61, 0x62, 0x63]); + let resized_image: RgbaImage = qrcode.resize(512, 512); + println!( + "đŸĻ€ fn resize(): ✅ {:?}", + resized_image.save("qrcode_resized.png") + ); // Print the PNG representation of the QRCode + match resized_image.save("qrcode_resized.png") { + Ok(_) => println!("đŸĻ€ resized file created: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + Err(e) => println!("đŸĻ€ resized file created: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + } + match fs::remove_file("qrcode_resized.png") { + Ok(_) => println!("đŸĻ€ resized file removed: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + Err(e) => println!("đŸĻ€ resized file removed: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + } + // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom size + let qrcode = QRCode::new(vec![0x61, 0x62, 0x63]); + let resized_image: RgbaImage = qrcode.resize(512, 512); + println!( + "đŸĻ€ fn resize(): ✅ {:?}", + resized_image.save("qrcode_resized.png") + ); // Print the PNG representation of the QRCode with a custom size of 512x512 + match resized_image.save("qrcode_resized.png") { + Ok(_) => println!("đŸĻ€ resized file created: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + Err(e) => println!("đŸĻ€ resized file created: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + } + match fs::remove_file("qrcode_resized.png") { + Ok(_) => println!("đŸĻ€ resized file removed: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + Err(e) => println!("đŸĻ€ resized file removed: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + } + // Create a new QRCode using the macro qr_code and convert it to an SVG representation with a custom size of 512x512 + let qrcode = qr_code!(URL.into()); + let qrcode_svg = qrcode.to_svg(512); // Convert the QRCode into an SVG representation with a custom size of 512x512 + match fs::write("qrcode.svg", qrcode_svg) { + Ok(_) => println!("đŸĻ€ svg file created: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" + Err(e) => println!("đŸĻ€ svg file created: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" + } + match fs::remove_file("qrcode.svg") { + Ok(_) => println!("đŸĻ€ svg file removed: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" + Err(e) => println!("đŸĻ€ svg file removed: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" + } // Create a new QRCode using the macro qr_code_to into a PNG representation with a custom size of 512x512 - // Note: Assuming you have these macros implemented - let qrcode_png = qr_code_to!(URL.into(), "png", 512); - save_image(&qrcode_png, "qrcode_macro.png"); - remove_file("qrcode_macro.png"); - - // Create a new QRCode using the macro qr_code_to into a GIF representation with a custom size of 512x512 - let qrcode_gif = qr_code_to!(URL.into(), "gif", 512); - save_image(&qrcode_gif, "qrcode_macro.gif"); - remove_file("qrcode_macro.gif"); - - // Add watermark to QRCode and save - let watermark_qrcode = QRCode::from_string(URL.to_string()); - let mut watermark_qr_img = watermark_qrcode.to_png(512); + let qrcode = qr_code_to!(URL.into(), "png", 512); + match qrcode.save("qrcode.png") { + Ok(_) => println!("đŸĻ€ png file created: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + Err(e) => println!("đŸĻ€ png file created: ❌ qrcode.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + } + match fs::remove_file("qrcode.png") { + Ok(_) => println!("đŸĻ€ png file removed: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + Err(e) => println!("đŸĻ€ png file removed: ❌ qrcode.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" + } + // Create a new QRCode using the macro qr_code_from into a GIF representation with a custom size of 512x512 + let qrcode = qr_code_to!(URL.into(), "gif", 512); + match qrcode.save("qrcode.gif") { + Ok(_) => println!("đŸĻ€ gif file created: ✅ qrcode.gif"), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" + Err(e) => println!("đŸĻ€ gif file created: ❌ qrcode.gif: {e}",), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" + } + match fs::remove_file("qrcode.gif") { + Ok(_) => println!("đŸĻ€ gif file removed: ✅ qrcode.gif"), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" + Err(e) => println!("đŸĻ€ gif file removed: ❌ qrcode.gif: {e}",), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" + } + // Create a new QRCode using the macro qr_code_to into a JPEG representation with a custom size of 512x512 + let qrcode = qr_code_to!(URL.into(), "jpg", 512); + match qrcode.save("qrcode.jpg") { + Ok(_) => println!("đŸĻ€ jpg file created: ✅ qrcode.jpg"), // Print the path to the JPG representation of the QRCode that was saved to a file called "qrcode.jpg" + Err(e) => println!("đŸĻ€ jpg file created: ❌ qrcode.jpg: {e}",), // Print the path to the JPEG representation of the QRCode that was saved to a file called "qrcode.jpg" + } + match fs::remove_file("qrcode.jpg") { + Ok(_) => println!("đŸĻ€ jpg file removed: ✅ qrcode.jpg"), // Print the path to the JPG representation of the QRCode that was saved to a file called "qrcode.jpg" + Err(e) => println!("đŸĻ€ jpg file removed: ❌ qrcode.jpg: {e}",), // Print the path to the JPEG representation of the QRCode that was saved to a file called "qrcode.jpg" + } - match add_watermark_to_qrcode(&mut watermark_qr_img, "bubba.ico") { + // Create a new QRCode add a watermark to it and save it as a PNG file + let qrcode = QRCode::from_string(URL.to_string()); + let mut qrcode_img = qrcode.to_png(512); + let watermark_img = image::open("bubba.ico").unwrap().into_rgba8(); + add_image_watermark!(&mut qrcode_img, &watermark_img); + match qrcode_img.save("qrcode_watermarked.png") { + Ok(_) => println!("đŸĻ€ png file with watermark: ✅ qrcode_watermarked.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" + Err(e) => println!("đŸĻ€ png file with watermark: ❌ qrcode_watermarked.png: {e}"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" + } + match fs::remove_file("qrcode_watermarked.png") { Ok(_) => { - save_image(&watermark_qr_img, "qrcode_watermarked.png") - } - Err(e) => println!("đŸĻ€ Error adding watermark: {}", e), + println!("đŸĻ€ png file with watermark removed: ✅ qrcode_watermarked.png") + } // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" + Err(e) => { + println!("đŸĻ€ png file with watermark removed: ❌ qrcode_watermarked.png: {e}") + } // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" } - - remove_file("qrcode_watermarked.png"); -} +} \ No newline at end of file From 9719fe99b1f28aac25fc6a365bfff3a87b0f2f0f Mon Sep 17 00:00:00 2001 From: Sebastien Rousseau Date: Fri, 29 Dec 2023 02:14:28 +0000 Subject: [PATCH 4/5] fix(mini-functions): :bug: Function with cyclomatic complexity higher than threshold --- examples/example_qr.rs | 190 +++++++++++------------------------------ 1 file changed, 52 insertions(+), 138 deletions(-) diff --git a/examples/example_qr.rs b/examples/example_qr.rs index 0e0e2483..52fb55cd 100644 --- a/examples/example_qr.rs +++ b/examples/example_qr.rs @@ -4,152 +4,66 @@ extern crate image; use image::{imageops, ImageBuffer, Rgba, RgbaImage}; extern crate qrc; -use self::qrc::{add_image_watermark, qr_code, qr_code_to, QRCode}; -use std::fs; // Import the fs module from the standard library // Import the QRCode struct from the mini_functions crate +use self::qrc::{QRCode}; -const URL: &str = "https://minifunctions.com/"; // Define a constant for the URL to be encoded +use std::fs; + +const URL: &str = "https://minifunctions.com/"; fn main() { - // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation - let qrcode = QRCode::from_string(URL.to_string()); // Create a new QRCode using the QRCode::from_string() function - let png = qrcode.to_png(512); // Convert the QRCode into a PNG representation - let png_data = png.into_raw(); // Convert the PNG representation of the QRCode into a vector of bytes - let png_image = ImageBuffer::, Vec>::from_raw(21, 21, png_data).unwrap(); - println!( - "đŸĻ€ fn to_png(): ✅ {:?}", - png_image.save("qrcode.png") - ); // Print the PNG representation of the QRCode - match png_image.save("qrcode.png") { - Ok(_) => println!("đŸĻ€ png file created: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - Err(e) => println!("đŸĻ€ png file created: ❌ qrcode.png: {e}"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - } - match fs::remove_file("qrcode.png") { - Ok(_) => println!("đŸĻ€ png file removed: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - Err(e) => println!("đŸĻ€ png file removed: ❌ qrcode.png: {e}"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - } + generate_and_process_qrcode(); +} - // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom color +fn generate_and_process_qrcode() { let qrcode = QRCode::from_string(URL.to_string()); + process_png(&qrcode, "qrcode.png"); + process_png_with_custom_color(&qrcode, "qrcode_colorized.png"); + process_svg(&qrcode, "qrcode.svg"); + process_resized_qrcode(&qrcode, "qrcode_resized.png"); + // Add additional QR code processing functions here as needed. +} + +fn process_png(qrcode: &QRCode, filename: &str) { + let png = qrcode.to_png(512); + save_and_remove_file(png.into_raw(), filename, 512, 512); +} + +fn process_png_with_custom_color(qrcode: &QRCode, filename: &str) { let red = Rgba([255, 0, 0, 255]); - let red_qrcode = qrcode.colorize(red); // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom color - let img: RgbaImage = red_qrcode; // Convert the colorized QR code to a PNG image. - let new_width = 512; - let new_height = 512; - let resized_img = imageops::resize(&img, new_width, new_height, imageops::FilterType::Nearest); - let image: ImageBuffer, Vec> = resized_img; // Convert the colorized QR code to a PNG image. - println!( - "đŸĻ€ fn colorize(): ✅ {:?}", - image.save("qrcode_colorized.png") - ); // Print the PNG representation of the QRCode - match image.save("qrcode_colorized.png") { - Ok(_) => println!("đŸĻ€ colorized png file created: ✅ qrcode_colorized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ colorized png file created: ❌ qrcode_colorized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - match fs::remove_file("qrcode_colorized.png") { - Ok(_) => println!("đŸĻ€ colorized png file removed: ✅ qrcode_colorized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ colorized png file removed: ❌ qrcode_colorized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } + let red_qrcode = qrcode.colorize(red); + let img: RgbaImage = red_qrcode; + let resized_img = imageops::resize(&img, 512, 512, imageops::FilterType::Nearest); + save_and_remove_file(resized_img.into_raw(), filename, 512, 512); +} - // Create a new QRCode using the QRCode::from_string() function and convert it to an SVG representation - let qrcode = QRCode::from_string(URL.to_string()); - let qrcode_svg = qrcode.to_svg(512); // Convert the QRCode into an SVG representation - match fs::write("qrcode.svg", qrcode_svg) { - Ok(_) => println!("đŸĻ€ svg file created: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - Err(e) => println!("đŸĻ€ svg file created: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - } - match fs::remove_file("qrcode.svg") { - Ok(_) => println!("đŸĻ€ svg file removed: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - Err(e) => println!("đŸĻ€ svg file removed: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - } +fn process_svg(qrcode: &QRCode, filename: &str) { + let svg_data = qrcode.to_svg(512); + match fs::write(filename, svg_data) { + Ok(_) => println!("đŸĻ€ SVG file created: ✅ {}", filename), + Err(e) => println!("đŸĻ€ SVG file creation failed: ❌ {}: {}", filename, e), + } + remove_file(filename); +} - // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom size - let qrcode = QRCode::new(vec![0x61, 0x62, 0x63]); - let resized_image: RgbaImage = qrcode.resize(512, 512); - println!( - "đŸĻ€ fn resize(): ✅ {:?}", - resized_image.save("qrcode_resized.png") - ); // Print the PNG representation of the QRCode - match resized_image.save("qrcode_resized.png") { - Ok(_) => println!("đŸĻ€ resized file created: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ resized file created: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - match fs::remove_file("qrcode_resized.png") { - Ok(_) => println!("đŸĻ€ resized file removed: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ resized file removed: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } +fn process_resized_qrcode(qrcode: &QRCode, filename: &str) { + let png = qrcode.to_png(512); + let img: RgbaImage = ImageBuffer::from_raw(512, 512, png.into_raw()).unwrap(); + let resized_img = imageops::resize(&img, 256, 256, imageops::FilterType::Nearest); // Example resizing + save_and_remove_file(resized_img.into_raw(), filename, 256, 256); +} - // Create a new QRCode using the QRCode::from_string() function and convert it to a PNG representation with a custom size - let qrcode = QRCode::new(vec![0x61, 0x62, 0x63]); - let resized_image: RgbaImage = qrcode.resize(512, 512); - println!( - "đŸĻ€ fn resize(): ✅ {:?}", - resized_image.save("qrcode_resized.png") - ); // Print the PNG representation of the QRCode with a custom size of 512x512 - match resized_image.save("qrcode_resized.png") { - Ok(_) => println!("đŸĻ€ resized file created: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ resized file created: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - match fs::remove_file("qrcode_resized.png") { - Ok(_) => println!("đŸĻ€ resized file removed: ✅ qrcode_resized.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ resized file removed: ❌ qrcode_resized.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - // Create a new QRCode using the macro qr_code and convert it to an SVG representation with a custom size of 512x512 - let qrcode = qr_code!(URL.into()); - let qrcode_svg = qrcode.to_svg(512); // Convert the QRCode into an SVG representation with a custom size of 512x512 - match fs::write("qrcode.svg", qrcode_svg) { - Ok(_) => println!("đŸĻ€ svg file created: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - Err(e) => println!("đŸĻ€ svg file created: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - } - match fs::remove_file("qrcode.svg") { - Ok(_) => println!("đŸĻ€ svg file removed: ✅ qrcode.svg"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - Err(e) => println!("đŸĻ€ svg file removed: ❌ qrcode.svg: {e}"), // Print the path to the SVG representation of the QRCode that was saved to a file called "qrcode.svg" - } - // Create a new QRCode using the macro qr_code_to into a PNG representation with a custom size of 512x512 - let qrcode = qr_code_to!(URL.into(), "png", 512); - match qrcode.save("qrcode.png") { - Ok(_) => println!("đŸĻ€ png file created: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ png file created: ❌ qrcode.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - match fs::remove_file("qrcode.png") { - Ok(_) => println!("đŸĻ€ png file removed: ✅ qrcode.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - Err(e) => println!("đŸĻ€ png file removed: ❌ qrcode.png: {e}",), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode.png" - } - // Create a new QRCode using the macro qr_code_from into a GIF representation with a custom size of 512x512 - let qrcode = qr_code_to!(URL.into(), "gif", 512); - match qrcode.save("qrcode.gif") { - Ok(_) => println!("đŸĻ€ gif file created: ✅ qrcode.gif"), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" - Err(e) => println!("đŸĻ€ gif file created: ❌ qrcode.gif: {e}",), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" - } - match fs::remove_file("qrcode.gif") { - Ok(_) => println!("đŸĻ€ gif file removed: ✅ qrcode.gif"), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" - Err(e) => println!("đŸĻ€ gif file removed: ❌ qrcode.gif: {e}",), // Print the path to the GIF representation of the QRCode that was saved to a file called "qrcode.gif" - } - // Create a new QRCode using the macro qr_code_to into a JPEG representation with a custom size of 512x512 - let qrcode = qr_code_to!(URL.into(), "jpg", 512); - match qrcode.save("qrcode.jpg") { - Ok(_) => println!("đŸĻ€ jpg file created: ✅ qrcode.jpg"), // Print the path to the JPG representation of the QRCode that was saved to a file called "qrcode.jpg" - Err(e) => println!("đŸĻ€ jpg file created: ❌ qrcode.jpg: {e}",), // Print the path to the JPEG representation of the QRCode that was saved to a file called "qrcode.jpg" - } - match fs::remove_file("qrcode.jpg") { - Ok(_) => println!("đŸĻ€ jpg file removed: ✅ qrcode.jpg"), // Print the path to the JPG representation of the QRCode that was saved to a file called "qrcode.jpg" - Err(e) => println!("đŸĻ€ jpg file removed: ❌ qrcode.jpg: {e}",), // Print the path to the JPEG representation of the QRCode that was saved to a file called "qrcode.jpg" - } +fn save_and_remove_file(data: Vec, filename: &str, width: u32, height: u32) { + let image = ImageBuffer::, Vec>::from_raw(width, height, data).unwrap(); + match image.save(filename) { + Ok(_) => println!("đŸĻ€ PNG file created: ✅ {}", filename), + Err(e) => println!("đŸĻ€ PNG file creation failed: ❌ {}: {}", filename, e), + } + remove_file(filename); +} - // Create a new QRCode add a watermark to it and save it as a PNG file - let qrcode = QRCode::from_string(URL.to_string()); - let mut qrcode_img = qrcode.to_png(512); - let watermark_img = image::open("bubba.ico").unwrap().into_rgba8(); - add_image_watermark!(&mut qrcode_img, &watermark_img); - match qrcode_img.save("qrcode_watermarked.png") { - Ok(_) => println!("đŸĻ€ png file with watermark: ✅ qrcode_watermarked.png"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - Err(e) => println!("đŸĻ€ png file with watermark: ❌ qrcode_watermarked.png: {e}"), // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - } - match fs::remove_file("qrcode_watermarked.png") { - Ok(_) => { - println!("đŸĻ€ png file with watermark removed: ✅ qrcode_watermarked.png") - } // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" - Err(e) => { - println!("đŸĻ€ png file with watermark removed: ❌ qrcode_watermarked.png: {e}") - } // Print the path to the PNG representation of the QRCode that was saved to a file called "qrcode1.png" +fn remove_file(filename: &str) { + match fs::remove_file(filename) { + Ok(_) => println!("đŸĻ€ File removed: ✅ {}", filename), + Err(e) => println!("đŸĻ€ File removal failed: ❌ {}: {}", filename, e), } -} \ No newline at end of file +} From 0b08769dc5eb3d0b290d5442bd9d7e1ad33ed508 Mon Sep 17 00:00:00 2001 From: Sebastien Rousseau Date: Fri, 29 Dec 2023 02:16:19 +0000 Subject: [PATCH 5/5] fix(mini-functions): :bug: Unnecessary braces in use statement --- examples/example_qr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example_qr.rs b/examples/example_qr.rs index 52fb55cd..06535034 100644 --- a/examples/example_qr.rs +++ b/examples/example_qr.rs @@ -4,7 +4,7 @@ extern crate image; use image::{imageops, ImageBuffer, Rgba, RgbaImage}; extern crate qrc; -use self::qrc::{QRCode}; +use self::qrc::QRCode; use std::fs;