diff --git a/Cargo.lock b/Cargo.lock index 271ddaa..89d8e1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -260,7 +260,7 @@ dependencies = [ [[package]] name = "fake" -version = "2.8.0" +version = "2.9.0" dependencies = [ "bigdecimal", "chrono", diff --git a/README.md b/README.md index a408ad5..0266a92 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Default: ```toml [dependencies] -fake = { version = "2.8", features = ["derive"] } +fake = { version = "2.9", features = ["derive"] } ``` Available features: diff --git a/fake/Cargo.toml b/fake/Cargo.toml index a9a155f..f0430b4 100644 --- a/fake/Cargo.toml +++ b/fake/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fake" -version = "2.8.0" +version = "2.9.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"] @@ -9,6 +9,7 @@ readme = "README.md" repository = "https://github.com/cksac/fake-rs" homepage = "https://github.com/cksac/fake-rs" edition = "2021" +rust-version = "1.56" [package.metadata.docs.rs] all-features = true diff --git a/fake/README.md b/fake/README.md index 5d249f6..4017394 100644 --- a/fake/README.md +++ b/fake/README.md @@ -11,7 +11,7 @@ Default: ```toml [dependencies] -fake = { version = "2.8", features = ["derive"] } +fake = { version = "2.9", features = ["derive"] } ``` Available features: diff --git a/fake/src/impls/bigdecimal/mod.rs b/fake/src/impls/bigdecimal/mod.rs index afaddd4..6888234 100644 --- a/fake/src/impls/bigdecimal/mod.rs +++ b/fake/src/impls/bigdecimal/mod.rs @@ -1,51 +1,53 @@ -use crate::decimal::*; use crate::{Dummy, Fake, Faker}; -use bigdecimal_rs as bd; +use bigdecimal_rs::num_bigint::{BigInt, Sign}; use rand::Rng; -use rust_decimal; -use std::str::FromStr; pub struct BigDecimal; pub struct NegativeBigDecimal; pub struct PositiveBigDecimal; pub struct NoBigDecimalPoints; -impl Dummy for bd::BigDecimal { +fn create_big_decimal(rng: &mut R, sign: Sign) -> bigdecimal_rs::BigDecimal { + let parts: [u32; 4] = Faker.fake_with_rng(rng); + let int = BigInt::from_slice(sign, &parts); + let scale = (0..64).fake_with_rng(rng); + + bigdecimal_rs::BigDecimal::new(int, scale) +} + +impl Dummy for bigdecimal_rs::BigDecimal { fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - let decimal: rust_decimal::Decimal = Faker.fake_with_rng(rng); + let sign = if Faker.fake_with_rng(rng) { + Sign::Plus + } else { + Sign::Minus + }; - bd::BigDecimal::from_str(&decimal.to_string()).unwrap() + create_big_decimal(rng, sign) } } -impl Dummy for bd::BigDecimal { +impl Dummy for bigdecimal_rs::BigDecimal { fn dummy_with_rng(_: &BigDecimal, rng: &mut R) -> Self { - let decimal: rust_decimal::Decimal = Decimal.fake_with_rng(rng); - - bd::BigDecimal::from_str(&decimal.to_string()).unwrap() + Faker.fake_with_rng(rng) } } -impl Dummy for bd::BigDecimal { +impl Dummy for bigdecimal_rs::BigDecimal { fn dummy_with_rng(_: &NegativeBigDecimal, rng: &mut R) -> Self { - let decimal: rust_decimal::Decimal = NegativeDecimal.fake_with_rng(rng); - - bd::BigDecimal::from_str(&decimal.to_string()).unwrap() + create_big_decimal(rng, Sign::Minus) } } -impl Dummy for bd::BigDecimal { +impl Dummy for bigdecimal_rs::BigDecimal { fn dummy_with_rng(_: &PositiveBigDecimal, rng: &mut R) -> Self { - let decimal: rust_decimal::Decimal = PositiveDecimal.fake_with_rng(rng); - - bd::BigDecimal::from_str(&decimal.to_string()).unwrap() + create_big_decimal(rng, Sign::Plus) } } -impl Dummy for bd::BigDecimal { +impl Dummy for bigdecimal_rs::BigDecimal { fn dummy_with_rng(_: &NoBigDecimalPoints, rng: &mut R) -> Self { - let decimal: rust_decimal::Decimal = NoDecimalPoints.fake_with_rng(rng); - - bd::BigDecimal::from_str(&decimal.to_string()).unwrap() + let decimal: bigdecimal_rs::BigDecimal = Faker.fake_with_rng(rng); + decimal.with_scale(0) } } diff --git a/fake/src/impls/chrono/mod.rs b/fake/src/impls/chrono/mod.rs index f76f506..773ed02 100644 --- a/fake/src/impls/chrono/mod.rs +++ b/fake/src/impls/chrono/mod.rs @@ -73,3 +73,52 @@ impl Dummy for NaiveDateTime { NaiveDateTime::new(date, time) } } + +pub struct Precision; + +trait AllowedPrecision { + const SCALE: i64; + + fn to_scale(nanos: i64) -> i64 { + if nanos != 0 { + nanos / Self::SCALE * Self::SCALE + } else { + nanos + } + } +} +macro_rules! allow_precision { + ($($precision:expr),*) => { + $(impl AllowedPrecision for Precision<$precision> { + const SCALE: i64 = 10i64.pow(9 - $precision); + })* + }; +} +allow_precision!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + +impl Dummy> for NaiveTime +where + Precision: AllowedPrecision, +{ + fn dummy_with_rng(_: &Precision, rng: &mut R) -> Self { + let hour = (0..24).fake_with_rng(rng); + let min = (0..60).fake_with_rng(rng); + let sec = (0..60).fake_with_rng(rng); + let nanos: i64 = (0..1_000_000_000).fake_with_rng(rng); + let nanos = Precision::::to_scale(nanos) as u32; + NaiveTime::from_hms_nano_opt(hour, min, sec, nanos).expect("failed to create time") + } +} + +impl Dummy> for DateTime +where + Tz: TimeZone + Dummy, + Precision: AllowedPrecision, +{ + fn dummy_with_rng(_: &Precision, rng: &mut R) -> Self { + let nanos: i64 = Faker.fake_with_rng(rng); + let utc: DateTime = Utc.timestamp_nanos(Precision::::to_scale(nanos)); + let tz: Tz = Faker.fake_with_rng(rng); + utc.with_timezone(&tz) + } +} diff --git a/fake/src/impls/decimal/mod.rs b/fake/src/impls/decimal/mod.rs index 70089b0..4d10fd2 100644 --- a/fake/src/impls/decimal/mod.rs +++ b/fake/src/impls/decimal/mod.rs @@ -50,8 +50,8 @@ impl Dummy for rust_decimal::Decimal { impl Dummy for rust_decimal::Decimal { fn dummy_with_rng(_: &NoDecimalPoints, rng: &mut R) -> Self { - Faker - .fake_with_rng::(rng) - .round_dp(0) + let mut decimal: rust_decimal::Decimal = Faker.fake_with_rng(rng); + decimal.set_scale(0).expect("failed to set scale"); + decimal } } diff --git a/fake/src/impls/std/array.rs b/fake/src/impls/std/array.rs index 6639dc6..968cd98 100644 --- a/fake/src/impls/std/array.rs +++ b/fake/src/impls/std/array.rs @@ -1,26 +1,11 @@ use crate::{Dummy, Fake}; use rand::Rng; -macro_rules! array_impl { - {$n:expr, $t:ident $($ts:ident)*} => { - impl Dummy for [T; $n] where T: Dummy { - fn dummy_with_rng(config: &U, rng: &mut R) -> Self { - [Fake::fake_with_rng::<$t, _>(config, rng), $(Fake::fake_with_rng::<$ts, _>(config, rng)),*] - } - } - array_impl!{($n - 1), $($ts)*} - }; - {$n:expr,} => { - impl Dummy for [T; $n] where T: Dummy { - fn dummy(_: &U) -> Self { - [] - } - - fn dummy_with_rng(_: &U, _rng: &mut R) -> Self { - [] - } - } - }; +impl Dummy for [T; N] +where + T: Dummy, +{ + fn dummy_with_rng(config: &U, rng: &mut R) -> Self { + std::array::from_fn(|_| Fake::fake_with_rng::(config, rng)) + } } - -array_impl! {32, T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T} diff --git a/fake/src/impls/time/mod.rs b/fake/src/impls/time/mod.rs index 15eaa5e..b0769b9 100644 --- a/fake/src/impls/time/mod.rs +++ b/fake/src/impls/time/mod.rs @@ -54,3 +54,61 @@ impl Dummy for PrimitiveDateTime { PrimitiveDateTime::new(date, time) } } + +pub struct Precision; + +trait AllowedPrecision { + const SCALE: i128; + + fn to_scale(nanos: i128) -> i128 { + if nanos != 0 { + nanos / Self::SCALE * Self::SCALE + } else { + nanos + } + } +} +macro_rules! allow_precision { + ($($precision:expr),*) => { + $(impl AllowedPrecision for Precision<$precision> { + const SCALE: i128 = 10i128.pow(9 - $precision); + })* + }; +} +allow_precision!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + +impl Dummy> for Time +where + Precision: AllowedPrecision, +{ + fn dummy_with_rng(_: &Precision, rng: &mut R) -> Self { + let hour = (0..24).fake_with_rng(rng); + let min = (0..60).fake_with_rng(rng); + let sec = (0..60).fake_with_rng(rng); + let nanos: i128 = (0..1_000_000_000).fake_with_rng(rng); + let nanos = Precision::::to_scale(nanos) as u32; + Time::from_hms_nano(hour, min, sec, nanos).expect("failed to create time") + } +} + +impl Dummy> for PrimitiveDateTime +where + Precision: AllowedPrecision, +{ + fn dummy_with_rng(_: &Precision, rng: &mut R) -> Self { + let date = Faker.fake_with_rng(rng); + let time = Precision::.fake_with_rng(rng); + PrimitiveDateTime::new(date, time) + } +} + +impl Dummy> for OffsetDateTime +where + Precision: AllowedPrecision, +{ + fn dummy_with_rng(_: &Precision, rng: &mut R) -> Self { + let nanos = (MIN_NANOS..MAX_NANOS).fake_with_rng(rng); + let nanos = Precision::::to_scale(nanos); + OffsetDateTime::from_unix_timestamp_nanos(nanos).unwrap() + } +}