From 99b89516c766328780399f5180098c7f070e1cad Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Sat, 15 Jun 2024 09:29:02 -0400 Subject: [PATCH 01/13] Begin v0.4.5 development --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ad1ee1f..86ab82c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bigdecimal" -version = "0.4.4" +version = "0.4.5+dev" authors = ["Andrew Kubera"] description = "Arbitrary precision decimal numbers" documentation = "https://docs.rs/bigdecimal" From aabc68b4f62d6029231566e743dc6a9219bfc925 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Sat, 15 Jun 2024 11:34:15 -0400 Subject: [PATCH 02/13] Fix typos in README and impl_fmt.rs --- README.md | 4 ++-- src/impl_fmt.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d832674..1fe4ea5 100644 --- a/README.md +++ b/README.md @@ -87,9 +87,9 @@ use serde_json; #[derive(Debug,Serialize,Deserialize)] struct MyStruct { name: String, - // this will be witten to json as string + // this will be written to json as string value: BigDecimal, - // this will be witten to json as number + // this will be written to json as number #[serde(with = "bigdecimal::serde::json_num")] number: BigDecimal, } diff --git a/src/impl_fmt.rs b/src/impl_fmt.rs index 9668896..380aa10 100644 --- a/src/impl_fmt.rs +++ b/src/impl_fmt.rs @@ -128,7 +128,7 @@ fn format_full_scale( debug_assert_ne!(digits.len(), 0); if this.scale <= 0 { - // formating an integer value (add trailing zeros to the right) + // formatting an integer value (add trailing zeros to the right) zero_right_pad_integer_ascii_digits(&mut digits, &mut exp, f.precision()); } else { let scale = this.scale as usize; From bf3fe0597a26fe19b9d41ce7ae96446f6f07ac26 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Sat, 15 Jun 2024 12:05:40 -0400 Subject: [PATCH 03/13] Add test for comparision of decimals with large mangitude scales --- src/impl_cmp.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/impl_cmp.rs b/src/impl_cmp.rs index 69be708..058a369 100644 --- a/src/impl_cmp.rs +++ b/src/impl_cmp.rs @@ -378,6 +378,20 @@ mod test { impl_test!(case_1116xx459_759xx717e2: "1116386634271380982470843247639640260491505327092723527088459" < "759522625769651746138617259189939751893902453291243506584717" e 2); } + /// Test that large-magnitidue exponentials will not crash + #[test] + fn test_cmp_on_exp_boundaries() { + let a = BigDecimal::new(1.into(), i64::MAX); + let z = BigDecimal::new(1.into(), i64::MIN); + assert_ne!(a, z); + assert_ne!(z, a); + + assert!(a < z); + + assert_eq!(a, a); + assert_eq!(z, z); + } + mod ord { use super::*; From 8a328805e334c4aa43cbbb99f5fbe6e75e96bfe4 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Mon, 17 Jun 2024 00:56:14 -0400 Subject: [PATCH 04/13] Add Cargo.lock --- Cargo.lock | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4b47646 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,157 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bigdecimal" +version = "0.4.5+dev" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", + "paste", + "serde", + "serde_json", + "serde_test", + "siphasher", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_test" +version = "1.0.175" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29baf0f77ca9ad9c6ed46e1b408b5e0f30b5184bcd66884e7f6d36bd7a65a8a4" +dependencies = [ + "serde", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "syn" +version = "2.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2415488199887523e74fd9a5f7be804dfd42d868ae0eca382e3917094d210e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" From 7fbff809a39753bbd6fa0390dd33d30751f9ae70 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Mon, 17 Jun 2024 01:14:56 -0400 Subject: [PATCH 05/13] Remove version restrictions of num-crate dependencies --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 86ab82c..d8eded5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,9 +21,9 @@ bench = false [dependencies] libm = "0.2.6" -num-bigint = { version = ">=0.3.0,<0.4.5", default-features = false } -num-integer = { version = "^0.1", default-features = false } -num-traits = { version = ">0.2.0,<0.2.19", default-features = false } +num-bigint = { version = "0.4", default-features = false } +num-integer = { version = "0.1", default-features = false } +num-traits = { version = "0.2", default-features = false } serde = { version = "1.0", optional = true, default-features = false } # Allow direct parsing of JSON floats, for full arbitrary precision serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc", "arbitrary_precision"]} From ed1757a9242657fe98805d3bbeac5d181805fb35 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Mon, 17 Jun 2024 01:09:52 -0400 Subject: [PATCH 06/13] Update .circleci to respect Cargo.lock --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6615f67..f4721ad 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -36,7 +36,7 @@ jobs: command: scripts/bigdecimal-property-tests enable - run: name: Generate cargo.lock - command: cargo generate-lockfile + command: if [ ! -f Cargo.lock ]; then cargo generate-lockfile; fi - restore_cache: keys: - bigdecimal-cargo-<< parameters.rust-version >>-{{ checksum "Cargo.lock" }} From bee64e846ac3f9a70b09d9e8972214e4ded58804 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Mon, 17 Jun 2024 02:04:37 -0400 Subject: [PATCH 07/13] Remove invalid unwrap --- src/impl_fmt.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/impl_fmt.rs b/src/impl_fmt.rs index 380aa10..2e2ce0d 100644 --- a/src/impl_fmt.rs +++ b/src/impl_fmt.rs @@ -169,7 +169,10 @@ fn zero_right_pad_integer_ascii_digits( ) { debug_assert!(*exp >= 0); - let trailing_zero_count = exp.to_usize().unwrap(); + let trailing_zero_count = match exp.to_usize() { + Some(n) => n, + None => { return; } + }; let total_additional_zeros = trailing_zero_count.saturating_add(precision.unwrap_or(0)); if total_additional_zeros > FMT_MAX_INTEGER_PADDING { return; From 570ed33c31c2b7e32f5ad46f733953e882f70f70 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Mon, 17 Jun 2024 02:08:18 -0400 Subject: [PATCH 08/13] Standardize capitalization --- src/impl_fmt.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/impl_fmt.rs b/src/impl_fmt.rs index 2e2ce0d..27e6488 100644 --- a/src/impl_fmt.rs +++ b/src/impl_fmt.rs @@ -151,7 +151,7 @@ fn format_full_scale( // add exp part to buffer (if not zero) if exp != 0 { - write!(buf, "E{:+}", exp)?; + write!(buf, "e{:+}", exp)?; } // write buffer to formatter @@ -866,8 +866,8 @@ mod test { } impl_case!(fmt_default: "{}" => "1e+100000"); - impl_case!(fmt_d1: "{:.1}" => "1E+100000"); - impl_case!(fmt_d4: "{:.4}" => "1E+100000"); + impl_case!(fmt_d1: "{:.1}" => "1e+100000"); + impl_case!(fmt_d4: "{:.4}" => "1e+100000"); } @@ -908,7 +908,7 @@ mod test { } impl_case!(fmt_default: "{}" => "13400476439814628800e+2502"); - impl_case!(fmt_d1: "{:.1}" => "13400476439814628800E+2502"); + impl_case!(fmt_d1: "{:.1}" => "13400476439814628800e+2502"); } } From a64bdbf4131c96b3bcb26d0fa24c5acd151f5515 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Mon, 17 Jun 2024 02:48:32 -0400 Subject: [PATCH 09/13] Fix digit counting for 32-bit arch in impl_fmt --- src/impl_fmt.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/impl_fmt.rs b/src/impl_fmt.rs index 27e6488..9d4c4d6 100644 --- a/src/impl_fmt.rs +++ b/src/impl_fmt.rs @@ -87,20 +87,23 @@ fn dynamically_format_decimal( // number of zeros between most significant digit and decimal point let leading_zero_count = this.scale - .to_usize() - .and_then(|scale| scale.checked_sub(abs_int.len())) + .to_u64() + .and_then(|scale| scale.checked_sub(abs_int.len() as u64)) .unwrap_or(0); // number of zeros between least significant digit and decimal point let trailing_zero_count = this.scale .checked_neg() - .and_then(|d| d.to_usize()); + .and_then(|d| d.to_u64()); // this ignores scientific-formatting if precision is requested let trailing_zeros = f.precision().map(|_| 0) .or(trailing_zero_count) .unwrap_or(0); + let leading_zero_threshold = leading_zero_threshold as u64; + let trailing_zero_threshold = trailing_zero_threshold as u64; + // use exponential form if decimal point is outside // the upper and lower thresholds of the decimal if leading_zero_threshold < leading_zero_count { From dc70ccaf2c088e39e45319acb9bb21fb6d03a101 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Mon, 17 Jun 2024 02:55:49 -0400 Subject: [PATCH 10/13] Replace more references of usize with u64 for 32-bit arch --- src/impl_fmt.rs | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/impl_fmt.rs b/src/impl_fmt.rs index 9d4c4d6..058f442 100644 --- a/src/impl_fmt.rs +++ b/src/impl_fmt.rs @@ -134,11 +134,11 @@ fn format_full_scale( // formatting an integer value (add trailing zeros to the right) zero_right_pad_integer_ascii_digits(&mut digits, &mut exp, f.precision()); } else { - let scale = this.scale as usize; + let scale = this.scale as u64; // no-precision behaves the same as precision matching scale (i.e. no padding or rounding) - let prec = f.precision().unwrap_or(scale); + let prec = f.precision().and_then(|prec| prec.to_u64()).unwrap_or(scale); - if scale < digits.len() { + if scale < digits.len() as u64 { // format both integer and fractional digits (always 'trim' to precision) trim_ascii_digits(&mut digits, scale, prec, &mut exp, this.sign); } else { @@ -201,16 +201,20 @@ fn zero_right_pad_integer_ascii_digits( /// Fill zeros into utf-8 digits fn trim_ascii_digits( digits: &mut Vec, - scale: usize, - prec: usize, + scale: u64, + prec: u64, exp: &mut i128, sign: Sign, ) { - debug_assert!(scale < digits.len()); + debug_assert!(scale < digits.len() as u64); // there are both integer and fractional digits - let integer_digit_count = digits.len() - scale; + let integer_digit_count = (digits.len() as u64 - scale) + .to_usize() + .expect("Number of digits exceeds maximum usize"); if prec < scale { + let prec = prec.to_usize() + .expect("Precision exceeds maximum usize"); apply_rounding_to_ascii_digits( digits, exp, integer_digit_count + prec, sign ); @@ -221,22 +225,26 @@ fn trim_ascii_digits( } if scale < prec { + let trailing_zero_count = (prec - scale) + .to_usize() + .expect("Too Big"); + // precision required beyond scale - digits.resize(digits.len() + (prec - scale), b'0'); + digits.resize(digits.len() + trailing_zero_count, b'0'); } } fn shift_or_trim_fractional_digits( digits: &mut Vec, - scale: usize, - prec: usize, + scale: u64, + prec: u64, exp: &mut i128, sign: Sign, ) { - debug_assert!(scale >= digits.len()); + debug_assert!(scale >= digits.len() as u64); // there are no integer digits - let leading_zeros = scale - digits.len(); + let leading_zeros = scale - digits.len() as u64; match prec.checked_sub(leading_zeros) { None => { @@ -244,7 +252,7 @@ fn shift_or_trim_fractional_digits( digits.push(b'0'); if prec > 0 { digits.push(b'.'); - digits.resize(2 + prec, b'0'); + digits.resize(2 + prec as usize, b'0'); } } Some(0) => { @@ -257,11 +265,15 @@ fn shift_or_trim_fractional_digits( if leading_zeros != 0 { digits.push(b'0'); digits.push(b'.'); - digits.resize(1 + leading_zeros, b'0'); + digits.resize(1 + leading_zeros as usize, b'0'); } digits.push(rounded_value + b'0'); } Some(digit_prec) => { + let digit_prec = digit_prec as usize; + let leading_zeros = leading_zeros + .to_usize() + .expect("Number of leading zeros exceeds max usize"); let trailing_zeros = digit_prec.saturating_sub(digits.len()); if digit_prec < digits.len() { apply_rounding_to_ascii_digits(digits, exp, digit_prec, sign); From 8f2936c2a120d69e592d97fc52422d01a3737314 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Mon, 17 Jun 2024 03:09:06 -0400 Subject: [PATCH 11/13] Add i686 test-job to gitlab-ci --- .gitlab-ci.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 63adcca..39ae95b 100755 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -173,6 +173,20 @@ cargo:test-stable: # enable property tests for the stable 'pipeline' - scripts/bigdecimal-property-tests run cargo test +cargo:test-i686: + stage: test + image: akubera/rust:stable + cache: + - <<: *cache-cargo-registry + policy: pull-push + - <<: *cache-cargo-build + variables: + RUST_CACHE_KEY: "stable-i686" + script: + - rustc --version && cargo --version + - rustup target add i686-unknown-linux-gnu + - cargo test --target i686-unknown-linux-gnu + cargo:build:no-std: stage: build From 4c5ee5af4168a5aaac1493da6947dd649192c801 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Mon, 17 Jun 2024 03:18:59 -0400 Subject: [PATCH 12/13] Remove i686 test-job in gitlab-ci This reverts commit 8f2936c2a120d69e592d97fc52422d01a3737314. --- .gitlab-ci.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 39ae95b..63adcca 100755 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -173,20 +173,6 @@ cargo:test-stable: # enable property tests for the stable 'pipeline' - scripts/bigdecimal-property-tests run cargo test -cargo:test-i686: - stage: test - image: akubera/rust:stable - cache: - - <<: *cache-cargo-registry - policy: pull-push - - <<: *cache-cargo-build - variables: - RUST_CACHE_KEY: "stable-i686" - script: - - rustc --version && cargo --version - - rustup target add i686-unknown-linux-gnu - - cargo test --target i686-unknown-linux-gnu - cargo:build:no-std: stage: build From 682343b7c54fa17bc5fff5a30ec95f810f83f1bf Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Mon, 17 Jun 2024 03:26:22 -0400 Subject: [PATCH 13/13] Version 0.4.5 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b47646..9245ced 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bigdecimal" -version = "0.4.5+dev" +version = "0.4.5" dependencies = [ "autocfg", "libm", diff --git a/Cargo.toml b/Cargo.toml index d8eded5..52e5989 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bigdecimal" -version = "0.4.5+dev" +version = "0.4.5" authors = ["Andrew Kubera"] description = "Arbitrary precision decimal numbers" documentation = "https://docs.rs/bigdecimal"