diff --git a/README.md b/README.md index 0266a92..565fa4c 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,7 @@ DirPath(); ```rust Bic(); +Isin(); ``` ### UUID diff --git a/fake/Cargo.toml b/fake/Cargo.toml index 0fdf655..3f5ae42 100644 --- a/fake/Cargo.toml +++ b/fake/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fake" -version = "2.9.0" +version = "2.10.0" authors = ["cksac "] description = "An easy to use library for generating fake data like name, number, address, lorem, dates, etc." keywords = ["faker", "data", "generator", "random"] diff --git a/fake/examples/fakers.rs b/fake/examples/fakers.rs index 0e7e9a7..bea1b1c 100644 --- a/fake/examples/fakers.rs +++ b/fake/examples/fakers.rs @@ -289,6 +289,16 @@ fn phone_number_faker() { println!("{:?}", val); } +fn finance_faker() { + use fake::faker::finance::raw::*; + + let val: String = Bic(EN).fake(); + println!("{:?}", val); + + let val: String = Isin(EN).fake(); + println!("{:?}", val); +} + #[cfg(feature = "http")] fn http_faker() { use fake::faker::http::raw::*; @@ -534,6 +544,7 @@ fn main() { internet_faker(); number_faker(); phone_number_faker(); + finance_faker(); currency_faker(); creditcard_faker(); barcode_faker(); diff --git a/fake/src/faker/impls/finance.rs b/fake/src/faker/impls/finance.rs index a8e2003..15e602a 100644 --- a/fake/src/faker/impls/finance.rs +++ b/fake/src/faker/impls/finance.rs @@ -9,6 +9,11 @@ const ALPHABET: &[char; 26] = &[ 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ]; +const ALPHANUMERIC: &[char; 36] = &[ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', +]; + const ISO3166: &[&str] = &[ "AC", "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", @@ -71,3 +76,42 @@ impl Dummy> for String { ) } } + +fn split_number_to_digits(x: u32) -> Vec { + x.to_string() + .chars() + .map(|x| x.to_digit(10).unwrap()) + .collect::>() +} + +impl Dummy> for String { + fn dummy_with_rng(_: &Isin, rng: &mut R) -> Self { + let country_code = *ISO3166.choose(rng).unwrap(); + let nsin = (1..10) + .map(|_x| *ALPHANUMERIC.choose(rng).unwrap()) + .collect::(); + // Checksum calculation according to Luhn algorithm + let char_to_num: Vec = country_code + .chars() + .chain(nsin.chars()) + .map(|x| { + if x.is_ascii_digit() { + x.to_digit(10).unwrap() + } else { + 10 + ((x as u32) - ('A' as u32)) + } + }) + .flat_map(split_number_to_digits) + .collect(); + let checksum_even = char_to_num.iter().rev().skip(1).step_by(2).sum::(); + let checksum_odd = char_to_num + .iter() + .rev() + .step_by(2) + .map(|&x| x * 2) + .flat_map(split_number_to_digits) + .sum::(); + let checksum_digit = (10 - ((checksum_even + checksum_odd) % 10)) % 10; + return format!("{}{}{}", country_code, nsin, checksum_digit); + } +} diff --git a/fake/src/faker/impls/internet.rs b/fake/src/faker/impls/internet.rs index 424854a..5b19a43 100644 --- a/fake/src/faker/impls/internet.rs +++ b/fake/src/faker/impls/internet.rs @@ -3,11 +3,11 @@ use crate::faker::lorem::raw::Word; use crate::faker::name::raw::FirstName; use crate::locales::Data; use crate::{Dummy, Fake, Faker}; +use deunicode::AsciiChars; use rand::distributions::{Distribution, Uniform}; use rand::seq::SliceRandom; use rand::Rng; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use deunicode::AsciiChars; impl Dummy> for String { fn dummy_with_rng(_: &FreeEmailProvider, rng: &mut R) -> Self { diff --git a/fake/src/faker/mod.rs b/fake/src/faker/mod.rs index ca24c15..879983b 100644 --- a/fake/src/faker/mod.rs +++ b/fake/src/faker/mod.rs @@ -235,6 +235,7 @@ pub mod currency { pub mod finance { def_fakers! { Bic(); + Isin(); } } diff --git a/fake/tests/determinism.rs b/fake/tests/determinism.rs index 293d45b..2930a19 100644 --- a/fake/tests/determinism.rs +++ b/fake/tests/determinism.rs @@ -188,6 +188,7 @@ check_determinism! { one fake_semver_en, String, Semver(EN) } use fake::faker::finance::raw::*; check_determinism! { l10d Bic; String, fake_bic_en, fake_bic_fr, fake_bic_cn, fake_bic_tw, fake_bic_jp } +check_determinism! { l10d Isin; String, fake_isin_en, fake_isin_fr, fake_isin_cn, fake_isin_tw, fake_isin_jp} // HTTP #[cfg(feature = "http")]