From fad2d4f989a1dd5bebd089b8fcfff53a9adfeee8 Mon Sep 17 00:00:00 2001 From: Paul Mason Date: Wed, 28 Jul 2021 14:12:40 +1200 Subject: [PATCH 1/4] Minor documentation improvements --- src/decimal.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/decimal.rs b/src/decimal.rs index c4103efb..d6ba5c26 100644 --- a/src/decimal.rs +++ b/src/decimal.rs @@ -529,7 +529,7 @@ impl Decimal { /// ``` /// use rust_decimal::Decimal; /// - /// let mut one = Decimal::new(1, 0); + /// let mut one = Decimal::ONE; /// one.set_sign(false); /// assert_eq!(one.to_string(), "-1"); /// ``` @@ -549,7 +549,7 @@ impl Decimal { /// ``` /// use rust_decimal::Decimal; /// - /// let mut one = Decimal::new(1, 0); + /// let mut one = Decimal::ONE; /// one.set_sign_positive(false); /// assert_eq!(one.to_string(), "-1"); /// ``` @@ -573,7 +573,7 @@ impl Decimal { /// ``` /// use rust_decimal::Decimal; /// - /// let mut one = Decimal::new(1, 0); + /// let mut one = Decimal::ONE; /// one.set_sign_negative(true); /// assert_eq!(one.to_string(), "-1"); /// ``` @@ -593,7 +593,7 @@ impl Decimal { /// ``` /// use rust_decimal::Decimal; /// - /// let mut one = Decimal::new(1, 0); + /// let mut one = Decimal::ONE; /// one.set_scale(5).unwrap(); /// assert_eq!(one.to_string(), "0.00001"); /// ``` @@ -622,12 +622,19 @@ impl Decimal { /// ``` /// use rust_decimal::prelude::*; /// + /// // Rescaling to a higher scale preserves the value /// let mut number = Decimal::from_str("1.123").unwrap(); + /// assert_eq!(number.scale(), 3); /// number.rescale(6); /// assert_eq!(number.to_string(), "1.123000"); - /// let mut round = Decimal::from_str("1.45").unwrap(); - /// round.rescale(1); - /// assert_eq!(round.to_string(), "1.5"); + /// assert_eq!(number.scale(), 6); + /// + /// // Rescaling to a lower scale forces the number to be rounded + /// let mut number = Decimal::from_str("1.45").unwrap(); + /// assert_eq!(number.scale(), 2); + /// number.rescale(1); + /// assert_eq!(number.to_string(), "1.5"); + /// assert_eq!(number.scale(), 1); /// ``` pub fn rescale(&mut self, scale: u32) { let mut array = [self.lo, self.mid, self.hi]; From 76f1c914bf3ac34d3320c13eb1d4b8ffec7eee19 Mon Sep 17 00:00:00 2001 From: Paul Mason Date: Wed, 28 Jul 2021 14:56:05 +1200 Subject: [PATCH 2/4] Added Build.md with build instructions --- BUILD.md | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ Makefile.toml | 28 +++++++----- README.md | 26 ++++++----- src/ops/rem.rs | 6 +-- 4 files changed, 148 insertions(+), 26 deletions(-) create mode 100644 BUILD.md diff --git a/BUILD.md b/BUILD.md new file mode 100644 index 00000000..e9164cf7 --- /dev/null +++ b/BUILD.md @@ -0,0 +1,114 @@ +Developing Rust Decimal +======================= + +* [Setup](#setup) +* [Building](#building) +* [Library Versioning](#library-versioning) +* [Formatting / Code Style](#formatting--code-style) +* [Testing](#testing) +* [Fuzzing](#fuzzing) +* [Benchmarking](#benchmarking) +* [Code Coverage](#code-coverage) + +## Setup + +**Minimum Rust Version:** `1.46.0` + +Rust Decimal leverages [cargo make](https://github.com/sagiegurari/cargo-make) to ensure a consistent build/test/release +approach. This also handles installing any additional dependencies in order to execute various commands, making getting set +up and going relatively straight forward and easy. + +Installing this can be done using `cargo`: + +```shell +cargo install --force cargo-make +``` + +Once this has been installed, common tasks can be initiated with the `makers` command. + +## Building + +**Useful Make Commands:** `makers build` + +Building this library doesn't require any special commands and can be performed using a standard `cargo build`. + +### Building no-std + +Builds by default leverage `std`. To disable this functionality you can build Rust Decimal without any default features +enabled: + +```shell +cargo build --no-default-features +``` + +## Library Versioning + +**Useful Make Commands:** `makers outdated` + +The general rule of thumb with Rust Decimal is to ensure that downstream dependencies are kept up to date, so long as they +align with the minimum requirements of the Rust Decimal build system. As a helpful measure, a `makers` command has been created +to identify any outdated dependencies within the project. On a regular basis this command is run and results evaluated for potential +updates to be applied. + +Please note: because this is a library, the `Cargo.lock` file is not committed into the repository. This means that `cargo update` +should be run before running `makers outdated`. + +## Formatting / Code Style + +**Useful Make Commands:** `makers format`, `makers clippy` + +To maintain consistent styling across the project, both `clippy` and `cargo fmt` are used. Github actions will +check for consistent styling upon pull request however it is recommended that both of these commands are run before creating +a PR. + +## Testing + +**Useful Make Commands:** `makers test-all`, `makers test-no-std`, `makers test-maths`, `makers test-serde`, `makers test-db` + +Testing is a critical part of the Rust Decimal development lifecycle. It helps ensure that the library is behaving correctly under +a mixture of different inputs and feature configurations. + +There are many different test configurations defined in `Makefile.toml` to help ensure that common test cases are easy to execute locally. +For the full complete list, please review `Makefile.toml` directly for all `test-*` tasks. Some useful test tasks are listed below: + +* `test-all`: Tests all test configurations against all features +* `test-default`: Test the default configuration +* `test-no-std`: Test the library against a `no-std` build +* `test-maths`: Test the maths feature of the library using both legacy and default ops. +* `test-serde`: Test serialization and deserialization using a mixture of serde features +* `test-db`: Test a variety of database logic changes, including `diesel` and `postgres` configurations. + +When adding new features, please make sure to generate new tasks within the `Makefile.toml` to ensure continued +coverage of your feature going forward. + +### Generated tests + +Rust Decimal includes a number of generated tests that have been generated outside the scope of this project. These are +effectively CSV files that use randomized data for the `lo`, `mid` and `hi` portions of the Decimal number. + +Modification of these files is restricted and should not be committed. If you would like to add further generated tests then +please create new files as you see fit. + +## Fuzzing + +**Useful Make Commands:** `makers fuzz` + +Rust Decimal includes some fuzz testing support also to help capture a wider range of testing scenarios. These can be +run by using `makers fuzz`. + +## Benchmarking + +**Useful Make Commands:** `makers bench` + +In order to ensure that Rust Decimal runs quickly, a number of benchmarks have been created and can be executed using +`makers bench`. + +When adding new benchmarking configurations please ensure that you add a corresponding `Makefile.toml` task to capture the +updated configuration. + +## Code Coverage + +**Useful Make Commands:** `makers coverage`, `makers codecov-open` + +Limited code coverage support has been added to Rust Decimal using `gcov`. A code coverage report +can be generated by running `makers coverage`. Once generated, the report can be opened using `makers codecov-open`. \ No newline at end of file diff --git a/Makefile.toml b/Makefile.toml index b096040c..23d8b2a3 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -8,6 +8,23 @@ FUZZ_RUNS = 10000000 command = "cargo" args = ["build"] +[tasks.format] +workspace = true +install_crate = "rustfmt" +command = "cargo" +args = ["fmt", "--", "--emit=files"] + +[tasks.clippy] +workspace = true +install_crate = "clippy" +command = "cargo" +args = ["clippy"] + +[tasks.outdated] +install_crate = "cargo-outdated" +command = "cargo" +args = ["outdated", "-R"] + [tasks.bench] toolchain = "nightly" command = "cargo" @@ -73,12 +90,6 @@ dependencies = ["test-no-std"] command = "cargo" args = ["test"] -[tasks.format] -workspace = true -install_crate = "rustfmt" -command = "cargo" -args = ["fmt", "--", "--emit=files"] - [tasks.fuzz] dependencies = [ "fuzz-arithmetic", @@ -97,11 +108,6 @@ install_crate = "cargo-fuzz" command = "cargo" args = ["fuzz", "run", "constructors", "--", "-runs=${FUZZ_RUNS}"] -[tasks.outdated] -install_crate = "cargo-outdated" -command = "cargo" -args = ["outdated", "-R"] - [tasks.test-all] dependencies = [ "test-no-std", diff --git a/README.md b/README.md index 598770cc..2ac31bed 100644 --- a/README.md +++ b/README.md @@ -85,39 +85,39 @@ assert_eq!(total.to_string(), "27.26"); * [serde-arbitrary-precision](#serde-arbitrary-precision) * [std](#std) -## `c-repr` +### `c-repr` Forces `Decimal` to use `[repr(C)]`. The corresponding target layout is 128 bit aligned. -## `db-postgres` +### `db-postgres` This feature enables a PostgreSQL communication module. It allows for reading and writing the `Decimal` type by transparently serializing/deserializing into the `NUMERIC` data type within PostgreSQL. -## `db-tokio-postgres` +### `db-tokio-postgres` Enables the tokio postgres module allowing for async communication with PostgreSQL. -## `db-diesel-postgres` +### `db-diesel-postgres` Enable `diesel` PostgreSQL support. -## `legacy-ops` +### `legacy-ops` As of `1.10` the algorithms used to perform basic operations have changed which has benefits of significant speed improvements. To maintain backwards compatibility this can be opted out of by enabling the `legacy-ops` feature. -## `maths` +### `maths` The `maths` feature enables additional complex mathematical functions such as `pow`, `ln`, `enf`, `exp` etc. Documentation detailing the additional functions can be found on the [`MathematicalOps`](https://docs.rs/rust_decimal/latest/rust_decimal/trait.MathematicalOps.html) trait. -## `rust-fuzz` +### `rust-fuzz` Enable `rust-fuzz` support by implementing the `Arbitrary` trait. -## `serde-float` +### `serde-float` Enable this so that JSON serialization of `Decimal` types are sent as a float instead of a string (default). @@ -128,7 +128,7 @@ e.g. with this turned on, JSON serialization would output: } ``` -## `serde-str` +### `serde-str` This is typically useful for `bincode` or `csv` like implementations. @@ -140,14 +140,18 @@ If, for some reason, you also have `serde-float` enabled then this will use `des converting to `f64` _loses_ precision, it's highly recommended that you do NOT enable this feature when working with `bincode`. That being said, this will only use 8 bytes so is slightly more efficient in terms of storage size. -## `serde-arbitrary-precision` +### `serde-arbitrary-precision` This is used primarily with `serde_json` and consequently adds it as a "weak dependency". This supports the `arbitrary_precision` feature inside `serde_json` when parsing decimals. This is recommended when parsing "float" looking data as it will prevent data loss. -## `std` +### `std` Enable `std` library support. This is enabled by default, however in the future will be opt in. For now, to support `no_std` libraries, this crate can be compiled with `--no-default-features`. + +## Building + +Please refer to the [Build document](BUILD.md) for more information on building and testing Rust Decimal. \ No newline at end of file diff --git a/src/ops/rem.rs b/src/ops/rem.rs index 19deb528..a79334e0 100644 --- a/src/ops/rem.rs +++ b/src/ops/rem.rs @@ -182,10 +182,8 @@ fn rem_full(d1: &Dec64, d2: &Buf12, scale: i32) -> CalculationResult { // TODO: Optimize slice logic let mut tmp = Buf16::zero(); + let divisor = d2.low64() << shift; if d2.hi() == 0 { - // 64 bit divisor so we adjust accordingly - let divisor = d2.low64() << shift; - // Do some division if upper == 6 { upper -= 1; @@ -232,7 +230,7 @@ fn rem_full(d1: &Dec64, d2: &Buf12, scale: i32) -> CalculationResult { d1.scale, )) } else { - let divisor_low64 = d2.low64() << shift; + let divisor_low64 = divisor; let divisor = Buf12 { data: [ divisor_low64 as u32, From 3a1dce353a4aead83fffa919294708be19c2d6d0 Mon Sep 17 00:00:00 2001 From: Paul Mason Date: Wed, 28 Jul 2021 15:10:02 +1200 Subject: [PATCH 3/4] Update version.md for release --- Cargo.toml | 2 +- README.md | 4 ++-- VERSION.md | 18 +++++++++++++++++- macros/Cargo.toml | 4 ++-- src/lib.rs | 30 +++++++++++++++++------------- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 29588894..c336d2b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" name = "rust_decimal" readme = "./README.md" repository = "https://github.com/paupino/rust-decimal" -version = "1.14.3" +version = "1.15.0" exclude = [ "tests/generated/*" ] [package.metadata.docs.rs] diff --git a/README.md b/README.md index 2ac31bed..722c9fb8 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ To get started, add `rust_decimal` and optionally `rust_decimal_macros` to your ```toml [dependencies] -rust_decimal = "1.14" -rust_decimal_macros = "1.14" +rust_decimal = "1.15" +rust_decimal_macros = "1.15" ``` ## Usage diff --git a/VERSION.md b/VERSION.md index 486f5ba0..4a4a4fda 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1,8 +1,24 @@ # Version History +## 1.15.0 + +A minor bug and feature release which adds a couple of new functions as well as cleans up some documentation: + +* Support for serializing to float without converting to float via the `serde-arbitrary-precision` feature. + [#402](https://github.com/paupino/rust-decimal/issues/402). Thanks [@JamesHinshelwood](https://github.com/JamesHinshelwood)! + for finding and fixing this! +* Add `log10` support to the `maths` feature. [#397](https://github.com/paupino/rust-decimal/issues/397). +* Added further constants to the `Decimal` library including `TWO`, `TEN`, `ONE_HUNDRED`, `ONE_THOUSAND`, and `NEGATIVE_ONE`. + [#400](https://github.com/paupino/rust-decimal/issues/400). +* Fixes serialization issue for `-0` whereby `-` would be output [#406](https://github.com/paupino/rust-decimal/pull/406). Thanks + [@edwardycl](https://github.com/edwardycl)! +* Fixes float rounding before return in `to_f64`. [#401](https://github.com/paupino/rust-decimal/issues/401). +* Added `BUILD.md` file to help people get set up with Rust Decimal locally and cleaned up some + documentation examples. + ## 1.14.3 -Fixes an issue[#398](https://github.com/paupino/rust-decimal/issues/398) where `Decimal::ZERO.ln()` would panic rather than returning `Decimal::ZERO`. This +Fixes an issue [#398](https://github.com/paupino/rust-decimal/issues/398) where `Decimal::ZERO.ln()` would panic rather than returning `Decimal::ZERO`. This aligns the behavior with calling `ln` on negative decimals. Thank you to [@SebRollen](https://github.com/SebRollen) for finding and fixing this. diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 73756218..d66214ca 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust_decimal_macros" -version = "1.14.3" +version = "1.15.0" authors = ["Paul Mason "] edition = "2018" description = "Shorthand macros to assist creating Decimal types." @@ -12,7 +12,7 @@ categories = ["science","data-structures"] license = "MIT" [dependencies] -rust_decimal = { path = "..", version = "1.14.3" } +rust_decimal = { path = "..", version = "1.15.0" } quote = "1.0" [features] diff --git a/src/lib.rs b/src/lib.rs index adb1ccf5..2def0eea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,8 +15,8 @@ //! //! ```toml //! [dependencies] -//! rust_decimal = "1.14" -//! rust_decimal_macros = "1.14" +//! rust_decimal = "1.15" +//! rust_decimal_macros = "1.15" //! ``` //! //! ## Usage @@ -85,39 +85,39 @@ //! * [serde-arbitrary-precision](#serde-arbitrary-precision) //! * [std](#std) //! -//! ## `c-repr` +//! ### `c-repr` //! //! Forces `Decimal` to use `[repr(C)]`. The corresponding target layout is 128 bit aligned. //! -//! ## `db-postgres` +//! ### `db-postgres` //! //! This feature enables a PostgreSQL communication module. It allows for reading and writing the `Decimal` //! type by transparently serializing/deserializing into the `NUMERIC` data type within PostgreSQL. //! -//! ## `db-tokio-postgres` +//! ### `db-tokio-postgres` //! //! Enables the tokio postgres module allowing for async communication with PostgreSQL. //! -//! ## `db-diesel-postgres` +//! ### `db-diesel-postgres` //! //! Enable `diesel` PostgreSQL support. //! -//! ## `legacy-ops` +//! ### `legacy-ops` //! //! As of `1.10` the algorithms used to perform basic operations have changed which has benefits of significant speed improvements. //! To maintain backwards compatibility this can be opted out of by enabling the `legacy-ops` feature. //! -//! ## `maths` +//! ### `maths` //! //! The `maths` feature enables additional complex mathematical functions such as `pow`, `ln`, `enf`, `exp` etc. //! Documentation detailing the additional functions can be found on the //! [`MathematicalOps`](https://docs.rs/rust_decimal/latest/rust_decimal/trait.MathematicalOps.html) trait. //! -//! ## `rust-fuzz` +//! ### `rust-fuzz` //! //! Enable `rust-fuzz` support by implementing the `Arbitrary` trait. //! -//! ## `serde-float` +//! ### `serde-float` //! //! Enable this so that JSON serialization of `Decimal` types are sent as a float instead of a string (default). //! @@ -128,7 +128,7 @@ //! } //! ``` //! -//! ## `serde-str` +//! ### `serde-str` //! //! This is typically useful for `bincode` or `csv` like implementations. //! @@ -140,18 +140,22 @@ //! converting to `f64` _loses_ precision, it's highly recommended that you do NOT enable this feature when working with //! `bincode`. That being said, this will only use 8 bytes so is slightly more efficient in terms of storage size. //! -//! ## `serde-arbitrary-precision` +//! ### `serde-arbitrary-precision` //! //! This is used primarily with `serde_json` and consequently adds it as a "weak dependency". This supports the //! `arbitrary_precision` feature inside `serde_json` when parsing decimals. //! //! This is recommended when parsing "float" looking data as it will prevent data loss. //! -//! ## `std` +//! ### `std` //! //! Enable `std` library support. This is enabled by default, however in the future will be opt in. For now, to support `no_std` //! libraries, this crate can be compiled with `--no-default-features`. //! +//! ## Building +//! +//! Please refer to the [Build document](BUILD.md) for more information on building and testing Rust Decimal. +//! #![forbid(unsafe_code)] #![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; From 4e03adcfe6c7de5d0420d326934e24a45ddcae72 Mon Sep 17 00:00:00 2001 From: Paul Mason Date: Wed, 28 Jul 2021 15:24:13 +1200 Subject: [PATCH 4/4] Added information about maths-nopanic --- README.md | 6 +++++- VERSION.md | 4 +++- src/lib.rs | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 722c9fb8..386b01f5 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,11 @@ To maintain backwards compatibility this can be opted out of by enabling the `le The `maths` feature enables additional complex mathematical functions such as `pow`, `ln`, `enf`, `exp` etc. Documentation detailing the additional functions can be found on the -[`MathematicalOps`](https://docs.rs/rust_decimal/latest/rust_decimal/trait.MathematicalOps.html) trait. +[`MathematicalOps`](https://docs.rs/rust_decimal/latest/rust_decimal/trait.MathematicalOps.html) trait. + +Please note that `ln` and `log10` will panic on invalid input with `checked_ln` and `checked_log10` the preferred functions +to curb against this. When the `maths` feature was first developed the library would return `0` on invalid input. To re-enable this +non-panicing behavior, please use the feature: `maths-nopanic`. ### `rust-fuzz` diff --git a/VERSION.md b/VERSION.md index 4a4a4fda..c78086f8 100644 --- a/VERSION.md +++ b/VERSION.md @@ -7,7 +7,9 @@ A minor bug and feature release which adds a couple of new functions as well as * Support for serializing to float without converting to float via the `serde-arbitrary-precision` feature. [#402](https://github.com/paupino/rust-decimal/issues/402). Thanks [@JamesHinshelwood](https://github.com/JamesHinshelwood)! for finding and fixing this! -* Add `log10` support to the `maths` feature. [#397](https://github.com/paupino/rust-decimal/issues/397). +* Add `log10` support to the `maths` feature. Please note that `ln` and `log10` will now panic on invalid input since both + functions have a `checked_*` equivalent. This is the preferred approach going forward, however if you would like to re-enable + the previous behavior please use the `maths-nopanic` feature. [#397](https://github.com/paupino/rust-decimal/issues/397). * Added further constants to the `Decimal` library including `TWO`, `TEN`, `ONE_HUNDRED`, `ONE_THOUSAND`, and `NEGATIVE_ONE`. [#400](https://github.com/paupino/rust-decimal/issues/400). * Fixes serialization issue for `-0` whereby `-` would be output [#406](https://github.com/paupino/rust-decimal/pull/406). Thanks diff --git a/src/lib.rs b/src/lib.rs index 2def0eea..fa6164c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -113,6 +113,10 @@ //! Documentation detailing the additional functions can be found on the //! [`MathematicalOps`](https://docs.rs/rust_decimal/latest/rust_decimal/trait.MathematicalOps.html) trait. //! +//! Please note that `ln` and `log10` will panic on invalid input with `checked_ln` and `checked_log10` the preferred functions +//! to curb against this. When the `maths` feature was first developed the library would return `0` on invalid input. To re-enable this +//! non-panicing behavior, please use the feature: `maths-nopanic`. +//! //! ### `rust-fuzz` //! //! Enable `rust-fuzz` support by implementing the `Arbitrary` trait.