summaryrefslogtreecommitdiffstats
path: root/third_party/rust/rust_decimal
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/rust_decimal')
-rw-r--r--third_party/rust/rust_decimal/.cargo-checksum.json1
-rw-r--r--third_party/rust/rust_decimal/CODE_OF_CONDUCT.md46
-rw-r--r--third_party/rust/rust_decimal/CONTRIBUTING.md40
-rw-r--r--third_party/rust/rust_decimal/Cargo.toml82
-rw-r--r--third_party/rust/rust_decimal/LICENSE21
-rw-r--r--third_party/rust/rust_decimal/README.md84
-rw-r--r--third_party/rust/rust_decimal/VERSION.md274
-rw-r--r--third_party/rust/rust_decimal/benches/lib_benches.rs194
-rw-r--r--third_party/rust/rust_decimal/rustfmt.toml1
-rw-r--r--third_party/rust/rust_decimal/src/decimal.rs3161
-rw-r--r--third_party/rust/rust_decimal/src/error.rs31
-rw-r--r--third_party/rust/rust_decimal/src/lib.rs56
-rw-r--r--third_party/rust/rust_decimal/src/postgres.rs856
-rw-r--r--third_party/rust/rust_decimal/src/serde_types.rs218
-rw-r--r--third_party/rust/rust_decimal/tests/decimal_tests.rs1633
15 files changed, 6698 insertions, 0 deletions
diff --git a/third_party/rust/rust_decimal/.cargo-checksum.json b/third_party/rust/rust_decimal/.cargo-checksum.json
new file mode 100644
index 0000000000..a3aae2c2ab
--- /dev/null
+++ b/third_party/rust/rust_decimal/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CODE_OF_CONDUCT.md":"64765f10290cfce7191b4208cb21698b708a118568f5016602cccc304846a09a","CONTRIBUTING.md":"471d6281fb5038e17e32d3b4450aacf542a396709605aa170e07d3971d70b9c1","Cargo.toml":"5bcdb31d3230d6592b1940f0730bc6a0a07c05ef245a4a71ae9ff48b83cc5f38","LICENSE":"f8218253704e32441cafea1b9b3bcb2c6a3c51c5553cd8513d179290202bccb2","README.md":"2e6fc38c2289725da3fea1e2429fdc6482484e32b3e11d0216b719d871193fc5","VERSION.md":"172eea9bab41bd1493cd6a4a03a6df5cdfba66a9f02ec79b776fe71ad55d5be8","benches/lib_benches.rs":"39a5a691cd614aee08c0be202d715045dfe1d27e0a998fd983b8cc2ceaca7b55","rustfmt.toml":"f33bda44a494d17c95b7bc1b3dd88c203030b75be766f3a7f9b63ef45d960bb0","src/decimal.rs":"23b00c66f1024c7883f654d492fa6563173b47aa7ad26b4641315883a8278ea4","src/error.rs":"7f546cbfb6b1fdc6bb7bb3d6ef9f1a2462e30beba6f561e1890e7515c9bfb640","src/lib.rs":"104050f8a7d36317da0021dd4b42973e5f6cd928d748f3d0621f100d8d66fa6e","src/postgres.rs":"454630887e43403011dacee0682d163e92aed0071f3258ee616624ec11b82eb6","src/serde_types.rs":"9eadeca56538e69cd909853dd378bffecf2acc98c651ca2eec3192b81044b0a1","tests/decimal_tests.rs":"6c2d5a178a064e4a5e1131ed0d6c14527e9ac819f52379c0225872fa23788bcf"},"package":"95ba36e8c41bf675947e200af432325f332f60a0aea0ef2dc456636c2f6037d7"} \ No newline at end of file
diff --git a/third_party/rust/rust_decimal/CODE_OF_CONDUCT.md b/third_party/rust/rust_decimal/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000..c86080edf9
--- /dev/null
+++ b/third_party/rust/rust_decimal/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at paul@form1.co.nz. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/third_party/rust/rust_decimal/CONTRIBUTING.md b/third_party/rust/rust_decimal/CONTRIBUTING.md
new file mode 100644
index 0000000000..fc8aa310ca
--- /dev/null
+++ b/third_party/rust/rust_decimal/CONTRIBUTING.md
@@ -0,0 +1,40 @@
+# Contributing to Rust Decimal
+
+Rust Decimal welcomes contributions from everyone. Here are the guidelines if you are
+thinking of helping us:
+
+## Contributions
+
+Contributions to Rust Decimal or its dependencies should be made in the form of GitHub
+pull requests. Each pull request will be reviewed by a core contributor
+(someone with permission to land patches) and either landed in the main tree or
+given feedback for changes that would be required. All contributions should
+follow this format, even those from core contributors.
+
+Should you wish to work on an issue, please claim it first by commenting on
+the GitHub issue that you want to work on it. This is to prevent duplicated
+efforts from contributors on the same issue.
+
+## Pull Request Checklist
+
+- Branch from the master branch and, if needed, rebase to the current master
+ branch before submitting your pull request. If it doesn't merge cleanly with
+ master you may be asked to rebase your changes.
+
+- If your patch is not getting reviewed or you need a specific person to review
+ it, you can @-reply a reviewer asking for a review in the pull request or inside a
+ comment.
+
+- Add tests relevant to the fixed bug or new feature.
+
+## Conduct
+
+In all Rust Decimal related forums, we follow the [Rust Code of
+Conduct](https://www.rust-lang.org/conduct.html). For escalation or moderation of
+issues, please contact Paul (paul@form1.co.nz) instead of the Rust
+moderation team.
+
+## Communication
+
+Opening tickets on the
+[paupino/rust-decimal](https://github.com/paupino/rust-decimal) project is the preferred method of communication. \ No newline at end of file
diff --git a/third_party/rust/rust_decimal/Cargo.toml b/third_party/rust/rust_decimal/Cargo.toml
new file mode 100644
index 0000000000..23c99a12f4
--- /dev/null
+++ b/third_party/rust/rust_decimal/Cargo.toml
@@ -0,0 +1,82 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "rust_decimal"
+version = "1.7.0"
+authors = ["Paul Mason <paul@form1.co.nz>"]
+description = "A Decimal Implementation written in pure Rust suitable for financial calculations."
+documentation = "https://docs.rs/rust_decimal/"
+readme = "./README.md"
+keywords = ["decimal", "financial", "fixed", "precision"]
+categories = ["science", "data-structures"]
+license = "MIT"
+repository = "https://github.com/paupino/rust-decimal"
+[dependencies.byteorder]
+version = "1.3"
+optional = true
+
+[dependencies.bytes]
+version = "0.5"
+optional = true
+
+[dependencies.diesel]
+version = "1.4"
+features = ["postgres"]
+optional = true
+default-features = false
+
+[dependencies.num-traits]
+version = "0.2"
+
+[dependencies.postgres]
+version = "0.17"
+optional = true
+
+[dependencies.serde]
+version = "1.0"
+optional = true
+
+[dependencies.tokio-postgres]
+version = "0.5"
+optional = true
+[dev-dependencies.bincode]
+version = "1.3"
+
+[dev-dependencies.bytes]
+version = "0.5"
+
+[dev-dependencies.futures]
+version = "0.3"
+
+[dev-dependencies.rand]
+version = "0.7"
+
+[dev-dependencies.serde_derive]
+version = "1.0"
+
+[dev-dependencies.serde_json]
+version = "1.0"
+
+[dev-dependencies.tokio]
+version = "0.2"
+features = ["rt-threaded", "test-util", "macros"]
+
+[features]
+db-diesel-postgres = ["diesel"]
+db-postgres = ["postgres", "bytes", "byteorder"]
+db-tokio-postgres = ["postgres", "tokio-postgres", "bytes", "byteorder"]
+default = ["serde"]
+serde-bincode = ["serde"]
+serde-float = ["serde"]
+tokio-pg = ["db-tokio-postgres"]
diff --git a/third_party/rust/rust_decimal/LICENSE b/third_party/rust/rust_decimal/LICENSE
new file mode 100644
index 0000000000..68364efa4e
--- /dev/null
+++ b/third_party/rust/rust_decimal/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 Paul Mason
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/third_party/rust/rust_decimal/README.md b/third_party/rust/rust_decimal/README.md
new file mode 100644
index 0000000000..1a713b2369
--- /dev/null
+++ b/third_party/rust/rust_decimal/README.md
@@ -0,0 +1,84 @@
+# Decimal &emsp; [![Build Status]][actions] [![Latest Version]][crates.io]
+
+[Build Status]: https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fpaupino%2Frust-decimal%2Fbadge&label=build&logo=none
+[actions]: https://actions-badge.atrox.dev/paupino/rust-decimal/goto
+[Latest Version]: https://img.shields.io/crates/v/rust-decimal.svg
+[crates.io]: https://crates.io/crates/rust-decimal
+
+A Decimal implementation written in pure Rust suitable for financial calculations that require significant integral and fractional digits with no round-off errors.
+
+The binary representation consists of a 96 bit integer number, a scaling factor used to specify the decimal fraction and a 1 bit sign. Because of this representation, trailing zeros are preserved and may be exposed when in string form. These can be truncated using the `normalize` or `round_dp` functions.
+
+[Documentation](https://docs.rs/rust_decimal/)
+
+## Usage
+
+Decimal numbers can be created in a few distinct ways. The easiest and most optimal method of creating a Decimal is to use the procedural macro within the `rust_decimal_macros` crate:
+
+```rust
+// Procedural macros need importing directly
+use rust_decimal_macros::*;
+
+let number = dec!(-1.23);
+```
+
+Alternatively you can also use one of the Decimal number convenience functions:
+
+```rust
+use rust_decimal::prelude::*;
+
+// Using an integer followed by the decimal points
+let scaled = Decimal::new(202, 2); // 2.02
+
+// From a string representation
+let from_string = Decimal::from_str("2.02").unwrap(); // 2.02
+
+// Using the `Into` trait
+let my_int : Decimal = 3i32.into();
+
+// Using the raw decimal representation
+// 3.1415926535897932384626433832
+let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28);
+```
+
+## Features
+
+* [db-postgres](#db-postgres)
+* [db-tokio-postgres](#db-tokio-postgres)
+* [db-diesel-postgres](#db-diesel-postgres)
+* [serde-float](#serde-float)
+* [serde-bincode](#serde-bincode)
+
+## `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`
+
+Enables the tokio postgres module allowing for async communication with PostgreSQL.
+
+## `db-diesel-postgres`
+
+Enable `diesel` PostgreSQL support.
+
+## `serde-float`
+
+Enable this so that JSON serialization of Decimal types are sent as a float instead of a string (default).
+
+e.g. with this turned on, JSON serialization would output:
+```
+{
+ "value": 1.234
+}
+```
+
+## `serde-bincode`
+
+Since `bincode` does not specify type information, we need to ensure that a type hint is provided in order to
+correctly be able to deserialize. Enabling this feature on it's own will force deserialization to use `deserialize_str`
+instead of `deserialize_any`.
+
+If, for some reason, you also have `serde-float` enabled then this will use `deserialize_f64` as a type hint. Because
+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 regards to storage size.
diff --git a/third_party/rust/rust_decimal/VERSION.md b/third_party/rust/rust_decimal/VERSION.md
new file mode 100644
index 0000000000..2396fd8040
--- /dev/null
+++ b/third_party/rust/rust_decimal/VERSION.md
@@ -0,0 +1,274 @@
+# Version History
+
+## 1.7.0
+
+* Enables `bincode` support via the feature `serde-bincode`. This provides a long term fix for a regression
+ that was introduced in version `0.6.5` (tests now cover this case!). [Issue 43](https://github.com/paupino/rust-decimal/issues/43).
+* Fixes issue where `rescale` on zero would not have an affect. This was due to an early exit condition which failed to
+ set the new scale. [Issue 253](https://github.com/paupino/rust-decimal/issues/253).
+* Add `min` and `max` functions, similar to what `f32` and `f64` provide. Thank you [@michalsieron](https://github.com/michalsieron).
+* Updates documentation for `is_sign_positive` and `is_sign_negative` to specify that the sign bit is being checked.
+
+Please note: feature naming conventions have been modified, however backwards compatible aliases have been created where
+necessary. It's highly recommended that you move over to the new naming conventions as these aliases may be removed at a
+later date.
+
+## 1.6.0
+
+* Fixes issue with PostgreSQL conversions whereby certain inputs would cause unexpected
+ outputs. [Issue 241](https://github.com/paupino/rust-decimal/issues/241).
+* Fixes issue with `from_str_radix` whereby rounding logic would kick in too early,
+ especially with radix less than 10. [Issue 242](https://github.com/paupino/rust-decimal/issues/242).
+* Fixes issue whereby `from_str` (implicity `from_str_radix`) would panic when there was overflow
+ and overflow significant digit was < 5. [Issue 246](https://github.com/paupino/rust-decimal/issues/246).
+* Make `bytes` and `byteorder` optional since they're only used in the `postgres` feature and tests.
+* Fix edge case in `from_i128_with_scale` when `i128::MIN` was provided.
+
+Thank you to [@serejkaaa512](https://github.com/serejkaaa512), [@AbsurdlySuspicious](https://github.com/AbsurdlySuspicious) and [@0e4ef622]((https://github.com/0e4ef622)) for your contributions!
+
+## 1.5.0
+
+* Added additional `RoundStrategy` abilities: `RoundUp` to always round up and `RoundDown` to always round down.
+* Updated prelude to include expected structs and traits by default.
+
+Special thank you to [@jean-airoldie](https://github.com/jean-airoldie) for adding the additional rounding strategies and to [@pfrenssen](https://github.com/pfrenssen) for fixing an
+issue in the README.
+
+## 1.4.1
+
+* Performance improvements for `to_f64` when using a scale > 0.
+
+Special thank you to [@hengchu](https://github.com/hengchu) who discovered and resolved the issue!
+
+## 1.4.0
+
+* Allow uppercase "E" in scientific notation.
+* Allow scientific notation in `dec!` macro.
+* Deprecate `set_sign` and replace with `set_sign_positive` and `set_sign_negative`. This is intended
+ to improve the readability of the API.
+* Fixes precision issue when parsing `f64` values. The base 2 mantissa of the float was assuming guaranteed accuracy
+ of 53 bit precision, however 52 bit precision is more accurate (`f64` only).
+* Removes deprecated usage of `Error::description`.
+
+## 1.3.0
+
+* Replace `num` dependency with `num_trait` - implemented `Signed` and `Num` traits.
+
+## 1.2.1
+
+* Fixes issue whereby overflow would occur reading from PostgreSQL with high precision. The library now
+ handles this by rounding high precision numbers as they're read as opposed to crashing (similar to other
+ underflow situations e.g. 1/3).
+
+## 1.2.0
+
+* Retain trailing zeros from PostgreSQL. This ensures that the scale is maintained when serialized into the Decimal type.
+* Fixes issue where -0 != 0 (these are now equivalent - thank you @hengchu for discovering).
+* Improve hashing function so that the following property is true: `k1 == k2 -> hash(k1) == hash(k2)`
+* Update normalize function so that -0 normalizes to 0.
+
+Special thanks to @hathawsh for their help in this release!
+
+## 1.1.0
+
+* Update to Postgres 0.17 and add postgres async/await support via `tokio-pg`
+* Added option for serializing decimals as float via `serde-float`
+
+Special thanks to @pimeys and @kaibyao!
+
+## 1.0.3
+
+Updates dependencies to prevent build issues.
+
+## 1.0.2
+
+Bug fix release:
+
+* Fixes issue where scaling logic produced incorrect results when one arm was a high precision zero. Thank you @KonishchevDmitry!
+
+## 1.0.1
+
+Bug fix release:
+
+* Fixes issue where `ToSql` was incorrectly calculating weight when whole portion = numeric portion.
+* Fixes issue where `Decimal::new` incorrectly handled `i64::max_value()` and `i64::min_value()`.
+* Fixes issue where `rem` operation incorrectly returned results when `scale` was required.
+
+## 1.0.0
+
+This release represents the start of semantic versioning and allows the library to start making fundamental improvements under
+the guise of V2.0. Leading up to that I expect to release 1.x versions which will include adding
+various mathematical functions such as `pow`, `ln`, `log10` etc.
+
+Version `1.0.0` does come with some new features:
+
+* Checked Operations! This implements `checked_add`, `checked_sub`, `checked_mul`, `checked_div` and `checked_rem`.
+* Fixes overflow from `max_value()` and `min_value()` for `i32` and `i64`.
+* Minor documentation improvements and test coverage.
+
+Special thanks to @0e4ef622 for their help with this release!
+
+## 0.11.3
+
+* Add prelude to help num trait inclusion (`use rust_decimal::prelude::*`)
+* Add `Default` trait to the library. This is equivalent to using `Decimal::zero()`
+* Added assignment operators for references.
+
+Special thanks to @jean-airoldie for his help with this release!
+
+## 0.11.2
+
+* Fall back to `from_scientific` when `from_str` fails during deserialization. Thanks @mattjbray!
+* Added basic `Sum` trait implementation
+
+## 0.11.1
+
+* Fixes a bug in `floor` and `ceil` where negative numbers were incorrectly handled.
+
+## 0.11.0
+
+* Macros are now supported on stable. This does use a [hack](https://github.com/dtolnay/proc-macro-hack) for the meantime
+so due diligence is required before usage.
+* Fixes issue when parsing strings where an underscore preceded a decimal point.
+* `const_fn` support via a feature flag. In the future this will be the default option however in order to support older
+compiler versions is behind a feature flag.
+
+## 0.10.2
+
+* Macros (nightly) now output structural data as opposed to serialized data. This is fully backwards compatible and results in some minor performance improvements. Also, removed feature gate so that it can be compiled in stable.
+* Fixes a string parsing bug when given highly significant numbers that require rounding.
+
+## 0.10.1
+
+* Bumped dependencies to remove some legacy serialization requirements.
+
+## 0.10.0
+
+Special thanks to @xilec, @snd and @AndrewSpeed for their help with this release.
+
+* New rounding strategies introduced via `round_dp_with_strategy`. Previously default rounding support used bankers rounding by default whereas now you can choose to round the half way point either up or down.
+* PostgreSQL write performance improved so that it is at least 3 times faster than the previous implementation.
+* `Debug` trait now outputs the actual decimal number by default to make it more useful within consuming libraries (e.g. `criterion.rs`). To get something similar to the previous functionality you can use the `unpack` argument - this is likely for core `rust-decimal` library maintainers.
+* Various other performance improvements for common operations such as `rescale`, `sub` and `div`.
+
+## 0.9.1
+
+* Performance optimization for `add`.
+
+## 0.9.0
+
+* Introduces the `Neg` trait to support the ability to use `-decimal_variable`.
+* Fixes bug with underflow on addition.
+
+## 0.8.1
+
+This release updates the published documentation only and is a no-op for functionality.
+
+## 0.8.0
+
+* Introduces `from_scientific` allowing parsing of scientific notation into the Decimal type.
+* Fixes a bug when formatting a number with a leading zero's.
+
+## 0.7.2
+
+* Fixes bug in `rescale` whereby scaling which invoked rounding incorrectly set the new scale for the left/right sides.
+
+## 0.7.1
+
+* Fixes bug in `cmp` whereby two negatives would return an incorrect result.
+* Further documentation examples
+* Small improvements in division logic
+* New `abs`, `floor` and `ceil` functions.
+
+## 0.7.0
+
+This is a minor version bump as we slowly build our way towards 1.0. Thank you for everyone's support and help as we get there! This has a few notable changes - also introducing a few new interfaces which is the reason for the version bump:
+
+* `from_parts` function to allow effective creation of `Decimal`'s without requiring binary serialization. An example of this benefit is with the lazy static group initializers for Postgres.
+* `normalize` function to allow stripping trailing zero's easily.
+* `trunc` function allows truncation of a number without any rounding. This effectively "truncates" the fractional part of the number.
+* `fract` function returns the fractional part of the number without the integral.
+* Minor improvements in some iterator logic, utilizing the compiler for further optimizations.
+* Fixes issue in string parsing logic whereby `_` would cause numbers to be incorrectly identified.
+* Many improvements to `mul`. Numbers utilizing the `lo` portion of the decimal only will now be shortcut and bigger numbers will now correctly overflow. True overflows will still panic, however large underflows will now be rounded as necessary as opposed to panicing.
+* `Hash` was implemented by convention in `0.6.5` however is reimplemented explicitly in `0.7.0` for effectiveness.
+* PostgreSQL read performance improved by pre-caching groups and leveraging `normalize` (i.e. avoiding strings). Further optimizations can be made in write however require some `div` optimizations first.
+* Added short circuit write improvement for zero in PostgreSQL writes.
+* Benchmarks are now recorded per build so we can start tracking where slow downs have occurred. This does mean there is a performance hit on Travis builds however hopefully the pay off will make it worthwhile.
+
+## 0.6.5
+
+Fixes issue with rescale sometimes causing a silent overflow which led to incorrect results during addition, subtraction and compare. Consequently Decimal now rounds the most significant number so that these operations work successfully.
+
+In addition, Decimal now derive's the `Hash` trait so that it can be used for indexing.
+
+## 0.6.4
+
+Fixes silent overflow errors when parsing highly significant strings. `from_str` will now round in these scenario's, similar to oleaut32 behavior.
+
+## 0.6.3
+
+Fixes a regression in ordering where by different scales would be rescaled towards losing precision instead of increasing precision. Have added numerous test suites to help cover more issues like this in the future.
+Also fixes an issue in parsing invalid strings whereby the precision exceeded our maximum precision. Previously, this would work with unintended results however this now returns an Error returned from `FromStr`.
+
+## 0.6.2
+
+Fixes an issue with division of rational numbers allowing results greater than `MAX_PRECISION`. This would ultimately cause issues for future operations on this number.
+In addition, in some cases transitive operations would not be equal due to overflow being lost.
+
+## 0.6.1
+
+This minor release is purely to expose `rust_decimal_macros` for use on the nightly channel. Documentation has been updated accordingly.
+
+## 0.6.0
+
+This release has a few major changes to the internal workings of the `Decimal` implementation and consequently comes with a number of performance improvements.
+
+* Floats can now be parsed into a `Decimal` type using `from_f32` and `from_f64`.
+* `add`, `sub`, `mul` run roughly 1500% faster than before.
+* `div` run's roughly 1000% faster than before with room for future improvement.
+* Also get significant speed improvements with `cmp`, `rescale`, `round_dp` and some string manipulations.
+* Implemented `*Assign` traits for simpler usage.
+* Removed `BigInt` and `BigUint` as being intermediary data types.
+
+## 0.5.2
+
+Minor bug fix to prevent a `panic` from overflow during comparison of high significant digit decimals.
+
+## 0.5.1
+
+Minor bux fix to prevent `panic` upon parsing an empty string.
+
+## 0.5.0
+
+* Removes postgres from default feature set.
+* `bincode` support for serde
+* Better support for format strings
+* Benchmarks added to tests
+
+## 0.4.2
+
+Fixes bug in `cmp` whereby negative's were not being compared correctly.
+
+## 0.4.1
+
+Minor bug fix to support creating negative numbers using the default constructor.
+
+## 0.4.0
+
+This release is a stylistic cleanup however does include some minor changes that may break existing builds.
+
+### Changed
+* Serde is now optional. You can enable Serde support within `features` using the keyword `serde`.
+* Serde now returns errors on invalid input as opposed to `0`.
+* `f64` conversion support has been added.
+* Update Postgres dependency to use v0.15.
+
+## 0.3.1
+
+This is a documentation release that should help with discoverability and usage.
+
+## 0.3.0
+
+### Changed
+* Removed trait `ToDecimal` and replaced with builtin [`From`](https://doc.rust-lang.org/std/convert/trait.From.html) trait ([`#12`](https://github.com/paupino/rust-decimal/pull/12))
diff --git a/third_party/rust/rust_decimal/benches/lib_benches.rs b/third_party/rust/rust_decimal/benches/lib_benches.rs
new file mode 100644
index 0000000000..89e7e70b94
--- /dev/null
+++ b/third_party/rust/rust_decimal/benches/lib_benches.rs
@@ -0,0 +1,194 @@
+#![feature(test)]
+
+extern crate test;
+
+use rust_decimal::Decimal;
+use std::str::FromStr;
+
+macro_rules! bench_decimal_op {
+ ($name:ident, $op:tt, $y:expr) => {
+ #[bench]
+ fn $name(b: &mut ::test::Bencher) {
+ let x = Decimal::from_str("2.01").unwrap();
+ let y = Decimal::from_str($y).unwrap();
+ b.iter(|| {
+ let result = x $op y;
+ ::test::black_box(result);
+ });
+ }
+ }
+}
+
+macro_rules! bench_fold_op {
+ ($name:ident, $op:tt, $init:expr, $count:expr) => {
+ #[bench]
+ fn $name(b: &mut ::test::Bencher) {
+ fn fold(values: &[Decimal]) -> Decimal {
+ let mut acc: Decimal = $init.into();
+ for value in values {
+ acc = acc $op value;
+ }
+ acc
+ }
+
+ let values: Vec<Decimal> = test::black_box((1..$count).map(|i| i.into()).collect());
+ b.iter(|| {
+ let result = fold(&values);
+ ::test::black_box(result);
+ });
+ }
+ }
+}
+
+/* Add */
+bench_decimal_op!(add_one, +, "1");
+bench_decimal_op!(add_two, +, "2");
+bench_decimal_op!(add_one_hundred, +, "100");
+bench_decimal_op!(add_point_zero_one, +, "0.01");
+bench_decimal_op!(add_negative_point_five, +, "-0.5");
+bench_decimal_op!(add_pi, +, "3.1415926535897932384626433832");
+bench_decimal_op!(add_negative_pi, +, "-3.1415926535897932384626433832");
+
+bench_fold_op!(add_10k, +, 0, 10_000);
+
+/* Sub */
+bench_decimal_op!(sub_one, -, "1");
+bench_decimal_op!(sub_two, -, "2");
+bench_decimal_op!(sub_one_hundred, -, "100");
+bench_decimal_op!(sub_point_zero_one, -, "0.01");
+bench_decimal_op!(sub_negative_point_five, -, "-0.5");
+bench_decimal_op!(sub_pi, -, "3.1415926535897932384626433832");
+bench_decimal_op!(sub_negative_pi, -, "-3.1415926535897932384626433832");
+
+bench_fold_op!(sub_10k, -, 5_000_000, 10_000);
+
+/* Mul */
+bench_decimal_op!(mul_one, *, "1");
+bench_decimal_op!(mul_two, *, "2");
+bench_decimal_op!(mul_one_hundred, *, "100");
+bench_decimal_op!(mul_point_zero_one, *, "0.01");
+bench_decimal_op!(mul_negative_point_five, *, "-0.5");
+bench_decimal_op!(mul_pi, *, "3.1415926535897932384626433832");
+bench_decimal_op!(mul_negative_pi, *, "-3.1415926535897932384626433832");
+
+/* Div */
+bench_decimal_op!(div_one, /, "1");
+bench_decimal_op!(div_two, /, "2");
+bench_decimal_op!(div_one_hundred, /, "100");
+bench_decimal_op!(div_point_zero_one, /, "0.01");
+bench_decimal_op!(div_negative_point_five, /, "-0.5");
+bench_decimal_op!(div_pi, /, "3.1415926535897932384626433832");
+bench_decimal_op!(div_negative_pi, /, "-3.1415926535897932384626433832");
+
+bench_fold_op!(div_10k, /, Decimal::max_value(), 10_000);
+
+/* Iteration */
+struct DecimalIterator {
+ count: usize,
+}
+
+impl DecimalIterator {
+ fn new() -> DecimalIterator {
+ DecimalIterator { count: 0 }
+ }
+}
+
+impl Iterator for DecimalIterator {
+ type Item = Decimal;
+
+ fn next(&mut self) -> Option<Decimal> {
+ self.count += 1;
+ if self.count < 6 {
+ Some(Decimal::new(314, 2))
+ } else {
+ None
+ }
+ }
+}
+
+#[bench]
+fn iterator_individual(b: &mut ::test::Bencher) {
+ b.iter(|| {
+ let mut result = Decimal::new(0, 0);
+ let iterator = DecimalIterator::new();
+ for i in iterator {
+ result += i;
+ }
+ ::test::black_box(result);
+ });
+}
+
+#[bench]
+fn iterator_sum(b: &mut ::test::Bencher) {
+ b.iter(|| {
+ let result: Decimal = DecimalIterator::new().sum();
+ ::test::black_box(result);
+ });
+}
+
+#[bench]
+fn decimal_from_str(b: &mut test::Bencher) {
+ let samples_strs = &[
+ "3950.123456",
+ "3950",
+ "0.1",
+ "0.01",
+ "0.001",
+ "0.0001",
+ "0.00001",
+ "0.000001",
+ "1",
+ "-100",
+ "-123.456",
+ "119996.25",
+ "1000000",
+ "9999999.99999",
+ "12340.56789",
+ ];
+
+ b.iter(|| {
+ for s in samples_strs {
+ let result = Decimal::from_str(s).unwrap();
+ test::black_box(result);
+ }
+ })
+}
+
+#[cfg(feature = "postgres")]
+#[bench]
+fn to_from_sql(b: &mut ::test::Bencher) {
+ use postgres::types::{FromSql, Kind, ToSql, Type};
+
+ let samples_strs = &[
+ "3950.123456",
+ "3950",
+ "0.1",
+ "0.01",
+ "0.001",
+ "0.0001",
+ "0.00001",
+ "0.000001",
+ "1",
+ "-100",
+ "-123.456",
+ "119996.25",
+ "1000000",
+ "9999999.99999",
+ "12340.56789",
+ ];
+
+ let samples: Vec<Decimal> = test::black_box(samples_strs.iter().map(|x| Decimal::from_str(x).unwrap()).collect());
+ let t = Type::_new("".into(), 0, Kind::Simple, "".into());
+ let mut vec = Vec::<u8>::with_capacity(100);
+
+ b.iter(|| {
+ for _ in 0..100 {
+ for sample in &samples {
+ vec.clear();
+ sample.to_sql(&t, &mut vec).unwrap();
+ let result = Decimal::from_sql(&t, &vec).unwrap();
+ ::test::black_box(result);
+ }
+ }
+ });
+}
diff --git a/third_party/rust/rust_decimal/rustfmt.toml b/third_party/rust/rust_decimal/rustfmt.toml
new file mode 100644
index 0000000000..866c756105
--- /dev/null
+++ b/third_party/rust/rust_decimal/rustfmt.toml
@@ -0,0 +1 @@
+max_width = 120 \ No newline at end of file
diff --git a/third_party/rust/rust_decimal/src/decimal.rs b/third_party/rust/rust_decimal/src/decimal.rs
new file mode 100644
index 0000000000..34ab50598c
--- /dev/null
+++ b/third_party/rust/rust_decimal/src/decimal.rs
@@ -0,0 +1,3161 @@
+use crate::Error;
+
+use num_traits::{FromPrimitive, Num, One, Signed, ToPrimitive, Zero};
+
+#[cfg(feature = "diesel")]
+use diesel::sql_types::Numeric;
+
+use std::{
+ cmp::{Ordering::Equal, *},
+ fmt,
+ hash::{Hash, Hasher},
+ iter::{repeat, Sum},
+ ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
+ str::FromStr,
+};
+
+// Sign mask for the flags field. A value of zero in this bit indicates a
+// positive Decimal value, and a value of one in this bit indicates a
+// negative Decimal value.
+const SIGN_MASK: u32 = 0x8000_0000;
+const UNSIGN_MASK: u32 = 0x4FFF_FFFF;
+
+// Scale mask for the flags field. This byte in the flags field contains
+// the power of 10 to divide the Decimal value by. The scale byte must
+// contain a value between 0 and 28 inclusive.
+const SCALE_MASK: u32 = 0x00FF_0000;
+const U8_MASK: u32 = 0x0000_00FF;
+const U32_MASK: u64 = 0xFFFF_FFFF;
+
+// Number of bits scale is shifted by.
+const SCALE_SHIFT: u32 = 16;
+// Number of bits sign is shifted by.
+const SIGN_SHIFT: u32 = 31;
+
+// The maximum supported precision
+pub(crate) const MAX_PRECISION: u32 = 28;
+// 79,228,162,514,264,337,593,543,950,335
+const MAX_I128_REPR: i128 = 0x0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF;
+
+static ONE_INTERNAL_REPR: [u32; 3] = [1, 0, 0];
+
+const MIN: Decimal = Decimal {
+ flags: 2_147_483_648,
+ lo: 4_294_967_295,
+ mid: 4_294_967_295,
+ hi: 4_294_967_295,
+};
+
+const MAX: Decimal = Decimal {
+ flags: 0,
+ lo: 4_294_967_295,
+ mid: 4_294_967_295,
+ hi: 4_294_967_295,
+};
+
+// Fast access for 10^n where n is 0-9
+static POWERS_10: [u32; 10] = [
+ 1,
+ 10,
+ 100,
+ 1_000,
+ 10_000,
+ 100_000,
+ 1_000_000,
+ 10_000_000,
+ 100_000_000,
+ 1_000_000_000,
+];
+// Fast access for 10^n where n is 10-19
+#[allow(dead_code)]
+static BIG_POWERS_10: [u64; 10] = [
+ 10_000_000_000,
+ 100_000_000_000,
+ 1_000_000_000_000,
+ 10_000_000_000_000,
+ 100_000_000_000_000,
+ 1_000_000_000_000_000,
+ 10_000_000_000_000_000,
+ 100_000_000_000_000_000,
+ 1_000_000_000_000_000_000,
+ 10_000_000_000_000_000_000,
+];
+
+/// `UnpackedDecimal` contains unpacked representation of `Decimal` where each component
+/// of decimal-format stored in it's own field
+#[derive(Clone, Copy, Debug)]
+pub struct UnpackedDecimal {
+ pub is_negative: bool,
+ pub scale: u32,
+ pub hi: u32,
+ pub mid: u32,
+ pub lo: u32,
+}
+
+/// `Decimal` represents a 128 bit representation of a fixed-precision decimal number.
+/// The finite set of values of type `Decimal` are of the form m / 10<sup>e</sup>,
+/// where m is an integer such that -2<sup>96</sup> < m < 2<sup>96</sup>, and e is an integer
+/// between 0 and 28 inclusive.
+#[derive(Clone, Copy)]
+#[cfg_attr(feature = "diesel", derive(FromSqlRow, AsExpression), sql_type = "Numeric")]
+pub struct Decimal {
+ // Bits 0-15: unused
+ // Bits 16-23: Contains "e", a value between 0-28 that indicates the scale
+ // Bits 24-30: unused
+ // Bit 31: the sign of the Decimal value, 0 meaning positive and 1 meaning negative.
+ flags: u32,
+ // The lo, mid, hi, and flags fields contain the representation of the
+ // Decimal value as a 96-bit integer.
+ hi: u32,
+ lo: u32,
+ mid: u32,
+}
+
+/// `RoundingStrategy` represents the different strategies that can be used by
+/// `round_dp_with_strategy`.
+///
+/// `RoundingStrategy::BankersRounding` - Rounds toward the nearest even number, e.g. 6.5 -> 6, 7.5 -> 8
+/// `RoundingStrategy::RoundHalfUp` - Rounds up if the value >= 5, otherwise rounds down, e.g. 6.5 -> 7,
+/// `RoundingStrategy::RoundHalfDown` - Rounds down if the value =< 5, otherwise rounds up, e.g.
+/// 6.5 -> 6, 6.51 -> 7
+/// 1.4999999 -> 1
+/// `RoundingStrategy::RoundDown` - Always round down.
+/// `RoundingStrategy::RoundUp` - Always round up.
+pub enum RoundingStrategy {
+ BankersRounding,
+ RoundHalfUp,
+ RoundHalfDown,
+ RoundDown,
+ RoundUp,
+}
+
+#[allow(dead_code)]
+impl Decimal {
+ /// Returns a `Decimal` with a 64 bit `m` representation and corresponding `e` scale.
+ ///
+ /// # Arguments
+ ///
+ /// * `num` - An i64 that represents the `m` portion of the decimal number
+ /// * `scale` - A u32 representing the `e` portion of the decimal number.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let pi = Decimal::new(3141, 3);
+ /// assert_eq!(pi.to_string(), "3.141");
+ /// ```
+ pub fn new(num: i64, scale: u32) -> Decimal {
+ if scale > MAX_PRECISION {
+ panic!(
+ "Scale exceeds the maximum precision allowed: {} > {}",
+ scale, MAX_PRECISION
+ );
+ }
+ let flags: u32 = scale << SCALE_SHIFT;
+ if num < 0 {
+ let pos_num = num.wrapping_neg() as u64;
+ return Decimal {
+ flags: flags | SIGN_MASK,
+ hi: 0,
+ lo: (pos_num & U32_MASK) as u32,
+ mid: ((pos_num >> 32) & U32_MASK) as u32,
+ };
+ }
+ Decimal {
+ flags,
+ hi: 0,
+ lo: (num as u64 & U32_MASK) as u32,
+ mid: ((num as u64 >> 32) & U32_MASK) as u32,
+ }
+ }
+
+ /// Creates a `Decimal` using a 128 bit signed `m` representation and corresponding `e` scale.
+ ///
+ /// # Arguments
+ ///
+ /// * `num` - An i128 that represents the `m` portion of the decimal number
+ /// * `scale` - A u32 representing the `e` portion of the decimal number.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let pi = Decimal::from_i128_with_scale(3141i128, 3);
+ /// assert_eq!(pi.to_string(), "3.141");
+ /// ```
+ pub fn from_i128_with_scale(num: i128, scale: u32) -> Decimal {
+ if scale > MAX_PRECISION {
+ panic!(
+ "Scale exceeds the maximum precision allowed: {} > {}",
+ scale, MAX_PRECISION
+ );
+ }
+ let mut neg = false;
+ let mut wrapped = num;
+ if num > MAX_I128_REPR {
+ panic!("Number exceeds maximum value that can be represented");
+ } else if num < -MAX_I128_REPR {
+ panic!("Number less than minimum value that can be represented");
+ } else if num < 0 {
+ neg = true;
+ wrapped = -num;
+ }
+ let flags: u32 = flags(neg, scale);
+ Decimal {
+ flags,
+ lo: (wrapped as u64 & U32_MASK) as u32,
+ mid: ((wrapped as u64 >> 32) & U32_MASK) as u32,
+ hi: ((wrapped as u128 >> 64) as u64 & U32_MASK) as u32,
+ }
+ }
+
+ /// Returns a `Decimal` using the instances constituent parts.
+ ///
+ /// # Arguments
+ ///
+ /// * `lo` - The low 32 bits of a 96-bit integer.
+ /// * `mid` - The middle 32 bits of a 96-bit integer.
+ /// * `hi` - The high 32 bits of a 96-bit integer.
+ /// * `negative` - `true` to indicate a negative number.
+ /// * `scale` - A power of 10 ranging from 0 to 28.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28);
+ /// assert_eq!(pi.to_string(), "3.1415926535897932384626433832");
+ /// ```
+ pub const fn from_parts(lo: u32, mid: u32, hi: u32, negative: bool, scale: u32) -> Decimal {
+ Decimal {
+ lo,
+ mid,
+ hi,
+ flags: flags(negative, scale),
+ }
+ }
+
+ /// Returns a `Result` which if successful contains the `Decimal` constitution of
+ /// the scientific notation provided by `value`.
+ ///
+ /// # Arguments
+ ///
+ /// * `value` - The scientific notation of the `Decimal`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let value = Decimal::from_scientific("9.7e-7").unwrap();
+ /// assert_eq!(value.to_string(), "0.00000097");
+ /// ```
+ pub fn from_scientific(value: &str) -> Result<Decimal, Error> {
+ let err = Error::new("Failed to parse");
+ let mut split = value.splitn(2, |c| c == 'e' || c == 'E');
+
+ let base = split.next().ok_or_else(|| err.clone())?;
+ let exp = split.next().ok_or_else(|| err.clone())?;
+
+ let mut ret = Decimal::from_str(base)?;
+ let current_scale = ret.scale();
+
+ if exp.starts_with('-') {
+ let exp: u32 = exp[1..].parse().map_err(move |_| err)?;
+ ret.set_scale(current_scale + exp)?;
+ } else {
+ let exp: u32 = exp.parse().map_err(move |_| err)?;
+ if exp <= current_scale {
+ ret.set_scale(current_scale - exp)?;
+ } else {
+ ret *= Decimal::from_i64(10_i64.pow(exp)).unwrap();
+ ret = ret.normalize();
+ }
+ }
+ Ok(ret)
+ }
+
+ /// Returns the scale of the decimal number, otherwise known as `e`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let num = Decimal::new(1234, 3);
+ /// assert_eq!(num.scale(), 3u32);
+ /// ```
+ #[inline]
+ pub const fn scale(&self) -> u32 {
+ ((self.flags & SCALE_MASK) >> SCALE_SHIFT) as u32
+ }
+
+ /// An optimized method for changing the sign of a decimal number.
+ ///
+ /// # Arguments
+ ///
+ /// * `positive`: true if the resulting decimal should be positive.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let mut one = Decimal::new(1, 0);
+ /// one.set_sign(false);
+ /// assert_eq!(one.to_string(), "-1");
+ /// ```
+ #[deprecated(since = "1.4.0", note = "please use `set_sign_positive` instead")]
+ pub fn set_sign(&mut self, positive: bool) {
+ self.set_sign_positive(positive);
+ }
+
+ /// An optimized method for changing the sign of a decimal number.
+ ///
+ /// # Arguments
+ ///
+ /// * `positive`: true if the resulting decimal should be positive.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let mut one = Decimal::new(1, 0);
+ /// one.set_sign_positive(false);
+ /// assert_eq!(one.to_string(), "-1");
+ /// ```
+ #[inline(always)]
+ pub fn set_sign_positive(&mut self, positive: bool) {
+ if positive {
+ self.flags &= UNSIGN_MASK;
+ } else {
+ self.flags |= SIGN_MASK;
+ }
+ }
+
+ /// An optimized method for changing the sign of a decimal number.
+ ///
+ /// # Arguments
+ ///
+ /// * `negative`: true if the resulting decimal should be negative.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let mut one = Decimal::new(1, 0);
+ /// one.set_sign_negative(true);
+ /// assert_eq!(one.to_string(), "-1");
+ /// ```
+ #[inline(always)]
+ pub fn set_sign_negative(&mut self, negative: bool) {
+ self.set_sign_positive(!negative);
+ }
+
+ /// An optimized method for changing the scale of a decimal number.
+ ///
+ /// # Arguments
+ ///
+ /// * `scale`: the new scale of the number
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let mut one = Decimal::new(1, 0);
+ /// one.set_scale(5);
+ /// assert_eq!(one.to_string(), "0.00001");
+ /// ```
+ pub fn set_scale(&mut self, scale: u32) -> Result<(), Error> {
+ if scale > MAX_PRECISION {
+ return Err(Error::new("Scale exceeds maximum precision"));
+ }
+ self.flags = (scale << SCALE_SHIFT) | (self.flags & SIGN_MASK);
+ Ok(())
+ }
+
+ /// Modifies the `Decimal` to the given scale, attempting to do so without changing the
+ /// underlying number itself.
+ ///
+ /// Note that setting the scale to something less then the current `Decimal`s scale will
+ /// cause the newly created `Decimal` to have some rounding.
+ /// Scales greater than the maximum precision supported by `Decimal` will be automatically
+ /// rounded to `Decimal::MAX_PRECISION`.
+ /// Rounding leverages the half up strategy.
+ ///
+ /// # Arguments
+ /// * `scale`: The scale to use for the new `Decimal` number.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let mut number = Decimal::new(1_123, 3);
+ /// number.rescale(6);
+ /// assert_eq!(number, Decimal::new(1_123_000, 6));
+ /// let mut round = Decimal::new(145, 2);
+ /// round.rescale(1);
+ /// assert_eq!(round, Decimal::new(15, 1));
+ /// ```
+ pub fn rescale(&mut self, scale: u32) {
+ let mut array = [self.lo, self.mid, self.hi];
+ let mut value_scale = self.scale();
+ rescale_internal(&mut array, &mut value_scale, scale);
+ self.lo = array[0];
+ self.mid = array[1];
+ self.hi = array[2];
+ self.flags = flags(self.is_sign_negative(), value_scale);
+ }
+
+ /// Returns a serialized version of the decimal number.
+ /// The resulting byte array will have the following representation:
+ ///
+ /// * Bytes 1-4: flags
+ /// * Bytes 5-8: lo portion of `m`
+ /// * Bytes 9-12: mid portion of `m`
+ /// * Bytes 13-16: high portion of `m`
+ pub const fn serialize(&self) -> [u8; 16] {
+ [
+ (self.flags & U8_MASK) as u8,
+ ((self.flags >> 8) & U8_MASK) as u8,
+ ((self.flags >> 16) & U8_MASK) as u8,
+ ((self.flags >> 24) & U8_MASK) as u8,
+ (self.lo & U8_MASK) as u8,
+ ((self.lo >> 8) & U8_MASK) as u8,
+ ((self.lo >> 16) & U8_MASK) as u8,
+ ((self.lo >> 24) & U8_MASK) as u8,
+ (self.mid & U8_MASK) as u8,
+ ((self.mid >> 8) & U8_MASK) as u8,
+ ((self.mid >> 16) & U8_MASK) as u8,
+ ((self.mid >> 24) & U8_MASK) as u8,
+ (self.hi & U8_MASK) as u8,
+ ((self.hi >> 8) & U8_MASK) as u8,
+ ((self.hi >> 16) & U8_MASK) as u8,
+ ((self.hi >> 24) & U8_MASK) as u8,
+ ]
+ }
+
+ /// Deserializes the given bytes into a decimal number.
+ /// The deserialized byte representation must be 16 bytes and adhere to the followign convention:
+ ///
+ /// * Bytes 1-4: flags
+ /// * Bytes 5-8: lo portion of `m`
+ /// * Bytes 9-12: mid portion of `m`
+ /// * Bytes 13-16: high portion of `m`
+ pub const fn deserialize(bytes: [u8; 16]) -> Decimal {
+ Decimal {
+ flags: (bytes[0] as u32) | (bytes[1] as u32) << 8 | (bytes[2] as u32) << 16 | (bytes[3] as u32) << 24,
+ lo: (bytes[4] as u32) | (bytes[5] as u32) << 8 | (bytes[6] as u32) << 16 | (bytes[7] as u32) << 24,
+ mid: (bytes[8] as u32) | (bytes[9] as u32) << 8 | (bytes[10] as u32) << 16 | (bytes[11] as u32) << 24,
+ hi: (bytes[12] as u32) | (bytes[13] as u32) << 8 | (bytes[14] as u32) << 16 | (bytes[15] as u32) << 24,
+ }
+ }
+
+ /// Returns `true` if the decimal is negative.
+ #[deprecated(since = "0.6.3", note = "please use `is_sign_negative` instead")]
+ pub fn is_negative(&self) -> bool {
+ self.is_sign_negative()
+ }
+
+ /// Returns `true` if the decimal is positive.
+ #[deprecated(since = "0.6.3", note = "please use `is_sign_positive` instead")]
+ pub fn is_positive(&self) -> bool {
+ self.is_sign_positive()
+ }
+
+ /// Returns `true` if the sign bit of the decimal is negative.
+ #[inline(always)]
+ pub const fn is_sign_negative(&self) -> bool {
+ self.flags & SIGN_MASK > 0
+ }
+
+ /// Returns `true` if the sign bit of the decimal is positive.
+ #[inline(always)]
+ pub const fn is_sign_positive(&self) -> bool {
+ self.flags & SIGN_MASK == 0
+ }
+
+ /// Returns the minimum possible number that `Decimal` can represent.
+ pub const fn min_value() -> Decimal {
+ MIN
+ }
+
+ /// Returns the maximum possible number that `Decimal` can represent.
+ pub const fn max_value() -> Decimal {
+ MAX
+ }
+
+ /// Returns a new `Decimal` integral with no fractional portion.
+ /// This is a true truncation whereby no rounding is performed.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let pi = Decimal::new(3141, 3);
+ /// let trunc = Decimal::new(3, 0);
+ /// // note that it returns a decimal
+ /// assert_eq!(pi.trunc(), trunc);
+ /// ```
+ pub fn trunc(&self) -> Decimal {
+ let mut scale = self.scale();
+ if scale == 0 {
+ // Nothing to do
+ return *self;
+ }
+ let mut working = [self.lo, self.mid, self.hi];
+ while scale > 0 {
+ // We're removing precision, so we don't care about overflow
+ if scale < 10 {
+ div_by_u32(&mut working, POWERS_10[scale as usize]);
+ break;
+ } else {
+ div_by_u32(&mut working, POWERS_10[9]);
+ // Only 9 as this array starts with 1
+ scale -= 9;
+ }
+ }
+ Decimal {
+ lo: working[0],
+ mid: working[1],
+ hi: working[2],
+ flags: flags(self.is_sign_negative(), 0),
+ }
+ }
+
+ /// Returns a new `Decimal` representing the fractional portion of the number.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let pi = Decimal::new(3141, 3);
+ /// let fract = Decimal::new(141, 3);
+ /// // note that it returns a decimal
+ /// assert_eq!(pi.fract(), fract);
+ /// ```
+ pub fn fract(&self) -> Decimal {
+ // This is essentially the original number minus the integral.
+ // Could possibly be optimized in the future
+ *self - self.trunc()
+ }
+
+ /// Computes the absolute value of `self`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let num = Decimal::new(-3141, 3);
+ /// assert_eq!(num.abs().to_string(), "3.141");
+ /// ```
+ pub fn abs(&self) -> Decimal {
+ let mut me = *self;
+ me.set_sign_positive(true);
+ me
+ }
+
+ /// Returns the largest integer less than or equal to a number.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let num = Decimal::new(3641, 3);
+ /// assert_eq!(num.floor().to_string(), "3");
+ /// ```
+ pub fn floor(&self) -> Decimal {
+ let scale = self.scale();
+ if scale == 0 {
+ // Nothing to do
+ return *self;
+ }
+
+ // Opportunity for optimization here
+ let floored = self.trunc();
+ if self.is_sign_negative() && !self.fract().is_zero() {
+ floored - Decimal::one()
+ } else {
+ floored
+ }
+ }
+
+ /// Returns the smallest integer greater than or equal to a number.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let num = Decimal::new(3141, 3);
+ /// assert_eq!(num.ceil().to_string(), "4");
+ /// let num = Decimal::new(3, 0);
+ /// assert_eq!(num.ceil().to_string(), "3");
+ /// ```
+ pub fn ceil(&self) -> Decimal {
+ let scale = self.scale();
+ if scale == 0 {
+ // Nothing to do
+ return *self;
+ }
+
+ // Opportunity for optimization here
+ if self.is_sign_positive() && !self.fract().is_zero() {
+ self.trunc() + Decimal::one()
+ } else {
+ self.trunc()
+ }
+ }
+
+ /// Returns the maximum of the two numbers.
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let x = Decimal::new(1, 0);
+ /// let y = Decimal::new(2, 0);
+ /// assert_eq!(y, x.max(y));
+ /// ```
+ pub fn max(self, other: Decimal) -> Decimal {
+ if self < other {
+ return other;
+ } else {
+ self
+ }
+ }
+
+ /// Returns the minimum of the two numbers.
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let x = Decimal::new(1, 0);
+ /// let y = Decimal::new(2, 0);
+ /// assert_eq!(x, x.min(y));
+ /// ```
+ pub fn min(self, other: Decimal) -> Decimal {
+ if self > other {
+ return other;
+ } else {
+ self
+ }
+ }
+
+ /// Strips any trailing zero's from a `Decimal` and converts -0 to 0.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// let number = Decimal::new(3100, 3);
+ /// // note that it returns a decimal, without the extra scale
+ /// assert_eq!(number.normalize().to_string(), "3.1");
+ /// ```
+ pub fn normalize(&self) -> Decimal {
+ if self.is_zero() {
+ // Convert -0, -0.0*, or 0.0* to 0.
+ return Decimal::zero();
+ }
+
+ let mut scale = self.scale();
+ if scale == 0 {
+ // Nothing to do
+ return *self;
+ }
+
+ let mut result = [self.lo, self.mid, self.hi];
+ let mut working = [self.lo, self.mid, self.hi];
+ while scale > 0 {
+ if div_by_u32(&mut working, 10) > 0 {
+ break;
+ }
+ scale -= 1;
+ result.copy_from_slice(&working);
+ }
+ Decimal {
+ lo: result[0],
+ mid: result[1],
+ hi: result[2],
+ flags: flags(self.is_sign_negative(), scale),
+ }
+ }
+
+ /// Returns a new `Decimal` number with no fractional portion (i.e. an integer).
+ /// Rounding currently follows "Bankers Rounding" rules. e.g. 6.5 -> 6, 7.5 -> 8
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ ///
+ /// // Demonstrating bankers rounding...
+ /// let number_down = Decimal::new(65, 1);
+ /// let number_up = Decimal::new(75, 1);
+ /// assert_eq!(number_down.round().to_string(), "6");
+ /// assert_eq!(number_up.round().to_string(), "8");
+ /// ```
+ pub fn round(&self) -> Decimal {
+ self.round_dp(0)
+ }
+
+ /// Returns a new `Decimal` number with the specified number of decimal points for fractional
+ /// portion.
+ /// Rounding is performed using the provided [`RoundingStrategy`]
+ ///
+ /// # Arguments
+ /// * `dp`: the number of decimal points to round to.
+ /// * `strategy`: the [`RoundingStrategy`] to use.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::{Decimal, RoundingStrategy};
+ /// use std::str::FromStr;
+ ///
+ /// let tax = Decimal::from_str("3.4395").unwrap();
+ /// assert_eq!(tax.round_dp_with_strategy(2, RoundingStrategy::RoundHalfUp).to_string(), "3.44");
+ /// ```
+ pub fn round_dp_with_strategy(&self, dp: u32, strategy: RoundingStrategy) -> Decimal {
+ // Short circuit for zero
+ if self.is_zero() {
+ return Decimal {
+ lo: 0,
+ mid: 0,
+ hi: 0,
+ flags: flags(self.is_sign_negative(), dp),
+ };
+ }
+
+ let old_scale = self.scale();
+
+ // return early if decimal has a smaller number of fractional places than dp
+ // e.g. 2.51 rounded to 3 decimal places is 2.51
+ if old_scale <= dp {
+ return *self;
+ }
+
+ let mut value = [self.lo, self.mid, self.hi];
+ let mut value_scale = self.scale();
+ let negative = self.is_sign_negative();
+
+ value_scale -= dp;
+
+ // Rescale to zero so it's easier to work with
+ while value_scale > 0 {
+ if value_scale < 10 {
+ div_by_u32(&mut value, POWERS_10[value_scale as usize]);
+ value_scale = 0;
+ } else {
+ div_by_u32(&mut value, POWERS_10[9]);
+ value_scale -= 9;
+ }
+ }
+
+ // Do some midpoint rounding checks
+ // We're actually doing two things here.
+ // 1. Figuring out midpoint rounding when we're right on the boundary. e.g. 2.50000
+ // 2. Figuring out whether to add one or not e.g. 2.51
+ // For this, we need to figure out the fractional portion that is additional to
+ // the rounded number. e.g. for 0.12345 rounding to 2dp we'd want 345.
+ // We're doing the equivalent of losing precision (e.g. to get 0.12)
+ // then increasing the precision back up to 0.12000
+ let mut offset = [self.lo, self.mid, self.hi];
+ let mut diff = old_scale - dp;
+
+ while diff > 0 {
+ if diff < 10 {
+ div_by_u32(&mut offset, POWERS_10[diff as usize]);
+ break;
+ } else {
+ div_by_u32(&mut offset, POWERS_10[9]);
+ // Only 9 as this array starts with 1
+ diff -= 9;
+ }
+ }
+
+ let mut diff = old_scale - dp;
+
+ while diff > 0 {
+ if diff < 10 {
+ mul_by_u32(&mut offset, POWERS_10[diff as usize]);
+ break;
+ } else {
+ mul_by_u32(&mut offset, POWERS_10[9]);
+ // Only 9 as this array starts with 1
+ diff -= 9;
+ }
+ }
+
+ let mut decimal_portion = [self.lo, self.mid, self.hi];
+ sub_internal(&mut decimal_portion, &offset);
+
+ // If the decimal_portion is zero then we round based on the other data
+ let mut cap = [5, 0, 0];
+ for _ in 0..(old_scale - dp - 1) {
+ mul_by_u32(&mut cap, 10);
+ }
+ let order = cmp_internal(&decimal_portion, &cap);
+
+ match strategy {
+ RoundingStrategy::BankersRounding => {
+ match order {
+ Ordering::Equal => {
+ if (value[0] & 1) == 1 {
+ add_internal(&mut value, &ONE_INTERNAL_REPR);
+ }
+ }
+ Ordering::Greater => {
+ // Doesn't matter about the decimal portion
+ add_internal(&mut value, &ONE_INTERNAL_REPR);
+ }
+ _ => {}
+ }
+ }
+ RoundingStrategy::RoundHalfDown => {
+ if let Ordering::Greater = order {
+ add_internal(&mut value, &ONE_INTERNAL_REPR);
+ }
+ }
+ RoundingStrategy::RoundHalfUp => {
+ // when Ordering::Equal, decimal_portion is 0.5 exactly
+ // when Ordering::Greater, decimal_portion is > 0.5
+ match order {
+ Ordering::Equal => {
+ add_internal(&mut value, &ONE_INTERNAL_REPR);
+ }
+ Ordering::Greater => {
+ // Doesn't matter about the decimal portion
+ add_internal(&mut value, &ONE_INTERNAL_REPR);
+ }
+ _ => {}
+ }
+ }
+ RoundingStrategy::RoundUp => {
+ if !is_all_zero(&decimal_portion) {
+ add_internal(&mut value, &ONE_INTERNAL_REPR);
+ }
+ }
+ RoundingStrategy::RoundDown => (),
+ }
+
+ Decimal {
+ lo: value[0],
+ mid: value[1],
+ hi: value[2],
+ flags: flags(negative, dp),
+ }
+ }
+
+ /// Returns a new `Decimal` number with the specified number of decimal points for fractional portion.
+ /// Rounding currently follows "Bankers Rounding" rules. e.g. 6.5 -> 6, 7.5 -> 8
+ ///
+ /// # Arguments
+ /// * `dp`: the number of decimal points to round to.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ /// use std::str::FromStr;
+ ///
+ /// let pi = Decimal::from_str("3.1415926535897932384626433832").unwrap();
+ /// assert_eq!(pi.round_dp(2).to_string(), "3.14");
+ /// ```
+ pub fn round_dp(&self, dp: u32) -> Decimal {
+ self.round_dp_with_strategy(dp, RoundingStrategy::BankersRounding)
+ }
+
+ /// Convert `Decimal` to an internal representation of the underlying struct. This is useful
+ /// for debugging the internal state of the object.
+ ///
+ /// # Important Disclaimer
+ /// This is primarily intended for library maintainers. The internal representation of a
+ /// `Decimal` is considered "unstable" for public use.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ /// use std::str::FromStr;
+ ///
+ /// let pi = Decimal::from_str("3.1415926535897932384626433832").unwrap();
+ /// assert_eq!(format!("{:?}", pi), "3.1415926535897932384626433832");
+ /// assert_eq!(format!("{:?}", pi.unpack()), "UnpackedDecimal { \
+ /// is_negative: false, scale: 28, hi: 1703060790, mid: 185874565, lo: 1102470952 \
+ /// }");
+ /// ```
+ pub const fn unpack(&self) -> UnpackedDecimal {
+ UnpackedDecimal {
+ is_negative: self.is_sign_negative(),
+ scale: self.scale(),
+ hi: self.hi,
+ lo: self.lo,
+ mid: self.mid,
+ }
+ }
+
+ /// Convert `Decimal` to an internal representation of the underlying struct. This is useful
+ /// for debugging the internal state of the object.
+ ///
+ /// # Important Disclaimer
+ /// This is primarily intended for library maintainers. The internal representation of a
+ /// `Decimal` is considered "unstable" for public use.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rust_decimal::Decimal;
+ /// use std::str::FromStr;
+ ///
+ /// let pi = Decimal::from_str("3.1415926535897932384626433832").unwrap();
+ /// assert_eq!(format!("{:?}", pi), "3.1415926535897932384626433832");
+ /// assert_eq!(format!("{:?}", pi.unpack()), "UnpackedDecimal { \
+ /// is_negative: false, scale: 28, hi: 1703060790, mid: 185874565, lo: 1102470952 \
+ /// }");
+ /// ```
+
+ #[inline(always)]
+ pub(crate) fn mantissa_array3(&self) -> [u32; 3] {
+ [self.lo, self.mid, self.hi]
+ }
+
+ #[inline(always)]
+ pub(crate) fn mantissa_array4(&self) -> [u32; 4] {
+ [self.lo, self.mid, self.hi, 0]
+ }
+
+ fn base2_to_decimal(bits: &mut [u32; 3], exponent2: i32, positive: bool, is64: bool) -> Option<Self> {
+ // 2^exponent2 = (10^exponent2)/(5^exponent2)
+ // = (5^-exponent2)*(10^exponent2)
+ let mut exponent5 = -exponent2;
+ let mut exponent10 = exponent2; // Ultimately, we want this for the scale
+
+ while exponent5 > 0 {
+ // Check to see if the mantissa is divisible by 2
+ if bits[0] & 0x1 == 0 {
+ exponent10 += 1;
+ exponent5 -= 1;
+
+ // We can divide by 2 without losing precision
+ let hi_carry = bits[2] & 0x1 == 1;
+ bits[2] >>= 1;
+ let mid_carry = bits[1] & 0x1 == 1;
+ bits[1] = (bits[1] >> 1) | if hi_carry { SIGN_MASK } else { 0 };
+ bits[0] = (bits[0] >> 1) | if mid_carry { SIGN_MASK } else { 0 };
+ } else {
+ // The mantissa is NOT divisible by 2. Therefore the mantissa should
+ // be multiplied by 5, unless the multiplication overflows.
+ exponent5 -= 1;
+
+ let mut temp = [bits[0], bits[1], bits[2]];
+ if mul_by_u32(&mut temp, 5) == 0 {
+ // Multiplication succeeded without overflow, so copy result back
+ bits[0] = temp[0];
+ bits[1] = temp[1];
+ bits[2] = temp[2];
+ } else {
+ // Multiplication by 5 overflows. The mantissa should be divided
+ // by 2, and therefore will lose significant digits.
+ exponent10 += 1;
+
+ // Shift right
+ let hi_carry = bits[2] & 0x1 == 1;
+ bits[2] >>= 1;
+ let mid_carry = bits[1] & 0x1 == 1;
+ bits[1] = (bits[1] >> 1) | if hi_carry { SIGN_MASK } else { 0 };
+ bits[0] = (bits[0] >> 1) | if mid_carry { SIGN_MASK } else { 0 };
+ }
+ }
+ }
+
+ // In order to divide the value by 5, it is best to multiply by 2/10.
+ // Therefore, exponent10 is decremented, and the mantissa should be multiplied by 2
+ while exponent5 < 0 {
+ if bits[2] & SIGN_MASK == 0 {
+ // No far left bit, the mantissa can withstand a shift-left without overflowing
+ exponent10 -= 1;
+ exponent5 += 1;
+ shl_internal(bits, 1, 0);
+ } else {
+ // The mantissa would overflow if shifted. Therefore it should be
+ // directly divided by 5. This will lose significant digits, unless
+ // by chance the mantissa happens to be divisible by 5.
+ exponent5 += 1;
+ div_by_u32(bits, 5);
+ }
+ }
+
+ // At this point, the mantissa has assimilated the exponent5, but
+ // exponent10 might not be suitable for assignment. exponent10 must be
+ // in the range [-MAX_PRECISION..0], so the mantissa must be scaled up or
+ // down appropriately.
+ while exponent10 > 0 {
+ // In order to bring exponent10 down to 0, the mantissa should be
+ // multiplied by 10 to compensate. If the exponent10 is too big, this
+ // will cause the mantissa to overflow.
+ if mul_by_u32(bits, 10) == 0 {
+ exponent10 -= 1;
+ } else {
+ // Overflowed - return?
+ return None;
+ }
+ }
+
+ // In order to bring exponent up to -MAX_PRECISION, the mantissa should
+ // be divided by 10 to compensate. If the exponent10 is too small, this
+ // will cause the mantissa to underflow and become 0.
+ while exponent10 < -(MAX_PRECISION as i32) {
+ let rem10 = div_by_u32(bits, 10);
+ exponent10 += 1;
+ if is_all_zero(bits) {
+ // Underflow, unable to keep dividing
+ exponent10 = 0;
+ } else if rem10 >= 5 {
+ add_internal(bits, &ONE_INTERNAL_REPR);
+ }
+ }
+
+ // This step is required in order to remove excess bits of precision from the
+ // end of the bit representation, down to the precision guaranteed by the
+ // floating point number
+ if is64 {
+ // Guaranteed to about 16 dp
+ while exponent10 < 0 && (bits[2] != 0 || (bits[1] & 0xFFF0_0000) != 0) {
+ let rem10 = div_by_u32(bits, 10);
+ exponent10 += 1;
+ if rem10 >= 5 {
+ add_internal(bits, &ONE_INTERNAL_REPR);
+ }
+ }
+ } else {
+ // Guaranteed to about 7 dp
+ while exponent10 < 0
+ && (bits[2] != 0 || bits[1] != 0 || (bits[2] == 0 && bits[1] == 0 && (bits[0] & 0xFF00_0000) != 0))
+ {
+ let rem10 = div_by_u32(bits, 10);
+ exponent10 += 1;
+ if rem10 >= 5 {
+ add_internal(bits, &ONE_INTERNAL_REPR);
+ }
+ }
+ }
+
+ // Remove multiples of 10 from the representation
+ while exponent10 < 0 {
+ let mut temp = [bits[0], bits[1], bits[2]];
+ let remainder = div_by_u32(&mut temp, 10);
+ if remainder == 0 {
+ exponent10 += 1;
+ bits[0] = temp[0];
+ bits[1] = temp[1];
+ bits[2] = temp[2];
+ } else {
+ break;
+ }
+ }
+
+ Some(Decimal {
+ lo: bits[0],
+ mid: bits[1],
+ hi: bits[2],
+ flags: flags(!positive, -exponent10 as u32),
+ })
+ }
+
+ /// Checked addition. Computes `self + other`, returning `None` if overflow occurred.
+ #[inline(always)]
+ pub fn checked_add(self, other: Decimal) -> Option<Decimal> {
+ // Convert to the same scale
+ let mut my = [self.lo, self.mid, self.hi];
+ let mut my_scale = self.scale();
+ let mut ot = [other.lo, other.mid, other.hi];
+ let mut other_scale = other.scale();
+ rescale_to_maximum_scale(&mut my, &mut my_scale, &mut ot, &mut other_scale);
+ let mut final_scale = my_scale.max(other_scale);
+
+ // Add the items together
+ let my_negative = self.is_sign_negative();
+ let other_negative = other.is_sign_negative();
+ let mut negative = false;
+ let carry;
+ if !(my_negative ^ other_negative) {
+ negative = my_negative;
+ carry = add3_internal(&mut my, &ot);
+ } else {
+ let cmp = cmp_internal(&my, &ot);
+ // -x + y
+ // if x > y then it's negative (i.e. -2 + 1)
+ match cmp {
+ Ordering::Less => {
+ negative = other_negative;
+ sub3_internal(&mut ot, &my);
+ my[0] = ot[0];
+ my[1] = ot[1];
+ my[2] = ot[2];
+ }
+ Ordering::Greater => {
+ negative = my_negative;
+ sub3_internal(&mut my, &ot);
+ }
+ Ordering::Equal => {
+ // -2 + 2
+ my[0] = 0;
+ my[1] = 0;
+ my[2] = 0;
+ }
+ }
+ carry = 0;
+ }
+
+ // If we have a carry we underflowed.
+ // We need to lose some significant digits (if possible)
+ if carry > 0 {
+ if final_scale == 0 {
+ return None;
+ }
+
+ // Copy it over to a temp array for modification
+ let mut temp = [my[0], my[1], my[2], carry];
+ while final_scale > 0 && temp[3] != 0 {
+ div_by_u32(&mut temp, 10);
+ final_scale -= 1;
+ }
+
+ // If we still have a carry bit then we overflowed
+ if temp[3] > 0 {
+ return None;
+ }
+
+ // Copy it back - we're done
+ my[0] = temp[0];
+ my[1] = temp[1];
+ my[2] = temp[2];
+ }
+ Some(Decimal {
+ lo: my[0],
+ mid: my[1],
+ hi: my[2],
+ flags: flags(negative, final_scale),
+ })
+ }
+
+ /// Checked subtraction. Computes `self - other`, returning `None` if overflow occurred.
+ #[inline(always)]
+ pub fn checked_sub(self, other: Decimal) -> Option<Decimal> {
+ let negated_other = Decimal {
+ lo: other.lo,
+ mid: other.mid,
+ hi: other.hi,
+ flags: other.flags ^ SIGN_MASK,
+ };
+ self.checked_add(negated_other)
+ }
+
+ /// Checked multiplication. Computes `self * other`, returning `None` if overflow occurred.
+ #[inline]
+ pub fn checked_mul(self, other: Decimal) -> Option<Decimal> {
+ // Early exit if either is zero
+ if self.is_zero() || other.is_zero() {
+ return Some(Decimal::zero());
+ }
+
+ // We are only resulting in a negative if we have mismatched signs
+ let negative = self.is_sign_negative() ^ other.is_sign_negative();
+
+ // We get the scale of the result by adding the operands. This may be too big, however
+ // we'll correct later
+ let mut final_scale = self.scale() + other.scale();
+
+ // First of all, if ONLY the lo parts of both numbers is filled
+ // then we can simply do a standard 64 bit calculation. It's a minor
+ // optimization however prevents the need for long form multiplication
+ if self.mid == 0 && self.hi == 0 && other.mid == 0 && other.hi == 0 {
+ // Simply multiplication
+ let mut u64_result = u64_to_array(u64::from(self.lo) * u64::from(other.lo));
+
+ // If we're above max precision then this is a very small number
+ if final_scale > MAX_PRECISION {
+ final_scale -= MAX_PRECISION;
+
+ // If the number is above 19 then this will equate to zero.
+ // This is because the max value in 64 bits is 1.84E19
+ if final_scale > 19 {
+ return Some(Decimal::zero());
+ }
+
+ let mut rem_lo = 0;
+ let mut power;
+ if final_scale > 9 {
+ // Since 10^10 doesn't fit into u32, we divide by 10^10/4
+ // and multiply the next divisor by 4.
+ rem_lo = div_by_u32(&mut u64_result, 2_500_000_000);
+ power = POWERS_10[final_scale as usize - 10] << 2;
+ } else {
+ power = POWERS_10[final_scale as usize];
+ }
+
+ // Divide fits in 32 bits
+ let rem_hi = div_by_u32(&mut u64_result, power);
+
+ // Round the result. Since the divisor is a power of 10
+ // we check to see if the remainder is >= 1/2 divisor
+ power >>= 1;
+ if rem_hi >= power && (rem_hi > power || (rem_lo | (u64_result[0] & 0x1)) != 0) {
+ u64_result[0] += 1;
+ }
+
+ final_scale = MAX_PRECISION;
+ }
+ return Some(Decimal {
+ lo: u64_result[0],
+ mid: u64_result[1],
+ hi: 0,
+ flags: flags(negative, final_scale),
+ });
+ }
+
+ // We're using some of the high bits, so we essentially perform
+ // long form multiplication. We compute the 9 partial products
+ // into a 192 bit result array.
+ //
+ // [my-h][my-m][my-l]
+ // x [ot-h][ot-m][ot-l]
+ // --------------------------------------
+ // 1. [r-hi][r-lo] my-l * ot-l [0, 0]
+ // 2. [r-hi][r-lo] my-l * ot-m [0, 1]
+ // 3. [r-hi][r-lo] my-m * ot-l [1, 0]
+ // 4. [r-hi][r-lo] my-m * ot-m [1, 1]
+ // 5. [r-hi][r-lo] my-l * ot-h [0, 2]
+ // 6. [r-hi][r-lo] my-h * ot-l [2, 0]
+ // 7. [r-hi][r-lo] my-m * ot-h [1, 2]
+ // 8. [r-hi][r-lo] my-h * ot-m [2, 1]
+ // 9.[r-hi][r-lo] my-h * ot-h [2, 2]
+ let my = [self.lo, self.mid, self.hi];
+ let ot = [other.lo, other.mid, other.hi];
+ let mut product = [0u32, 0u32, 0u32, 0u32, 0u32, 0u32];
+
+ // We can perform a minor short circuit here. If the
+ // high portions are both 0 then we can skip portions 5-9
+ let to = if my[2] == 0 && ot[2] == 0 { 2 } else { 3 };
+
+ for my_index in 0..to {
+ for ot_index in 0..to {
+ let (mut rlo, mut rhi) = mul_part(my[my_index], ot[ot_index], 0);
+
+ // Get the index for the lo portion of the product
+ for prod in product.iter_mut().skip(my_index + ot_index) {
+ let (res, overflow) = add_part(rlo, *prod);
+ *prod = res;
+
+ // If we have something in rhi from before then promote that
+ if rhi > 0 {
+ // If we overflowed in the last add, add that with rhi
+ if overflow > 0 {
+ let (nlo, nhi) = add_part(rhi, overflow);
+ rlo = nlo;
+ rhi = nhi;
+ } else {
+ rlo = rhi;
+ rhi = 0;
+ }
+ } else if overflow > 0 {
+ rlo = overflow;
+ rhi = 0;
+ } else {
+ break;
+ }
+
+ // If nothing to do next round then break out
+ if rlo == 0 {
+ break;
+ }
+ }
+ }
+ }
+
+ // If our result has used up the high portion of the product
+ // then we either have an overflow or an underflow situation
+ // Overflow will occur if we can't scale it back, whereas underflow
+ // with kick in rounding
+ let mut remainder = 0;
+ while final_scale > 0 && (product[3] != 0 || product[4] != 0 || product[5] != 0) {
+ remainder = div_by_u32(&mut product, 10u32);
+ final_scale -= 1;
+ }
+
+ // Round up the carry if we need to
+ if remainder >= 5 {
+ for part in product.iter_mut() {
+ if remainder == 0 {
+ break;
+ }
+ let digit: u64 = u64::from(*part) + 1;
+ remainder = if digit > 0xFFFF_FFFF { 1 } else { 0 };
+ *part = (digit & 0xFFFF_FFFF) as u32;
+ }
+ }
+
+ // If we're still above max precision then we'll try again to
+ // reduce precision - we may be dealing with a limit of "0"
+ if final_scale > MAX_PRECISION {
+ // We're in an underflow situation
+ // The easiest way to remove precision is to divide off the result
+ while final_scale > MAX_PRECISION && !is_all_zero(&product) {
+ div_by_u32(&mut product, 10);
+ final_scale -= 1;
+ }
+ // If we're still at limit then we can't represent any
+ // siginificant decimal digits and will return an integer only
+ // Can also be invoked while representing 0.
+ if final_scale > MAX_PRECISION {
+ final_scale = 0;
+ }
+ } else if !(product[3] == 0 && product[4] == 0 && product[5] == 0) {
+ // We're in an overflow situation - we're within our precision bounds
+ // but still have bits in overflow
+ return None;
+ }
+
+ Some(Decimal {
+ lo: product[0],
+ mid: product[1],
+ hi: product[2],
+ flags: flags(negative, final_scale),
+ })
+ }
+
+ /// Checked division. Computes `self / other`, returning `None` if `other == 0.0` or the
+ /// division results in overflow.
+ pub fn checked_div(self, other: Decimal) -> Option<Decimal> {
+ match self.div_impl(other) {
+ DivResult::Ok(quot) => Some(quot),
+ DivResult::Overflow => None,
+ DivResult::DivByZero => None,
+ }
+ }
+
+ fn div_impl(self, other: Decimal) -> DivResult {
+ if other.is_zero() {
+ return DivResult::DivByZero;
+ }
+ if self.is_zero() {
+ return DivResult::Ok(Decimal::zero());
+ }
+
+ let dividend = [self.lo, self.mid, self.hi];
+ let divisor = [other.lo, other.mid, other.hi];
+ let mut quotient = [0u32, 0u32, 0u32];
+ let mut quotient_scale: i32 = self.scale() as i32 - other.scale() as i32;
+
+ // We supply an extra overflow word for each of the dividend and the remainder
+ let mut working_quotient = [dividend[0], dividend[1], dividend[2], 0u32];
+ let mut working_remainder = [0u32, 0u32, 0u32, 0u32];
+ let mut working_scale = quotient_scale;
+ let mut remainder_scale = quotient_scale;
+ let mut underflow;
+
+ loop {
+ div_internal(&mut working_quotient, &mut working_remainder, &divisor);
+ underflow = add_with_scale_internal(
+ &mut quotient,
+ &mut quotient_scale,
+ &mut working_quotient,
+ &mut working_scale,
+ );
+
+ // Multiply the remainder by 10
+ let mut overflow = 0;
+ for part in working_remainder.iter_mut() {
+ let (lo, hi) = mul_part(*part, 10, overflow);
+ *part = lo;
+ overflow = hi;
+ }
+ // Copy temp remainder into the temp quotient section
+ working_quotient.copy_from_slice(&working_remainder);
+
+ remainder_scale += 1;
+ working_scale = remainder_scale;
+
+ if underflow || is_all_zero(&working_remainder) {
+ break;
+ }
+ }
+
+ // If we have a really big number try to adjust the scale to 0
+ while quotient_scale < 0 {
+ copy_array_diff_lengths(&mut working_quotient, &quotient);
+ working_quotient[3] = 0;
+ working_remainder.iter_mut().for_each(|x| *x = 0);
+
+ // Mul 10
+ let mut overflow = 0;
+ for part in &mut working_quotient {
+ let (lo, hi) = mul_part(*part, 10, overflow);
+ *part = lo;
+ overflow = hi;
+ }
+ for part in &mut working_remainder {
+ let (lo, hi) = mul_part(*part, 10, overflow);
+ *part = lo;
+ overflow = hi;
+ }
+ if working_quotient[3] == 0 && is_all_zero(&working_remainder) {
+ quotient_scale += 1;
+ quotient[0] = working_quotient[0];
+ quotient[1] = working_quotient[1];
+ quotient[2] = working_quotient[2];
+ } else {
+ // Overflow
+ return DivResult::Overflow;
+ }
+ }
+
+ if quotient_scale > 255 {
+ quotient[0] = 0;
+ quotient[1] = 0;
+ quotient[2] = 0;
+ quotient_scale = 0;
+ }
+
+ let mut quotient_negative = self.is_sign_negative() ^ other.is_sign_negative();
+
+ // Check for underflow
+ let mut final_scale: u32 = quotient_scale as u32;
+ if final_scale > MAX_PRECISION {
+ let mut remainder = 0;
+
+ // Division underflowed. We must remove some significant digits over using
+ // an invalid scale.
+ while final_scale > MAX_PRECISION && !is_all_zero(&quotient) {
+ remainder = div_by_u32(&mut quotient, 10);
+ final_scale -= 1;
+ }
+ if final_scale > MAX_PRECISION {
+ // Result underflowed so set to zero
+ final_scale = 0;
+ quotient_negative = false;
+ } else if remainder >= 5 {
+ for part in &mut quotient {
+ if remainder == 0 {
+ break;
+ }
+ let digit: u64 = u64::from(*part) + 1;
+ remainder = if digit > 0xFFFF_FFFF { 1 } else { 0 };
+ *part = (digit & 0xFFFF_FFFF) as u32;
+ }
+ }
+ }
+
+ DivResult::Ok(Decimal {
+ lo: quotient[0],
+ mid: quotient[1],
+ hi: quotient[2],
+ flags: flags(quotient_negative, final_scale),
+ })
+ }
+
+ /// Checked remainder. Computes `self % other`, returning `None` if `other == 0.0`.
+ pub fn checked_rem(self, other: Decimal) -> Option<Decimal> {
+ if other.is_zero() {
+ return None;
+ }
+ if self.is_zero() {
+ return Some(Decimal::zero());
+ }
+
+ // Rescale so comparable
+ let initial_scale = self.scale();
+ let mut quotient = [self.lo, self.mid, self.hi];
+ let mut quotient_scale = initial_scale;
+ let mut divisor = [other.lo, other.mid, other.hi];
+ let mut divisor_scale = other.scale();
+ rescale_to_maximum_scale(&mut quotient, &mut quotient_scale, &mut divisor, &mut divisor_scale);
+
+ // Working is the remainder + the quotient
+ // We use an aligned array since we'll be using it a lot.
+ let mut working_quotient = [quotient[0], quotient[1], quotient[2], 0u32];
+ let mut working_remainder = [0u32, 0u32, 0u32, 0u32];
+ div_internal(&mut working_quotient, &mut working_remainder, &divisor);
+
+ // Round if necessary. This is for semantic correctness, but could feasibly be removed for
+ // performance improvements.
+ if quotient_scale > initial_scale {
+ let mut working = [
+ working_remainder[0],
+ working_remainder[1],
+ working_remainder[2],
+ working_remainder[3],
+ ];
+ while quotient_scale > initial_scale {
+ if div_by_u32(&mut working, 10) > 0 {
+ break;
+ }
+ quotient_scale -= 1;
+ working_remainder.copy_from_slice(&working);
+ }
+ }
+
+ Some(Decimal {
+ lo: working_remainder[0],
+ mid: working_remainder[1],
+ hi: working_remainder[2],
+ flags: flags(self.is_sign_negative(), quotient_scale),
+ })
+ }
+}
+
+impl Default for Decimal {
+ fn default() -> Self {
+ Self::zero()
+ }
+}
+
+enum DivResult {
+ Ok(Decimal),
+ Overflow,
+ DivByZero,
+}
+
+#[inline]
+const fn flags(neg: bool, scale: u32) -> u32 {
+ (scale << SCALE_SHIFT) | ((neg as u32) << SIGN_SHIFT)
+}
+
+/// Rescales the given decimals to equivalent scales.
+/// It will firstly try to scale both the left and the right side to
+/// the maximum scale of left/right. If it is unable to do that it
+/// will try to reduce the accuracy of the other argument.
+/// e.g. with 1.23 and 2.345 it'll rescale the first arg to 1.230
+#[inline(always)]
+fn rescale_to_maximum_scale(left: &mut [u32; 3], left_scale: &mut u32, right: &mut [u32; 3], right_scale: &mut u32) {
+ if left_scale == right_scale {
+ // Nothing to do
+ return;
+ }
+
+ if is_all_zero(left) {
+ *left_scale = *right_scale;
+ return;
+ } else if is_all_zero(right) {
+ *right_scale = *left_scale;
+ return;
+ }
+
+ if left_scale > right_scale {
+ rescale_internal(right, right_scale, *left_scale);
+ if right_scale != left_scale {
+ rescale_internal(left, left_scale, *right_scale);
+ }
+ } else {
+ rescale_internal(left, left_scale, *right_scale);
+ if right_scale != left_scale {
+ rescale_internal(right, right_scale, *left_scale);
+ }
+ }
+}
+
+/// Rescales the given decimal to new scale.
+/// e.g. with 1.23 and new scale 3 rescale the value to 1.230
+#[inline(always)]
+fn rescale_internal(value: &mut [u32; 3], value_scale: &mut u32, new_scale: u32) {
+ if *value_scale == new_scale {
+ // Nothing to do
+ return;
+ }
+
+ if is_all_zero(value) {
+ *value_scale = new_scale;
+ return;
+ }
+
+ if *value_scale > new_scale {
+ let mut diff = *value_scale - new_scale;
+ // Scaling further isn't possible since we got an overflow
+ // In this case we need to reduce the accuracy of the "side to keep"
+
+ // Now do the necessary rounding
+ let mut remainder = 0;
+ while diff > 0 {
+ if is_all_zero(value) {
+ *value_scale = new_scale;
+ return;
+ }
+
+ diff -= 1;
+
+ // Any remainder is discarded if diff > 0 still (i.e. lost precision)
+ remainder = div_by_10(value);
+ }
+ if remainder >= 5 {
+ for part in value.iter_mut() {
+ let digit = u64::from(*part) + 1u64;
+ remainder = if digit > 0xFFFF_FFFF { 1 } else { 0 };
+ *part = (digit & 0xFFFF_FFFF) as u32;
+ if remainder == 0 {
+ break;
+ }
+ }
+ }
+ *value_scale = new_scale;
+ } else {
+ let mut diff = new_scale - *value_scale;
+ let mut working = [value[0], value[1], value[2]];
+ while diff > 0 && mul_by_10(&mut working) == 0 {
+ value.copy_from_slice(&working);
+ diff -= 1;
+ }
+ *value_scale = new_scale - diff;
+ }
+}
+
+// This method should only be used where copy from slice cannot be
+#[inline]
+fn copy_array_diff_lengths(into: &mut [u32], from: &[u32]) {
+ for i in 0..into.len() {
+ if i >= from.len() {
+ break;
+ }
+ into[i] = from[i];
+ }
+}
+
+#[inline]
+fn u64_to_array(value: u64) -> [u32; 2] {
+ [(value & U32_MASK) as u32, (value >> 32 & U32_MASK) as u32]
+}
+
+fn add_internal(value: &mut [u32], by: &[u32]) -> u32 {
+ let mut carry: u64 = 0;
+ let vl = value.len();
+ let bl = by.len();
+ if vl >= bl {
+ let mut sum: u64;
+ for i in 0..bl {
+ sum = u64::from(value[i]) + u64::from(by[i]) + carry;
+ value[i] = (sum & U32_MASK) as u32;
+ carry = sum >> 32;
+ }
+ if vl > bl && carry > 0 {
+ for i in value.iter_mut().skip(bl) {
+ sum = u64::from(*i) + carry;
+ *i = (sum & U32_MASK) as u32;
+ carry = sum >> 32;
+ if carry == 0 {
+ break;
+ }
+ }
+ }
+ } else if vl + 1 == bl {
+ // Overflow, by default, is anything in the high portion of by
+ let mut sum: u64;
+ for i in 0..vl {
+ sum = u64::from(value[i]) + u64::from(by[i]) + carry;
+ value[i] = (sum & U32_MASK) as u32;
+ carry = sum >> 32;
+ }
+ if by[vl] > 0 {
+ carry += u64::from(by[vl]);
+ }
+ } else {
+ panic!("Internal error: add using incompatible length arrays. {} <- {}", vl, bl);
+ }
+ carry as u32
+}
+
+#[inline]
+fn add3_internal(value: &mut [u32; 3], by: &[u32; 3]) -> u32 {
+ let mut carry: u32 = 0;
+ let bl = by.len();
+ for i in 0..bl {
+ let res1 = value[i].overflowing_add(by[i]);
+ let res2 = res1.0.overflowing_add(carry);
+ value[i] = res2.0;
+ carry = (res1.1 | res2.1) as u32;
+ }
+ carry
+}
+
+fn add_with_scale_internal(
+ quotient: &mut [u32; 3],
+ quotient_scale: &mut i32,
+ working_quotient: &mut [u32; 4],
+ working_scale: &mut i32,
+) -> bool {
+ // Add quotient and the working (i.e. quotient = quotient + working)
+ if is_all_zero(quotient) {
+ // Quotient is zero so we can just copy the working quotient in directly
+ // First, make sure they are both 96 bit.
+ while working_quotient[3] != 0 {
+ div_by_u32(working_quotient, 10);
+ *working_scale -= 1;
+ }
+ copy_array_diff_lengths(quotient, working_quotient);
+ *quotient_scale = *working_scale;
+ return false;
+ }
+
+ if is_all_zero(working_quotient) {
+ return false;
+ }
+
+ // We have ensured that our working is not zero so we should do the addition
+
+ // If our two quotients are different then
+ // try to scale down the one with the bigger scale
+ let mut temp3 = [0u32, 0u32, 0u32];
+ let mut temp4 = [0u32, 0u32, 0u32, 0u32];
+ if *quotient_scale != *working_scale {
+ // TODO: Remove necessity for temp (without performance impact)
+ fn div_by_10(target: &mut [u32], temp: &mut [u32], scale: &mut i32, target_scale: i32) {
+ // Copy to the temp array
+ temp.copy_from_slice(target);
+ // divide by 10 until target scale is reached
+ while *scale > target_scale {
+ let remainder = div_by_u32(temp, 10);
+ if remainder == 0 {
+ *scale -= 1;
+ target.copy_from_slice(&temp);
+ } else {
+ break;
+ }
+ }
+ }
+
+ if *quotient_scale < *working_scale {
+ div_by_10(working_quotient, &mut temp4, working_scale, *quotient_scale);
+ } else {
+ div_by_10(quotient, &mut temp3, quotient_scale, *working_scale);
+ }
+ }
+
+ // If our two quotients are still different then
+ // try to scale up the smaller scale
+ if *quotient_scale != *working_scale {
+ // TODO: Remove necessity for temp (without performance impact)
+ fn mul_by_10(target: &mut [u32], temp: &mut [u32], scale: &mut i32, target_scale: i32) {
+ temp.copy_from_slice(target);
+ let mut overflow = 0;
+ // Multiply by 10 until target scale reached or overflow
+ while *scale < target_scale && overflow == 0 {
+ overflow = mul_by_u32(temp, 10);
+ if overflow == 0 {
+ // Still no overflow
+ *scale += 1;
+ target.copy_from_slice(&temp);
+ }
+ }
+ }
+
+ if *quotient_scale > *working_scale {
+ mul_by_10(working_quotient, &mut temp4, working_scale, *quotient_scale);
+ } else {
+ mul_by_10(quotient, &mut temp3, quotient_scale, *working_scale);
+ }
+ }
+
+ // If our two quotients are still different then
+ // try to scale down the one with the bigger scale
+ // (ultimately losing significant digits)
+ if *quotient_scale != *working_scale {
+ // TODO: Remove necessity for temp (without performance impact)
+ fn div_by_10_lossy(target: &mut [u32], temp: &mut [u32], scale: &mut i32, target_scale: i32) {
+ temp.copy_from_slice(target);
+ // divide by 10 until target scale is reached
+ while *scale > target_scale {
+ div_by_u32(temp, 10);
+ *scale -= 1;
+ target.copy_from_slice(&temp);
+ }
+ }
+ if *quotient_scale < *working_scale {
+ div_by_10_lossy(working_quotient, &mut temp4, working_scale, *quotient_scale);
+ } else {
+ div_by_10_lossy(quotient, &mut temp3, quotient_scale, *working_scale);
+ }
+ }
+
+ // If quotient or working are zero we have an underflow condition
+ if is_all_zero(quotient) || is_all_zero(working_quotient) {
+ // Underflow
+ return true;
+ } else {
+ // Both numbers have the same scale and can be added.
+ // We just need to know whether we can fit them in
+ let mut underflow = false;
+ let mut temp = [0u32, 0u32, 0u32];
+ while !underflow {
+ temp.copy_from_slice(quotient);
+
+ // Add the working quotient
+ let overflow = add_internal(&mut temp, working_quotient);
+ if overflow == 0 {
+ // addition was successful
+ quotient.copy_from_slice(&temp);
+ break;
+ } else {
+ // addition overflowed - remove significant digits and try again
+ div_by_u32(quotient, 10);
+ *quotient_scale -= 1;
+ div_by_u32(working_quotient, 10);
+ *working_scale -= 1;
+ // Check for underflow
+ underflow = is_all_zero(quotient) || is_all_zero(working_quotient);
+ }
+ }
+ if underflow {
+ return true;
+ }
+ }
+ false
+}
+
+#[inline]
+fn add_part(left: u32, right: u32) -> (u32, u32) {
+ let added = u64::from(left) + u64::from(right);
+ ((added & U32_MASK) as u32, (added >> 32 & U32_MASK) as u32)
+}
+
+#[inline(always)]
+fn sub3_internal(value: &mut [u32; 3], by: &[u32; 3]) {
+ let mut overflow = 0;
+ let vl = value.len();
+ for i in 0..vl {
+ let part = (0x1_0000_0000u64 + u64::from(value[i])) - (u64::from(by[i]) + overflow);
+ value[i] = part as u32;
+ overflow = 1 - (part >> 32);
+ }
+}
+
+fn sub_internal(value: &mut [u32], by: &[u32]) -> u32 {
+ // The way this works is similar to long subtraction
+ // Let's assume we're working with bytes for simpliciy in an example:
+ // 257 - 8 = 249
+ // 0000_0001 0000_0001 - 0000_0000 0000_1000 = 0000_0000 1111_1001
+ // We start by doing the first byte...
+ // Overflow = 0
+ // Left = 0000_0001 (1)
+ // Right = 0000_1000 (8)
+ // Firstly, we make sure the left and right are scaled up to twice the size
+ // Left = 0000_0000 0000_0001
+ // Right = 0000_0000 0000_1000
+ // We then subtract right from left
+ // Result = Left - Right = 1111_1111 1111_1001
+ // We subtract the overflow, which in this case is 0.
+ // Because left < right (1 < 8) we invert the high part.
+ // Lo = 1111_1001
+ // Hi = 1111_1111 -> 0000_0001
+ // Lo is the field, hi is the overflow.
+ // We do the same for the second byte...
+ // Overflow = 1
+ // Left = 0000_0001
+ // Right = 0000_0000
+ // Result = Left - Right = 0000_0000 0000_0001
+ // We subtract the overflow...
+ // Result = 0000_0000 0000_0001 - 1 = 0
+ // And we invert the high, just because (invert 0 = 0).
+ // So our result is:
+ // 0000_0000 1111_1001
+ let mut overflow = 0;
+ let vl = value.len();
+ let bl = by.len();
+ for i in 0..vl {
+ if i >= bl {
+ break;
+ }
+ let (lo, hi) = sub_part(value[i], by[i], overflow);
+ value[i] = lo;
+ overflow = hi;
+ }
+ overflow
+}
+
+fn sub_part(left: u32, right: u32, overflow: u32) -> (u32, u32) {
+ let part = 0x1_0000_0000u64 + u64::from(left) - (u64::from(right) + u64::from(overflow));
+ let lo = part as u32;
+ let hi = 1 - ((part >> 32) as u32);
+ (lo, hi)
+}
+
+// Returns overflow
+#[inline]
+fn mul_by_10(bits: &mut [u32; 3]) -> u32 {
+ let mut overflow = 0u64;
+ for b in bits.iter_mut() {
+ let result = u64::from(*b) * 10u64 + overflow;
+ let hi = (result >> 32) & U32_MASK;
+ let lo = (result & U32_MASK) as u32;
+ *b = lo;
+ overflow = hi;
+ }
+
+ overflow as u32
+}
+
+// Returns overflow
+pub(crate) fn mul_by_u32(bits: &mut [u32], m: u32) -> u32 {
+ let mut overflow = 0;
+ for b in bits.iter_mut() {
+ let (lo, hi) = mul_part(*b, m, overflow);
+ *b = lo;
+ overflow = hi;
+ }
+ overflow
+}
+
+fn mul_part(left: u32, right: u32, high: u32) -> (u32, u32) {
+ let result = u64::from(left) * u64::from(right) + u64::from(high);
+ let hi = ((result >> 32) & U32_MASK) as u32;
+ let lo = (result & U32_MASK) as u32;
+ (lo, hi)
+}
+
+fn div_internal(quotient: &mut [u32; 4], remainder: &mut [u32; 4], divisor: &[u32; 3]) {
+ // There are a couple of ways to do division on binary numbers:
+ // 1. Using long division
+ // 2. Using the complement method
+ // ref: http://paulmason.me/dividing-binary-numbers-part-2/
+ // The complement method basically keeps trying to subtract the
+ // divisor until it can't anymore and placing the rest in remainder.
+ let mut complement = [
+ divisor[0] ^ 0xFFFF_FFFF,
+ divisor[1] ^ 0xFFFF_FFFF,
+ divisor[2] ^ 0xFFFF_FFFF,
+ 0xFFFF_FFFF,
+ ];
+
+ // Add one onto the complement
+ add_internal(&mut complement, &[1u32]);
+
+ // Make sure the remainder is 0
+ remainder.iter_mut().for_each(|x| *x = 0);
+
+ // If we have nothing in our hi+ block then shift over till we do
+ let mut blocks_to_process = 0;
+ while blocks_to_process < 4 && quotient[3] == 0 {
+ // Shift whole blocks to the "left"
+ shl_internal(quotient, 32, 0);
+
+ // Incremember the counter
+ blocks_to_process += 1;
+ }
+
+ // Let's try and do the addition...
+ let mut block = blocks_to_process << 5;
+ let mut working = [0u32, 0u32, 0u32, 0u32];
+ while block < 128 {
+ // << 1 for quotient AND remainder
+ let carry = shl_internal(quotient, 1, 0);
+ shl_internal(remainder, 1, carry);
+
+ // Copy the remainder of working into sub
+ working.copy_from_slice(remainder);
+
+ // Add the remainder with the complement
+ add_internal(&mut working, &complement);
+
+ // Check for the significant bit - move over to the quotient
+ // as necessary
+ if (working[3] & 0x8000_0000) == 0 {
+ remainder.copy_from_slice(&working);
+ quotient[0] |= 1;
+ }
+
+ // Increment our pointer
+ block += 1;
+ }
+}
+
+// Returns remainder
+pub(crate) fn div_by_u32(bits: &mut [u32], divisor: u32) -> u32 {
+ if divisor == 0 {
+ // Divide by zero
+ panic!("Internal error: divide by zero");
+ } else if divisor == 1 {
+ // dividend remains unchanged
+ 0
+ } else {
+ let mut remainder = 0u32;
+ let divisor = u64::from(divisor);
+ for part in bits.iter_mut().rev() {
+ let temp = (u64::from(remainder) << 32) + u64::from(*part);
+ remainder = (temp % divisor) as u32;
+ *part = (temp / divisor) as u32;
+ }
+
+ remainder
+ }
+}
+
+fn div_by_10(bits: &mut [u32; 3]) -> u32 {
+ let mut remainder = 0u32;
+ let divisor = 10u64;
+ for part in bits.iter_mut().rev() {
+ let temp = (u64::from(remainder) << 32) + u64::from(*part);
+ remainder = (temp % divisor) as u32;
+ *part = (temp / divisor) as u32;
+ }
+
+ remainder
+}
+
+#[inline]
+fn shl_internal(bits: &mut [u32], shift: u32, carry: u32) -> u32 {
+ let mut shift = shift;
+
+ // Whole blocks first
+ while shift >= 32 {
+ // memcpy would be useful here
+ for i in (1..bits.len()).rev() {
+ bits[i] = bits[i - 1];
+ }
+ bits[0] = 0;
+ shift -= 32;
+ }
+
+ // Continue with the rest
+ if shift > 0 {
+ let mut carry = carry;
+ for part in bits.iter_mut() {
+ let b = *part >> (32 - shift);
+ *part = (*part << shift) | carry;
+ carry = b;
+ }
+ carry
+ } else {
+ 0
+ }
+}
+
+#[inline]
+fn cmp_internal(left: &[u32; 3], right: &[u32; 3]) -> Ordering {
+ let left_hi: u32 = left[2];
+ let right_hi: u32 = right[2];
+ let left_lo: u64 = u64::from(left[1]) << 32 | u64::from(left[0]);
+ let right_lo: u64 = u64::from(right[1]) << 32 | u64::from(right[0]);
+ if left_hi < right_hi || (left_hi <= right_hi && left_lo < right_lo) {
+ Ordering::Less
+ } else if left_hi == right_hi && left_lo == right_lo {
+ Ordering::Equal
+ } else {
+ Ordering::Greater
+ }
+}
+
+#[inline]
+pub(crate) fn is_all_zero(bits: &[u32]) -> bool {
+ bits.iter().all(|b| *b == 0)
+}
+
+macro_rules! impl_from {
+ ($T:ty, $from_ty:path) => {
+ impl From<$T> for Decimal {
+ #[inline]
+ fn from(t: $T) -> Decimal {
+ $from_ty(t).unwrap()
+ }
+ }
+ };
+}
+
+impl_from!(isize, FromPrimitive::from_isize);
+impl_from!(i8, FromPrimitive::from_i8);
+impl_from!(i16, FromPrimitive::from_i16);
+impl_from!(i32, FromPrimitive::from_i32);
+impl_from!(i64, FromPrimitive::from_i64);
+impl_from!(usize, FromPrimitive::from_usize);
+impl_from!(u8, FromPrimitive::from_u8);
+impl_from!(u16, FromPrimitive::from_u16);
+impl_from!(u32, FromPrimitive::from_u32);
+impl_from!(u64, FromPrimitive::from_u64);
+
+macro_rules! forward_val_val_binop {
+ (impl $imp:ident for $res:ty, $method:ident) => {
+ impl $imp<$res> for $res {
+ type Output = $res;
+
+ #[inline]
+ fn $method(self, other: $res) -> $res {
+ (&self).$method(&other)
+ }
+ }
+ };
+}
+
+macro_rules! forward_ref_val_binop {
+ (impl $imp:ident for $res:ty, $method:ident) => {
+ impl<'a> $imp<$res> for &'a $res {
+ type Output = $res;
+
+ #[inline]
+ fn $method(self, other: $res) -> $res {
+ self.$method(&other)
+ }
+ }
+ };
+}
+
+macro_rules! forward_val_ref_binop {
+ (impl $imp:ident for $res:ty, $method:ident) => {
+ impl<'a> $imp<&'a $res> for $res {
+ type Output = $res;
+
+ #[inline]
+ fn $method(self, other: &$res) -> $res {
+ (&self).$method(other)
+ }
+ }
+ };
+}
+
+macro_rules! forward_all_binop {
+ (impl $imp:ident for $res:ty, $method:ident) => {
+ forward_val_val_binop!(impl $imp for $res, $method);
+ forward_ref_val_binop!(impl $imp for $res, $method);
+ forward_val_ref_binop!(impl $imp for $res, $method);
+ };
+}
+
+impl Zero for Decimal {
+ fn zero() -> Decimal {
+ Decimal {
+ flags: 0,
+ hi: 0,
+ lo: 0,
+ mid: 0,
+ }
+ }
+
+ fn is_zero(&self) -> bool {
+ self.lo.is_zero() && self.mid.is_zero() && self.hi.is_zero()
+ }
+}
+
+impl One for Decimal {
+ fn one() -> Decimal {
+ Decimal {
+ flags: 0,
+ hi: 0,
+ lo: 1,
+ mid: 0,
+ }
+ }
+}
+
+impl Signed for Decimal {
+ fn abs(&self) -> Self {
+ self.abs()
+ }
+
+ fn abs_sub(&self, other: &Self) -> Self {
+ if self <= other {
+ Decimal::zero()
+ } else {
+ self.abs()
+ }
+ }
+
+ fn signum(&self) -> Self {
+ if self.is_zero() {
+ Decimal::zero()
+ } else {
+ let mut value = Decimal::one();
+ if self.is_sign_negative() {
+ value.set_sign_negative(true);
+ }
+ value
+ }
+ }
+
+ fn is_positive(&self) -> bool {
+ self.is_sign_positive()
+ }
+
+ fn is_negative(&self) -> bool {
+ self.is_sign_negative()
+ }
+}
+
+impl Num for Decimal {
+ type FromStrRadixErr = Error;
+
+ fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
+ if str.is_empty() {
+ return Err(Error::new("Invalid decimal: empty"));
+ }
+ if radix < 2 {
+ return Err(Error::new("Unsupported radix < 2"));
+ }
+ if radix > 36 {
+ // As per trait documentation
+ return Err(Error::new("Unsupported radix > 36"));
+ }
+
+ let mut offset = 0;
+ let mut len = str.len();
+ let bytes: Vec<u8> = str.bytes().collect();
+ let mut negative = false; // assume positive
+
+ // handle the sign
+ if bytes[offset] == b'-' {
+ negative = true; // leading minus means negative
+ offset += 1;
+ len -= 1;
+ } else if bytes[offset] == b'+' {
+ // leading + allowed
+ offset += 1;
+ len -= 1;
+ }
+
+ // should now be at numeric part of the significand
+ let mut digits_before_dot: i32 = -1; // digits before '.', -1 if no '.'
+ let mut coeff = Vec::new(); // integer significand array
+
+ // Supporting different radix
+ let (max_n, max_alpha_lower, max_alpha_upper) = if radix <= 10 {
+ (b'0' + (radix - 1) as u8, 0, 0)
+ } else {
+ let adj = (radix - 11) as u8;
+ (b'9', adj + b'a', adj + b'A')
+ };
+
+ // Estimate the max precision. All in all, it needs to fit into 96 bits.
+ // Rather than try to estimate, I've included the constants directly in here. We could,
+ // perhaps, replace this with a formula if it's faster - though it does appear to be log2.
+ let estimated_max_precision = match radix {
+ 2 => 96,
+ 3 => 61,
+ 4 => 48,
+ 5 => 42,
+ 6 => 38,
+ 7 => 35,
+ 8 => 32,
+ 9 => 31,
+ 10 => 29,
+ 11 => 28,
+ 12 => 27,
+ 13 => 26,
+ 14 => 26,
+ 15 => 25,
+ 16 => 24,
+ 17 => 24,
+ 18 => 24,
+ 19 => 23,
+ 20 => 23,
+ 21 => 22,
+ 22 => 22,
+ 23 => 22,
+ 24 => 21,
+ 25 => 21,
+ 26 => 21,
+ 27 => 21,
+ 28 => 20,
+ 29 => 20,
+ 30 => 20,
+ 31 => 20,
+ 32 => 20,
+ 33 => 20,
+ 34 => 19,
+ 35 => 19,
+ 36 => 19,
+ _ => return Err(Error::new("Unsupported radix")),
+ };
+
+ let mut maybe_round = false;
+ while len > 0 {
+ let b = bytes[offset];
+ match b {
+ b'0'..=b'9' => {
+ if b > max_n {
+ return Err(Error::new("Invalid decimal: invalid character"));
+ }
+ coeff.push(u32::from(b - b'0'));
+ offset += 1;
+ len -= 1;
+
+ // If the coefficient is longer than the max, exit early
+ if coeff.len() as u32 > estimated_max_precision {
+ maybe_round = true;
+ break;
+ }
+ }
+ b'a'..=b'z' => {
+ if b > max_alpha_lower {
+ return Err(Error::new("Invalid decimal: invalid character"));
+ }
+ coeff.push(u32::from(b - b'a') + 10);
+ offset += 1;
+ len -= 1;
+
+ if coeff.len() as u32 > estimated_max_precision {
+ maybe_round = true;
+ break;
+ }
+ }
+ b'A'..=b'Z' => {
+ if b > max_alpha_upper {
+ return Err(Error::new("Invalid decimal: invalid character"));
+ }
+ coeff.push(u32::from(b - b'A') + 10);
+ offset += 1;
+ len -= 1;
+
+ if coeff.len() as u32 > estimated_max_precision {
+ maybe_round = true;
+ break;
+ }
+ }
+ b'.' => {
+ if digits_before_dot >= 0 {
+ return Err(Error::new("Invalid decimal: two decimal points"));
+ }
+ digits_before_dot = coeff.len() as i32;
+ offset += 1;
+ len -= 1;
+ }
+ b'_' => {
+ // Must start with a number...
+ if coeff.is_empty() {
+ return Err(Error::new("Invalid decimal: must start lead with a number"));
+ }
+ offset += 1;
+ len -= 1;
+ }
+ _ => return Err(Error::new("Invalid decimal: unknown character")),
+ }
+ }
+
+ // If we exited before the end of the string then do some rounding if necessary
+ if maybe_round && offset < bytes.len() {
+ let next_byte = bytes[offset];
+ let digit = match next_byte {
+ b'0'..=b'9' => {
+ if next_byte > max_n {
+ return Err(Error::new("Invalid decimal: invalid character"));
+ }
+ u32::from(next_byte - b'0')
+ }
+ b'a'..=b'z' => {
+ if next_byte > max_alpha_lower {
+ return Err(Error::new("Invalid decimal: invalid character"));
+ }
+ u32::from(next_byte - b'a') + 10
+ }
+ b'A'..=b'Z' => {
+ if next_byte > max_alpha_upper {
+ return Err(Error::new("Invalid decimal: invalid character"));
+ }
+ u32::from(next_byte - b'A') + 10
+ }
+ b'_' => 0,
+ b'.' => {
+ // Still an error if we have a second dp
+ if digits_before_dot >= 0 {
+ return Err(Error::new("Invalid decimal: two decimal points"));
+ }
+ 0
+ }
+ _ => return Err(Error::new("Invalid decimal: unknown character")),
+ };
+
+ // Round at midpoint
+ let midpoint = if radix & 0x1 == 1 { radix / 2 } else { radix + 1 / 2 };
+ if digit >= midpoint {
+ let mut index = coeff.len() - 1;
+ loop {
+ let new_digit = coeff[index] + 1;
+ if new_digit <= 9 {
+ coeff[index] = new_digit;
+ break;
+ } else {
+ coeff[index] = 0;
+ if index == 0 {
+ coeff.insert(0, 1u32);
+ digits_before_dot += 1;
+ coeff.pop();
+ break;
+ }
+ }
+ index -= 1;
+ }
+ }
+ }
+
+ // here when no characters left
+ if coeff.is_empty() {
+ return Err(Error::new("Invalid decimal: no digits found"));
+ }
+
+ let mut scale = if digits_before_dot >= 0 {
+ // we had a decimal place so set the scale
+ (coeff.len() as u32) - (digits_before_dot as u32)
+ } else {
+ 0
+ };
+
+ // Parse this using specified radix
+ let mut data = [0u32, 0u32, 0u32];
+ let mut tmp = [0u32, 0u32, 0u32];
+ let len = coeff.len();
+ for (i, digit) in coeff.iter().enumerate() {
+ // If the data is going to overflow then we should go into recovery mode
+ tmp[0] = data[0];
+ tmp[1] = data[1];
+ tmp[2] = data[2];
+ let overflow = mul_by_u32(&mut tmp, radix);
+ if overflow > 0 {
+ // This means that we have more data to process, that we're not sure what to do with.
+ // This may or may not be an issue - depending on whether we're past a decimal point
+ // or not.
+ if (i as i32) < digits_before_dot && i + 1 < len {
+ return Err(Error::new("Invalid decimal: overflow from too many digits"));
+ }
+
+ if *digit >= 5 {
+ let carry = add_internal(&mut data, &ONE_INTERNAL_REPR);
+ if carry > 0 {
+ // Highly unlikely scenario which is more indicative of a bug
+ return Err(Error::new("Invalid decimal: overflow when rounding"));
+ }
+ }
+ // We're also one less digit so reduce the scale
+ let diff = (len - i) as u32;
+ if diff > scale {
+ return Err(Error::new("Invalid decimal: overflow from scale mismatch"));
+ }
+ scale -= diff;
+ break;
+ } else {
+ data[0] = tmp[0];
+ data[1] = tmp[1];
+ data[2] = tmp[2];
+ let carry = add_internal(&mut data, &[*digit]);
+ if carry > 0 {
+ // Highly unlikely scenario which is more indicative of a bug
+ return Err(Error::new("Invalid decimal: overflow from carry"));
+ }
+ }
+ }
+
+ Ok(Decimal {
+ lo: data[0],
+ mid: data[1],
+ hi: data[2],
+ flags: flags(negative, scale),
+ })
+ }
+}
+
+impl FromStr for Decimal {
+ type Err = Error;
+
+ fn from_str(value: &str) -> Result<Decimal, Self::Err> {
+ Decimal::from_str_radix(value, 10)
+ }
+}
+
+impl FromPrimitive for Decimal {
+ fn from_i32(n: i32) -> Option<Decimal> {
+ let flags: u32;
+ let value_copy: i64;
+ if n >= 0 {
+ flags = 0;
+ value_copy = n as i64;
+ } else {
+ flags = SIGN_MASK;
+ value_copy = -(n as i64);
+ }
+ Some(Decimal {
+ flags,
+ lo: value_copy as u32,
+ mid: 0,
+ hi: 0,
+ })
+ }
+
+ fn from_i64(n: i64) -> Option<Decimal> {
+ let flags: u32;
+ let value_copy: i128;
+ if n >= 0 {
+ flags = 0;
+ value_copy = n as i128;
+ } else {
+ flags = SIGN_MASK;
+ value_copy = -(n as i128);
+ }
+ Some(Decimal {
+ flags,
+ lo: value_copy as u32,
+ mid: (value_copy >> 32) as u32,
+ hi: 0,
+ })
+ }
+
+ fn from_u32(n: u32) -> Option<Decimal> {
+ Some(Decimal {
+ flags: 0,
+ lo: n,
+ mid: 0,
+ hi: 0,
+ })
+ }
+
+ fn from_u64(n: u64) -> Option<Decimal> {
+ Some(Decimal {
+ flags: 0,
+ lo: n as u32,
+ mid: (n >> 32) as u32,
+ hi: 0,
+ })
+ }
+
+ fn from_f32(n: f32) -> Option<Decimal> {
+ // Handle the case if it is NaN, Infinity or -Infinity
+ if !n.is_finite() {
+ return None;
+ }
+
+ // It's a shame we can't use a union for this due to it being broken up by bits
+ // i.e. 1/8/23 (sign, exponent, mantissa)
+ // See https://en.wikipedia.org/wiki/IEEE_754-1985
+ // n = (sign*-1) * 2^exp * mantissa
+ // Decimal of course stores this differently... 10^-exp * significand
+ let raw = n.to_bits();
+ let positive = (raw >> 31) == 0;
+ let biased_exponent = ((raw >> 23) & 0xFF) as i32;
+ let mantissa = raw & 0x007F_FFFF;
+
+ // Handle the special zero case
+ if biased_exponent == 0 && mantissa == 0 {
+ let mut zero = Decimal::zero();
+ if !positive {
+ zero.set_sign_negative(true);
+ }
+ return Some(zero);
+ }
+
+ // Get the bits and exponent2
+ let mut exponent2 = biased_exponent - 127;
+ let mut bits = [mantissa, 0u32, 0u32];
+ if biased_exponent == 0 {
+ // Denormalized number - correct the exponent
+ exponent2 += 1;
+ } else {
+ // Add extra hidden bit to mantissa
+ bits[0] |= 0x0080_0000;
+ }
+
+ // The act of copying a mantissa as integer bits is equivalent to shifting
+ // left the mantissa 23 bits. The exponent is reduced to compensate.
+ exponent2 -= 23;
+
+ // Convert to decimal
+ Decimal::base2_to_decimal(&mut bits, exponent2, positive, false)
+ }
+
+ fn from_f64(n: f64) -> Option<Decimal> {
+ // Handle the case if it is NaN, Infinity or -Infinity
+ if !n.is_finite() {
+ return None;
+ }
+
+ // It's a shame we can't use a union for this due to it being broken up by bits
+ // i.e. 1/11/52 (sign, exponent, mantissa)
+ // See https://en.wikipedia.org/wiki/IEEE_754-1985
+ // n = (sign*-1) * 2^exp * mantissa
+ // Decimal of course stores this differently... 10^-exp * significand
+ let raw = n.to_bits();
+ let positive = (raw >> 63) == 0;
+ let biased_exponent = ((raw >> 52) & 0x7FF) as i32;
+ let mantissa = raw & 0x000F_FFFF_FFFF_FFFF;
+
+ // Handle the special zero case
+ if biased_exponent == 0 && mantissa == 0 {
+ let mut zero = Decimal::zero();
+ if !positive {
+ zero.set_sign_negative(true);
+ }
+ return Some(zero);
+ }
+
+ // Get the bits and exponent2
+ let mut exponent2 = biased_exponent - 1023;
+ let mut bits = [
+ (mantissa & 0xFFFF_FFFF) as u32,
+ ((mantissa >> 32) & 0xFFFF_FFFF) as u32,
+ 0u32,
+ ];
+ if biased_exponent == 0 {
+ // Denormalized number - correct the exponent
+ exponent2 += 1;
+ } else {
+ // Add extra hidden bit to mantissa
+ bits[1] |= 0x0010_0000;
+ }
+
+ // The act of copying a mantissa as integer bits is equivalent to shifting
+ // left the mantissa 52 bits. The exponent is reduced to compensate.
+ exponent2 -= 52;
+
+ // Convert to decimal
+ Decimal::base2_to_decimal(&mut bits, exponent2, positive, true)
+ }
+}
+
+impl ToPrimitive for Decimal {
+ fn to_i64(&self) -> Option<i64> {
+ let d = self.trunc();
+ // Quick overflow check
+ if d.hi != 0 || (d.mid & 0x8000_0000) > 0 {
+ // Overflow
+ return None;
+ }
+
+ let raw: i64 = (i64::from(d.mid) << 32) | i64::from(d.lo);
+ if self.is_sign_negative() {
+ Some(-raw)
+ } else {
+ Some(raw)
+ }
+ }
+
+ fn to_u64(&self) -> Option<u64> {
+ if self.is_sign_negative() {
+ return None;
+ }
+
+ let d = self.trunc();
+ if d.hi != 0 {
+ // Overflow
+ return None;
+ }
+
+ Some((u64::from(d.mid) << 32) | u64::from(d.lo))
+ }
+
+ fn to_f64(&self) -> Option<f64> {
+ if self.scale() == 0 {
+ let integer = self.to_i64();
+ match integer {
+ Some(i) => Some(i as f64),
+ None => None,
+ }
+ } else {
+ let sign: f64 = if self.is_sign_negative() { -1.0 } else { 1.0 };
+ let mut mantissa: u128 = self.lo.into();
+ mantissa |= (self.mid as u128) << 32;
+ mantissa |= (self.hi as u128) << 64;
+ // scale is at most 28, so this fits comfortably into a u128.
+ let scale = self.scale();
+ let precision: u128 = 10_u128.pow(scale);
+ let integral_part = mantissa / precision;
+ let frac_part = mantissa % precision;
+ let frac_f64 = (frac_part as f64) / (precision as f64);
+ Some(sign * ((integral_part as f64) + frac_f64))
+ }
+ }
+}
+
+impl fmt::Display for Decimal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ // Get the scale - where we need to put the decimal point
+ let mut scale = self.scale() as usize;
+
+ // Convert to a string and manipulate that (neg at front, inject decimal)
+ let mut chars = Vec::new();
+ let mut working = [self.lo, self.mid, self.hi];
+ while !is_all_zero(&working) {
+ let remainder = div_by_u32(&mut working, 10u32);
+ chars.push(char::from(b'0' + remainder as u8));
+ }
+ while scale > chars.len() {
+ chars.push('0');
+ }
+
+ let mut rep = chars.iter().rev().collect::<String>();
+ let len = rep.len();
+
+ if let Some(n_dp) = f.precision() {
+ if n_dp < scale {
+ rep.truncate(len - scale + n_dp)
+ } else {
+ let zeros = repeat("0").take(n_dp - scale).collect::<String>();
+ rep.push_str(&zeros[..]);
+ }
+ scale = n_dp;
+ }
+ let len = rep.len();
+
+ // Inject the decimal point
+ if scale > 0 {
+ // Must be a low fractional
+ // TODO: Remove this condition as it's no longer possible for `scale > len`
+ if scale > len {
+ let mut new_rep = String::new();
+ let zeros = repeat("0").take(scale as usize - len).collect::<String>();
+ new_rep.push_str("0.");
+ new_rep.push_str(&zeros[..]);
+ new_rep.push_str(&rep[..]);
+ rep = new_rep;
+ } else if scale == len {
+ rep.insert(0, '.');
+ rep.insert(0, '0');
+ } else {
+ rep.insert(len - scale as usize, '.');
+ }
+ } else if rep.is_empty() {
+ // corner case for when we truncated everything in a low fractional
+ rep.insert(0, '0');
+ }
+
+ f.pad_integral(self.is_sign_positive(), "", &rep)
+ }
+}
+
+impl fmt::Debug for Decimal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl Neg for Decimal {
+ type Output = Decimal;
+
+ fn neg(self) -> Decimal {
+ -&self
+ }
+}
+
+impl<'a> Neg for &'a Decimal {
+ type Output = Decimal;
+
+ fn neg(self) -> Decimal {
+ Decimal {
+ flags: flags(!self.is_sign_negative(), self.scale()),
+ hi: self.hi,
+ lo: self.lo,
+ mid: self.mid,
+ }
+ }
+}
+
+forward_all_binop!(impl Add for Decimal, add);
+
+impl<'a, 'b> Add<&'b Decimal> for &'a Decimal {
+ type Output = Decimal;
+
+ #[inline(always)]
+ fn add(self, other: &Decimal) -> Decimal {
+ match self.checked_add(*other) {
+ Some(sum) => sum,
+ None => panic!("Addition overflowed"),
+ }
+ }
+}
+
+impl AddAssign for Decimal {
+ fn add_assign(&mut self, other: Decimal) {
+ let result = self.add(other);
+ self.lo = result.lo;
+ self.mid = result.mid;
+ self.hi = result.hi;
+ self.flags = result.flags;
+ }
+}
+
+impl<'a> AddAssign<&'a Decimal> for Decimal {
+ fn add_assign(&mut self, other: &'a Decimal) {
+ Decimal::add_assign(self, *other)
+ }
+}
+
+impl<'a> AddAssign<Decimal> for &'a mut Decimal {
+ fn add_assign(&mut self, other: Decimal) {
+ Decimal::add_assign(*self, other)
+ }
+}
+
+impl<'a> AddAssign<&'a Decimal> for &'a mut Decimal {
+ fn add_assign(&mut self, other: &'a Decimal) {
+ Decimal::add_assign(*self, *other)
+ }
+}
+
+forward_all_binop!(impl Sub for Decimal, sub);
+
+impl<'a, 'b> Sub<&'b Decimal> for &'a Decimal {
+ type Output = Decimal;
+
+ #[inline(always)]
+ fn sub(self, other: &Decimal) -> Decimal {
+ match self.checked_sub(*other) {
+ Some(diff) => diff,
+ None => panic!("Subtraction overflowed"),
+ }
+ }
+}
+
+impl SubAssign for Decimal {
+ fn sub_assign(&mut self, other: Decimal) {
+ let result = self.sub(other);
+ self.lo = result.lo;
+ self.mid = result.mid;
+ self.hi = result.hi;
+ self.flags = result.flags;
+ }
+}
+
+impl<'a> SubAssign<&'a Decimal> for Decimal {
+ fn sub_assign(&mut self, other: &'a Decimal) {
+ Decimal::sub_assign(self, *other)
+ }
+}
+
+impl<'a> SubAssign<Decimal> for &'a mut Decimal {
+ fn sub_assign(&mut self, other: Decimal) {
+ Decimal::sub_assign(*self, other)
+ }
+}
+
+impl<'a> SubAssign<&'a Decimal> for &'a mut Decimal {
+ fn sub_assign(&mut self, other: &'a Decimal) {
+ Decimal::sub_assign(*self, *other)
+ }
+}
+
+forward_all_binop!(impl Mul for Decimal, mul);
+
+impl<'a, 'b> Mul<&'b Decimal> for &'a Decimal {
+ type Output = Decimal;
+
+ #[inline]
+ fn mul(self, other: &Decimal) -> Decimal {
+ match self.checked_mul(*other) {
+ Some(prod) => prod,
+ None => panic!("Multiplication overflowed"),
+ }
+ }
+}
+
+impl MulAssign for Decimal {
+ fn mul_assign(&mut self, other: Decimal) {
+ let result = self.mul(other);
+ self.lo = result.lo;
+ self.mid = result.mid;
+ self.hi = result.hi;
+ self.flags = result.flags;
+ }
+}
+
+impl<'a> MulAssign<&'a Decimal> for Decimal {
+ fn mul_assign(&mut self, other: &'a Decimal) {
+ Decimal::mul_assign(self, *other)
+ }
+}
+
+impl<'a> MulAssign<Decimal> for &'a mut Decimal {
+ fn mul_assign(&mut self, other: Decimal) {
+ Decimal::mul_assign(*self, other)
+ }
+}
+
+impl<'a> MulAssign<&'a Decimal> for &'a mut Decimal {
+ fn mul_assign(&mut self, other: &'a Decimal) {
+ Decimal::mul_assign(*self, *other)
+ }
+}
+
+forward_all_binop!(impl Div for Decimal, div);
+
+impl<'a, 'b> Div<&'b Decimal> for &'a Decimal {
+ type Output = Decimal;
+
+ fn div(self, other: &Decimal) -> Decimal {
+ match self.div_impl(*other) {
+ DivResult::Ok(quot) => quot,
+ DivResult::Overflow => panic!("Division overflowed"),
+ DivResult::DivByZero => panic!("Division by zero"),
+ }
+ }
+}
+
+impl DivAssign for Decimal {
+ fn div_assign(&mut self, other: Decimal) {
+ let result = self.div(other);
+ self.lo = result.lo;
+ self.mid = result.mid;
+ self.hi = result.hi;
+ self.flags = result.flags;
+ }
+}
+
+impl<'a> DivAssign<&'a Decimal> for Decimal {
+ fn div_assign(&mut self, other: &'a Decimal) {
+ Decimal::div_assign(self, *other)
+ }
+}
+
+impl<'a> DivAssign<Decimal> for &'a mut Decimal {
+ fn div_assign(&mut self, other: Decimal) {
+ Decimal::div_assign(*self, other)
+ }
+}
+
+impl<'a> DivAssign<&'a Decimal> for &'a mut Decimal {
+ fn div_assign(&mut self, other: &'a Decimal) {
+ Decimal::div_assign(*self, *other)
+ }
+}
+
+forward_all_binop!(impl Rem for Decimal, rem);
+
+impl<'a, 'b> Rem<&'b Decimal> for &'a Decimal {
+ type Output = Decimal;
+
+ #[inline]
+ fn rem(self, other: &Decimal) -> Decimal {
+ match self.checked_rem(*other) {
+ Some(rem) => rem,
+ None => panic!("Division by zero"),
+ }
+ }
+}
+
+impl RemAssign for Decimal {
+ fn rem_assign(&mut self, other: Decimal) {
+ let result = self.rem(other);
+ self.lo = result.lo;
+ self.mid = result.mid;
+ self.hi = result.hi;
+ self.flags = result.flags;
+ }
+}
+
+impl<'a> RemAssign<&'a Decimal> for Decimal {
+ fn rem_assign(&mut self, other: &'a Decimal) {
+ Decimal::rem_assign(self, *other)
+ }
+}
+
+impl<'a> RemAssign<Decimal> for &'a mut Decimal {
+ fn rem_assign(&mut self, other: Decimal) {
+ Decimal::rem_assign(*self, other)
+ }
+}
+
+impl<'a> RemAssign<&'a Decimal> for &'a mut Decimal {
+ fn rem_assign(&mut self, other: &'a Decimal) {
+ Decimal::rem_assign(*self, *other)
+ }
+}
+
+impl PartialEq for Decimal {
+ #[inline]
+ fn eq(&self, other: &Decimal) -> bool {
+ self.cmp(other) == Equal
+ }
+}
+
+impl Eq for Decimal {}
+
+impl Hash for Decimal {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ let n = self.normalize();
+ n.lo.hash(state);
+ n.mid.hash(state);
+ n.hi.hash(state);
+ n.flags.hash(state);
+ }
+}
+
+impl PartialOrd for Decimal {
+ #[inline]
+ fn partial_cmp(&self, other: &Decimal) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Decimal {
+ fn cmp(&self, other: &Decimal) -> Ordering {
+ // Quick exit if major differences
+ let self_negative = self.is_sign_negative();
+ let other_negative = other.is_sign_negative();
+ if self_negative && !other_negative {
+ if self.is_zero() && other.is_zero() {
+ return Ordering::Equal;
+ }
+ return Ordering::Less;
+ } else if !self_negative && other_negative {
+ if self.is_zero() && other.is_zero() {
+ return Ordering::Equal;
+ }
+ return Ordering::Greater;
+ }
+
+ // If we have 1.23 and 1.2345 then we have
+ // 123 scale 2 and 12345 scale 4
+ // We need to convert the first to
+ // 12300 scale 4 so we can compare equally
+ let left: &Decimal;
+ let right: &Decimal;
+ if self_negative && other_negative {
+ // Both are negative, so reverse cmp
+ left = other;
+ right = self;
+ } else {
+ left = self;
+ right = other;
+ }
+ let mut left_scale = left.scale();
+ let mut right_scale = right.scale();
+
+ if left_scale == right_scale {
+ // Fast path for same scale
+ if left.hi != right.hi {
+ return left.hi.cmp(&right.hi);
+ }
+ if left.mid != right.mid {
+ return left.mid.cmp(&right.mid);
+ }
+ return left.lo.cmp(&right.lo);
+ }
+
+ // Rescale and compare
+ let mut left_raw = [left.lo, left.mid, left.hi];
+ let mut right_raw = [right.lo, right.mid, right.hi];
+ rescale_to_maximum_scale(&mut left_raw, &mut left_scale, &mut right_raw, &mut right_scale);
+ cmp_internal(&left_raw, &right_raw)
+ }
+}
+
+impl Sum for Decimal {
+ fn sum<I: Iterator<Item = Decimal>>(iter: I) -> Self {
+ let mut sum = Decimal::zero();
+ for i in iter {
+ sum += i;
+ }
+ sum
+ }
+}
+
+#[cfg(test)]
+mod test {
+ // Tests on private methods.
+ //
+ // All public tests should go under `tests/`.
+
+ use super::*;
+
+ #[test]
+ fn it_can_rescale_to_maximum_scale() {
+ fn extract(value: &str) -> ([u32; 3], u32) {
+ let v = Decimal::from_str(value).unwrap();
+ ([v.lo, v.mid, v.hi], v.scale())
+ }
+
+ let tests = &[
+ ("1", "1", "1", "1"),
+ ("1", "1.0", "1.0", "1.0"),
+ ("1", "1.00000", "1.00000", "1.00000"),
+ ("1", "1.0000000000", "1.0000000000", "1.0000000000"),
+ (
+ "1",
+ "1.00000000000000000000",
+ "1.00000000000000000000",
+ "1.00000000000000000000",
+ ),
+ ("1.1", "1.1", "1.1", "1.1"),
+ ("1.1", "1.10000", "1.10000", "1.10000"),
+ ("1.1", "1.1000000000", "1.1000000000", "1.1000000000"),
+ (
+ "1.1",
+ "1.10000000000000000000",
+ "1.10000000000000000000",
+ "1.10000000000000000000",
+ ),
+ (
+ "0.6386554621848739495798319328",
+ "11.815126050420168067226890757",
+ "0.638655462184873949579831933",
+ "11.815126050420168067226890757",
+ ),
+ (
+ "0.0872727272727272727272727272", // Scale 28
+ "843.65000000", // Scale 8
+ "0.0872727272727272727272727", // 25
+ "843.6500000000000000000000000", // 25
+ ),
+ ];
+
+ for &(left_raw, right_raw, expected_left, expected_right) in tests {
+ // Left = the value to rescale
+ // Right = the new scale we're scaling to
+ // Expected = the expected left value after rescale
+ let (expected_left, expected_lscale) = extract(expected_left);
+ let (expected_right, expected_rscale) = extract(expected_right);
+
+ let (mut left, mut left_scale) = extract(left_raw);
+ let (mut right, mut right_scale) = extract(right_raw);
+ rescale_to_maximum_scale(&mut left, &mut left_scale, &mut right, &mut right_scale);
+ assert_eq!(left, expected_left);
+ assert_eq!(left_scale, expected_lscale);
+ assert_eq!(right, expected_right);
+ assert_eq!(right_scale, expected_rscale);
+
+ // Also test the transitive case
+ let (mut left, mut left_scale) = extract(left_raw);
+ let (mut right, mut right_scale) = extract(right_raw);
+ rescale_to_maximum_scale(&mut right, &mut right_scale, &mut left, &mut left_scale);
+ assert_eq!(left, expected_left);
+ assert_eq!(left_scale, expected_lscale);
+ assert_eq!(right, expected_right);
+ assert_eq!(right_scale, expected_rscale);
+ }
+ }
+
+ #[test]
+ fn it_can_rescale_internal() {
+ fn extract(value: &str) -> ([u32; 3], u32) {
+ let v = Decimal::from_str(value).unwrap();
+ ([v.lo, v.mid, v.hi], v.scale())
+ }
+
+ let tests = &[
+ ("1", 0, "1"),
+ ("1", 1, "1.0"),
+ ("1", 5, "1.00000"),
+ ("1", 10, "1.0000000000"),
+ ("1", 20, "1.00000000000000000000"),
+ ("0.6386554621848739495798319328", 27, "0.638655462184873949579831933"),
+ (
+ "843.65000000", // Scale 8
+ 25, // 25
+ "843.6500000000000000000000000", // 25
+ ),
+ (
+ "843.65000000", // Scale 8
+ 30, // 30
+ "843.6500000000000000000000000000", // 28
+ ),
+ ];
+
+ for &(value_raw, new_scale, expected_value) in tests {
+ let (expected_value, _) = extract(expected_value);
+ let (mut value, mut value_scale) = extract(value_raw);
+ rescale_internal(&mut value, &mut value_scale, new_scale);
+ assert_eq!(value, expected_value);
+ }
+ }
+}
diff --git a/third_party/rust/rust_decimal/src/error.rs b/third_party/rust/rust_decimal/src/error.rs
new file mode 100644
index 0000000000..82bd7f0489
--- /dev/null
+++ b/third_party/rust/rust_decimal/src/error.rs
@@ -0,0 +1,31 @@
+use std::{error, fmt};
+
+/// Error type for the library.
+#[derive(Clone, Debug)]
+pub struct Error {
+ message: String,
+}
+
+impl Error {
+ /// Instantiate an error with the specified error message.
+ ///
+ /// This function is only available within the crate as there should never
+ /// be a need to create this error outside of the library.
+ pub(crate) fn new<S: Into<String>>(message: S) -> Error {
+ Error {
+ message: message.into(),
+ }
+ }
+}
+
+impl error::Error for Error {
+ fn description(&self) -> &str {
+ &self.message
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ f.pad(&self.message)
+ }
+}
diff --git a/third_party/rust/rust_decimal/src/lib.rs b/third_party/rust/rust_decimal/src/lib.rs
new file mode 100644
index 0000000000..cbcd931cd5
--- /dev/null
+++ b/third_party/rust/rust_decimal/src/lib.rs
@@ -0,0 +1,56 @@
+//!
+//! A Decimal implementation written in pure Rust suitable
+//! for financial calculations that require significant integral
+//! and fractional digits with no round-off errors.
+//!
+//! The binary representation consists of a 96 bit integer number,
+//! a scaling factor used to specify the decimal fraction and a 1
+//! bit sign. Because of this representation, trailing zeros are
+//! preserved and may be exposed when in string form. These can be
+//! truncated using the `normalize` or `round_dp` functions.
+//!
+//! ## Usage
+//!
+//! Decimal numbers can be created in a few distinct ways, depending
+//! on the rust compiler version you're targeting.
+//!
+//! The stable version of rust requires you to create a Decimal number
+//! using one of it's convenience methods.
+//!
+//! ```rust
+//! use rust_decimal::prelude::*;
+//!
+//! // Using an integer followed by the decimal points
+//! let scaled = Decimal::new(202, 2); // 2.02
+//!
+//! // From a string representation
+//! let from_string = Decimal::from_str("2.02").unwrap(); // 2.02
+//!
+//! // Using the `Into` trait
+//! let my_int : Decimal = 3i32.into();
+//!
+//! // Using the raw decimal representation
+//! // 3.1415926535897932384626433832
+//! let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28);
+//! ```
+//!
+mod decimal;
+mod error;
+
+#[cfg(any(feature = "postgres", feature = "diesel"))]
+mod postgres;
+#[cfg(feature = "serde")]
+mod serde_types;
+
+pub use decimal::{Decimal, RoundingStrategy};
+pub use error::Error;
+
+pub mod prelude {
+ pub use crate::{Decimal, RoundingStrategy};
+ pub use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
+ pub use std::str::FromStr;
+}
+
+#[cfg(feature = "diesel")]
+#[macro_use]
+extern crate diesel;
diff --git a/third_party/rust/rust_decimal/src/postgres.rs b/third_party/rust/rust_decimal/src/postgres.rs
new file mode 100644
index 0000000000..c34ed5df62
--- /dev/null
+++ b/third_party/rust/rust_decimal/src/postgres.rs
@@ -0,0 +1,856 @@
+use num_traits::Zero;
+
+use crate::Decimal;
+
+use std::{convert::TryInto, error, fmt, result::*};
+
+use crate::decimal::{div_by_u32, is_all_zero, mul_by_u32, MAX_PRECISION};
+
+#[derive(Debug, Clone)]
+pub struct InvalidDecimal {
+ inner: Option<String>,
+}
+
+impl fmt::Display for InvalidDecimal {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ if let Some(ref msg) = self.inner {
+ fmt.write_fmt(format_args!("Invalid Decimal: {}", msg))
+ } else {
+ fmt.write_str("Invalid Decimal")
+ }
+ }
+}
+
+impl error::Error for InvalidDecimal {}
+
+struct PostgresDecimal<D> {
+ neg: bool,
+ weight: i16,
+ scale: u16,
+ digits: D,
+}
+
+impl Decimal {
+ fn from_postgres<D: ExactSizeIterator<Item = u16>>(
+ PostgresDecimal {
+ neg,
+ scale,
+ digits,
+ weight,
+ }: PostgresDecimal<D>,
+ ) -> Result<Self, InvalidDecimal> {
+ let mut digits = digits.into_iter().collect::<Vec<_>>();
+
+ let fractionals_part_count = digits.len() as i32 + (-weight as i32) - 1;
+ let integers_part_count = weight as i32 + 1;
+
+ let mut result = Decimal::zero();
+ // adding integer part
+ if integers_part_count > 0 {
+ let (start_integers, last) = if integers_part_count > digits.len() as i32 {
+ (integers_part_count - digits.len() as i32, digits.len() as i32)
+ } else {
+ (0, integers_part_count)
+ };
+ let integers: Vec<_> = digits.drain(..last as usize).collect();
+ for digit in integers {
+ result *= Decimal::from_i128_with_scale(10i128.pow(4), 0);
+ result += Decimal::new(digit as i64, 0);
+ }
+ result *= Decimal::from_i128_with_scale(10i128.pow(4 * start_integers as u32), 0);
+ }
+ // adding fractional part
+ if fractionals_part_count > 0 {
+ let dec: Vec<_> = digits.into_iter().collect();
+ let start_fractionals = if weight < 0 { (-weight as u32) - 1 } else { 0 };
+ for (i, digit) in dec.into_iter().enumerate() {
+ let fract_pow = 4 * (i as u32 + 1 + start_fractionals);
+ if fract_pow <= MAX_PRECISION {
+ result += Decimal::new(digit as i64, 0) / Decimal::from_i128_with_scale(10i128.pow(fract_pow), 0);
+ } else if fract_pow == MAX_PRECISION + 4 {
+ // rounding last digit
+ if digit >= 5000 {
+ result +=
+ Decimal::new(1 as i64, 0) / Decimal::from_i128_with_scale(10i128.pow(MAX_PRECISION), 0);
+ }
+ }
+ }
+ }
+
+ result.set_sign_negative(neg);
+ // Rescale to the postgres value, automatically rounding as needed.
+ result.rescale(scale as u32);
+
+ Ok(result)
+ }
+
+ fn to_postgres(self) -> PostgresDecimal<Vec<i16>> {
+ if self.is_zero() {
+ return PostgresDecimal {
+ neg: false,
+ weight: 0,
+ scale: 0,
+ digits: vec![0],
+ };
+ }
+ let scale = self.scale() as u16;
+
+ let groups_diff = scale & 0x3; // groups_diff = scale % 4
+
+ let mut mantissa = self.mantissa_array4();
+
+ if groups_diff > 0 {
+ let remainder = 4 - groups_diff;
+ let power = 10u32.pow(u32::from(remainder));
+ mul_by_u32(&mut mantissa, power);
+ }
+
+ // array to store max mantissa of Decimal in Postgres decimal format
+ const MAX_GROUP_COUNT: usize = 8;
+ let mut digits = Vec::with_capacity(MAX_GROUP_COUNT);
+
+ while !is_all_zero(&mantissa) {
+ let digit = div_by_u32(&mut mantissa, 10000) as u16;
+ digits.push(digit.try_into().unwrap());
+ }
+ digits.reverse();
+ let digits_after_decimal = (scale + 3) as u16 / 4;
+ let weight = digits.len() as i16 - digits_after_decimal as i16 - 1;
+
+ let unnecessary_zeroes = if weight >= 0 {
+ let index_of_decimal = (weight + 1) as usize;
+ digits
+ .get(index_of_decimal..)
+ .expect("enough digits exist")
+ .iter()
+ .rev()
+ .take_while(|i| **i == 0)
+ .count()
+ } else {
+ 0
+ };
+ let relevant_digits = digits.len() - unnecessary_zeroes;
+ digits.truncate(relevant_digits);
+
+ PostgresDecimal {
+ neg: self.is_sign_negative(),
+ digits,
+ scale,
+ weight,
+ }
+ }
+}
+
+#[cfg(feature = "diesel")]
+mod diesel {
+ use super::*;
+
+ use ::diesel::{
+ deserialize::{self, FromSql},
+ pg::data_types::PgNumeric,
+ pg::Pg,
+ serialize::{self, Output, ToSql},
+ sql_types::Numeric,
+ };
+ use ::std::{
+ convert::{TryFrom, TryInto},
+ io::Write,
+ };
+
+ impl<'a> TryFrom<&'a PgNumeric> for Decimal {
+ type Error = Box<dyn error::Error + Send + Sync>;
+
+ fn try_from(numeric: &'a PgNumeric) -> deserialize::Result<Self> {
+ let (neg, weight, scale, digits) = match *numeric {
+ PgNumeric::Positive {
+ weight,
+ scale,
+ ref digits,
+ } => (false, weight, scale, digits),
+ PgNumeric::Negative {
+ weight,
+ scale,
+ ref digits,
+ } => (true, weight, scale, digits),
+ PgNumeric::NaN => return Err(Box::from("NaN is not supported in Decimal")),
+ };
+
+ Ok(Self::from_postgres(PostgresDecimal {
+ neg,
+ weight,
+ scale,
+ digits: digits.iter().copied().map(|v| v.try_into().unwrap()),
+ })
+ .map_err(Box::new)?)
+ }
+ }
+
+ impl TryFrom<PgNumeric> for Decimal {
+ type Error = Box<dyn error::Error + Send + Sync>;
+
+ fn try_from(numeric: PgNumeric) -> deserialize::Result<Self> {
+ (&numeric).try_into()
+ }
+ }
+
+ impl<'a> From<&'a Decimal> for PgNumeric {
+ // NOTE(clippy): Clippy suggests to replace the `.take_while(|i| i.is_zero())`
+ // with `.take_while(Zero::is_zero)`, but that's a false positive.
+ // The closure gets an `&&i16` due to autoderef `<i16 as Zero>::is_zero(&self) -> bool`
+ // is called. There is no impl for `&i16` that would work with this closure.
+ #[allow(clippy::assign_op_pattern, clippy::redundant_closure)]
+ fn from(decimal: &'a Decimal) -> Self {
+ let PostgresDecimal {
+ neg,
+ weight,
+ scale,
+ digits,
+ } = decimal.to_postgres();
+
+ let digits = digits.into_iter().map(|v| v.try_into().unwrap()).collect();
+
+ if neg {
+ PgNumeric::Negative { digits, scale, weight }
+ } else {
+ PgNumeric::Positive { digits, scale, weight }
+ }
+ }
+ }
+
+ impl From<Decimal> for PgNumeric {
+ fn from(bigdecimal: Decimal) -> Self {
+ (&bigdecimal).into()
+ }
+ }
+
+ impl ToSql<Numeric, Pg> for Decimal {
+ fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
+ let numeric = PgNumeric::from(self);
+ ToSql::<Numeric, Pg>::to_sql(&numeric, out)
+ }
+ }
+
+ impl FromSql<Numeric, Pg> for Decimal {
+ fn from_sql(numeric: Option<&[u8]>) -> deserialize::Result<Self> {
+ PgNumeric::from_sql(numeric)?.try_into()
+ }
+ }
+
+ #[cfg(test)]
+ mod pg_tests {
+ use super::*;
+ use std::str::FromStr;
+
+ #[test]
+ fn test_unnecessary_zeroes() {
+ fn extract(value: &str) -> Decimal {
+ Decimal::from_str(value).unwrap()
+ }
+
+ let tests = &[
+ ("0.000001660"),
+ ("41.120255926293000"),
+ ("0.5538973300"),
+ ("08883.55986854293100"),
+ ("0.0000_0000_0016_6000_00"),
+ ("0.00000166650000"),
+ ("1666500000000"),
+ ("1666500000000.0000054500"),
+ ("8944.000000000000"),
+ ];
+
+ for &value in tests {
+ let value = extract(value);
+ let pg = PgNumeric::from(value);
+ let dec = Decimal::try_from(pg).unwrap();
+ assert_eq!(dec, value);
+ }
+ }
+
+ #[test]
+ fn decimal_to_pgnumeric_converts_digits_to_base_10000() {
+ let decimal = Decimal::from_str("1").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: 0,
+ scale: 0,
+ digits: vec![1],
+ };
+ assert_eq!(expected, decimal.into());
+
+ let decimal = Decimal::from_str("10").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: 0,
+ scale: 0,
+ digits: vec![10],
+ };
+ assert_eq!(expected, decimal.into());
+
+ let decimal = Decimal::from_str("10000").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: 1,
+ scale: 0,
+ digits: vec![1, 0],
+ };
+ assert_eq!(expected, decimal.into());
+
+ let decimal = Decimal::from_str("10001").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: 1,
+ scale: 0,
+ digits: vec![1, 1],
+ };
+ assert_eq!(expected, decimal.into());
+
+ let decimal = Decimal::from_str("100000000").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: 2,
+ scale: 0,
+ digits: vec![1, 0, 0],
+ };
+ assert_eq!(expected, decimal.into());
+ }
+
+ #[test]
+ fn decimal_to_pg_numeric_properly_adjusts_scale() {
+ let decimal = Decimal::from_str("1").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: 0,
+ scale: 0,
+ digits: vec![1],
+ };
+ assert_eq!(expected, decimal.into());
+
+ let decimal = Decimal::from_str("1.0").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: 0,
+ scale: 1,
+ digits: vec![1],
+ };
+ assert_eq!(expected, decimal.into());
+
+ let decimal = Decimal::from_str("1.1").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: 0,
+ scale: 1,
+ digits: vec![1, 1000],
+ };
+ assert_eq!(expected, decimal.into());
+
+ let decimal = Decimal::from_str("1.10").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: 0,
+ scale: 2,
+ digits: vec![1, 1000],
+ };
+ assert_eq!(expected, decimal.into());
+
+ let decimal = Decimal::from_str("100000000.0001").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: 2,
+ scale: 4,
+ digits: vec![1, 0, 0, 1],
+ };
+ assert_eq!(expected, decimal.into());
+
+ let decimal = Decimal::from_str("0.1").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: -1,
+ scale: 1,
+ digits: vec![1000],
+ };
+ assert_eq!(expected, decimal.into());
+ }
+
+ #[test]
+ #[cfg(feature = "unstable")]
+ fn decimal_to_pg_numeric_retains_sign() {
+ let decimal = Decimal::from_str("123.456").unwrap();
+ let expected = PgNumeric::Positive {
+ weight: 0,
+ scale: 3,
+ digits: vec![123, 4560],
+ };
+ assert_eq!(expected, decimal.into());
+
+ let decimal = Decimal::from_str("-123.456").unwrap();
+ let expected = PgNumeric::Negative {
+ weight: 0,
+ scale: 3,
+ digits: vec![123, 4560],
+ };
+ assert_eq!(expected, decimal.into());
+ }
+
+ #[test]
+ fn pg_numeric_to_decimal_works() {
+ let expected = Decimal::from_str("50").unwrap();
+ let pg_numeric = PgNumeric::Positive {
+ weight: 0,
+ scale: 0,
+ digits: vec![50],
+ };
+ let res: Decimal = pg_numeric.try_into().unwrap();
+ assert_eq!(res, expected);
+ let expected = Decimal::from_str("123.456").unwrap();
+ let pg_numeric = PgNumeric::Positive {
+ weight: 0,
+ scale: 3,
+ digits: vec![123, 4560],
+ };
+ let res: Decimal = pg_numeric.try_into().unwrap();
+ assert_eq!(res, expected);
+
+ let expected = Decimal::from_str("-56.78").unwrap();
+ let pg_numeric = PgNumeric::Negative {
+ weight: 0,
+ scale: 2,
+ digits: vec![56, 7800],
+ };
+ let res: Decimal = pg_numeric.try_into().unwrap();
+ assert_eq!(res, expected);
+
+ // Verify no trailing zeroes are lost.
+
+ let expected = Decimal::from_str("1.100").unwrap();
+ let pg_numeric = PgNumeric::Positive {
+ weight: 0,
+ scale: 3,
+ digits: vec![1, 1000],
+ };
+ let res: Decimal = pg_numeric.try_into().unwrap();
+ assert_eq!(res.to_string(), expected.to_string());
+
+ // To represent 5.00, Postgres can return either [5, 0] as the list of digits.
+ let expected = Decimal::from_str("5.00").unwrap();
+ let pg_numeric = PgNumeric::Positive {
+ weight: 0,
+ scale: 2,
+
+ digits: vec![5, 0],
+ };
+ let res: Decimal = pg_numeric.try_into().unwrap();
+ assert_eq!(res.to_string(), expected.to_string());
+
+ // To represent 5.00, Postgres can return [5] as the list of digits.
+ let expected = Decimal::from_str("5.00").unwrap();
+ let pg_numeric = PgNumeric::Positive {
+ weight: 0,
+ scale: 2,
+ digits: vec![5],
+ };
+ let res: Decimal = pg_numeric.try_into().unwrap();
+ assert_eq!(res.to_string(), expected.to_string());
+
+ let expected = Decimal::from_str("3.1415926535897932384626433833").unwrap();
+ let pg_numeric = PgNumeric::Positive {
+ weight: 0,
+ scale: 30,
+ digits: vec![3, 1415, 9265, 3589, 7932, 3846, 2643, 3832, 7950, 2800],
+ };
+ let res: Decimal = pg_numeric.try_into().unwrap();
+ assert_eq!(res.to_string(), expected.to_string());
+
+ let expected = Decimal::from_str("3.1415926535897932384626433833").unwrap();
+ let pg_numeric = PgNumeric::Positive {
+ weight: 0,
+ scale: 34,
+ digits: vec![3, 1415, 9265, 3589, 7932, 3846, 2643, 3832, 7950, 2800],
+ };
+
+ let res: Decimal = pg_numeric.try_into().unwrap();
+ assert_eq!(res.to_string(), expected.to_string());
+
+ let expected = Decimal::from_str("1.2345678901234567890123456790").unwrap();
+ let pg_numeric = PgNumeric::Positive {
+ weight: 0,
+ scale: 34,
+ digits: vec![1, 2345, 6789, 0123, 4567, 8901, 2345, 6789, 5000, 0],
+ };
+
+ let res: Decimal = pg_numeric.try_into().unwrap();
+ assert_eq!(res.to_string(), expected.to_string());
+ }
+ }
+}
+
+#[cfg(feature = "postgres")]
+mod postgres {
+ use super::*;
+
+ use ::byteorder::{BigEndian, ReadBytesExt};
+ use ::bytes::{BufMut, BytesMut};
+ use ::postgres::types::*;
+ use ::std::io::Cursor;
+
+ impl<'a> FromSql<'a> for Decimal {
+ // Decimals are represented as follows:
+ // Header:
+ // u16 numGroups
+ // i16 weightFirstGroup (10000^weight)
+ // u16 sign (0x0000 = positive, 0x4000 = negative, 0xC000 = NaN)
+ // i16 dscale. Number of digits (in base 10) to print after decimal separator
+ //
+ // Psuedo code :
+ // const Decimals [
+ // 0.0000000000000000000000000001,
+ // 0.000000000000000000000001,
+ // 0.00000000000000000001,
+ // 0.0000000000000001,
+ // 0.000000000001,
+ // 0.00000001,
+ // 0.0001,
+ // 1,
+ // 10000,
+ // 100000000,
+ // 1000000000000,
+ // 10000000000000000,
+ // 100000000000000000000,
+ // 1000000000000000000000000,
+ // 10000000000000000000000000000
+ // ]
+ // overflow = false
+ // result = 0
+ // for i = 0, weight = weightFirstGroup + 7; i < numGroups; i++, weight--
+ // group = read.u16
+ // if weight < 0 or weight > MaxNum
+ // overflow = true
+ // else
+ // result += Decimals[weight] * group
+ // sign == 0x4000 ? -result : result
+
+ // So if we were to take the number: 3950.123456
+ //
+ // Stored on Disk:
+ // 00 03 00 00 00 00 00 06 0F 6E 04 D2 15 E0
+ //
+ // Number of groups: 00 03
+ // Weight of first group: 00 00
+ // Sign: 00 00
+ // DScale: 00 06
+ //
+ // 0F 6E = 3950
+ // result = result + 3950 * 1;
+ // 04 D2 = 1234
+ // result = result + 1234 * 0.0001;
+ // 15 E0 = 5600
+ // result = result + 5600 * 0.00000001;
+ //
+
+ fn from_sql(_: &Type, raw: &[u8]) -> Result<Decimal, Box<dyn error::Error + 'static + Sync + Send>> {
+ let mut raw = Cursor::new(raw);
+ let num_groups = raw.read_u16::<BigEndian>()?;
+ let weight = raw.read_i16::<BigEndian>()?; // 10000^weight
+ // Sign: 0x0000 = positive, 0x4000 = negative, 0xC000 = NaN
+ let sign = raw.read_u16::<BigEndian>()?;
+ // Number of digits (in base 10) to print after decimal separator
+ let scale = raw.read_u16::<BigEndian>()?;
+
+ // Read all of the groups
+ let mut groups = Vec::new();
+ for _ in 0..num_groups as usize {
+ groups.push(raw.read_u16::<BigEndian>()?);
+ }
+
+ Ok(Self::from_postgres(PostgresDecimal {
+ neg: sign == 0x4000,
+ weight,
+ scale,
+ digits: groups.into_iter(),
+ })
+ .map_err(Box::new)?)
+ }
+
+ fn accepts(ty: &Type) -> bool {
+ match ty {
+ &Type::NUMERIC => true,
+ _ => false,
+ }
+ }
+ }
+
+ impl ToSql for Decimal {
+ fn to_sql(
+ &self,
+ _: &Type,
+ out: &mut BytesMut,
+ ) -> Result<IsNull, Box<dyn error::Error + 'static + Sync + Send>> {
+ let PostgresDecimal {
+ neg,
+ weight,
+ scale,
+ digits,
+ } = self.to_postgres();
+
+ let num_digits = digits.len();
+
+ // Reserve bytes
+ out.reserve(8 + num_digits * 2);
+
+ // Number of groups
+ out.put_u16(num_digits.try_into().unwrap());
+ // Weight of first group
+ out.put_i16(weight);
+ // Sign
+ out.put_u16(if neg { 0x4000 } else { 0x0000 });
+ // DScale
+ out.put_u16(scale);
+ // Now process the number
+ for digit in digits[0..num_digits].iter() {
+ out.put_i16(*digit);
+ }
+
+ Ok(IsNull::No)
+ }
+
+ fn accepts(ty: &Type) -> bool {
+ match ty {
+ &Type::NUMERIC => true,
+ _ => false,
+ }
+ }
+
+ to_sql_checked!();
+ }
+
+ #[cfg(test)]
+ mod test {
+ use super::*;
+
+ use ::postgres::{Client, NoTls};
+
+ use std::str::FromStr;
+
+ /// Gets the URL for connecting to PostgreSQL for testing. Set the POSTGRES_URL
+ /// environment variable to change from the default of "postgres://postgres@localhost".
+ fn get_postgres_url() -> String {
+ if let Ok(url) = std::env::var("POSTGRES_URL") {
+ return url;
+ }
+ "postgres://postgres@localhost".to_string()
+ }
+
+ pub static TEST_DECIMALS: &[(u32, u32, &str, &str)] = &[
+ // precision, scale, sent, expected
+ (35, 6, "3950.123456", "3950.123456"),
+ (35, 2, "3950.123456", "3950.12"),
+ (35, 2, "3950.1256", "3950.13"),
+ (10, 2, "3950.123456", "3950.12"),
+ (35, 6, "3950", "3950.000000"),
+ (4, 0, "3950", "3950"),
+ (35, 6, "0.1", "0.100000"),
+ (35, 6, "0.01", "0.010000"),
+ (35, 6, "0.001", "0.001000"),
+ (35, 6, "0.0001", "0.000100"),
+ (35, 6, "0.00001", "0.000010"),
+ (35, 6, "0.000001", "0.000001"),
+ (35, 6, "1", "1.000000"),
+ (35, 6, "-100", "-100.000000"),
+ (35, 6, "-123.456", "-123.456000"),
+ (35, 6, "119996.25", "119996.250000"),
+ (35, 6, "1000000", "1000000.000000"),
+ (35, 6, "9999999.99999", "9999999.999990"),
+ (35, 6, "12340.56789", "12340.567890"),
+ // Scale is only 28 since that is the maximum we can represent.
+ (65, 30, "1.2", "1.2000000000000000000000000000"),
+ // Pi - rounded at scale 28
+ (
+ 65,
+ 30,
+ "3.141592653589793238462643383279",
+ "3.1415926535897932384626433833",
+ ),
+ (
+ 65,
+ 34,
+ "3.1415926535897932384626433832795028",
+ "3.1415926535897932384626433833",
+ ),
+ // Unrounded number
+ (
+ 65,
+ 34,
+ "1.234567890123456789012345678950000",
+ "1.2345678901234567890123456790",
+ ),
+ (
+ 65,
+ 34, // No rounding due to 49999 after significant digits
+ "1.234567890123456789012345678949999",
+ "1.2345678901234567890123456789",
+ ),
+ // 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF (96 bit)
+ (35, 0, "79228162514264337593543950335", "79228162514264337593543950335"),
+ // 0x0FFF_FFFF_FFFF_FFFF_FFFF_FFFF (95 bit)
+ (35, 1, "4951760157141521099596496895", "4951760157141521099596496895.0"),
+ // 0x1000_0000_0000_0000_0000_0000
+ (35, 1, "4951760157141521099596496896", "4951760157141521099596496896.0"),
+ (35, 6, "18446744073709551615", "18446744073709551615.000000"),
+ (35, 6, "-18446744073709551615", "-18446744073709551615.000000"),
+ (35, 6, "0.10001", "0.100010"),
+ (35, 6, "0.12345", "0.123450"),
+ ];
+
+ #[test]
+ fn test_null() {
+ let mut client = match Client::connect(&get_postgres_url(), NoTls) {
+ Ok(x) => x,
+ Err(err) => panic!("{:#?}", err),
+ };
+
+ // Test NULL
+ let result: Option<Decimal> = match client.query("SELECT NULL::numeric", &[]) {
+ Ok(x) => x.iter().next().unwrap().get(0),
+ Err(err) => panic!("{:#?}", err),
+ };
+ assert_eq!(None, result);
+ }
+
+ #[tokio::test]
+ #[cfg(feature = "tokio-pg")]
+ async fn async_test_null() {
+ use ::futures::future::FutureExt;
+ use ::tokio_postgres::connect;
+
+ let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();
+ let connection = connection.map(|e| e.unwrap());
+ tokio::spawn(connection);
+
+ let statement = client.prepare(&"SELECT NULL::numeric").await.unwrap();
+ let rows = client.query(&statement, &[]).await.unwrap();
+ let result: Option<Decimal> = rows.iter().next().unwrap().get(0);
+
+ assert_eq!(None, result);
+ }
+
+ #[test]
+ fn read_numeric_type() {
+ let mut client = match Client::connect(&get_postgres_url(), NoTls) {
+ Ok(x) => x,
+ Err(err) => panic!("{:#?}", err),
+ };
+ for &(precision, scale, sent, expected) in TEST_DECIMALS.iter() {
+ let result: Decimal =
+ match client.query(&*format!("SELECT {}::NUMERIC({}, {})", sent, precision, scale), &[]) {
+ Ok(x) => x.iter().next().unwrap().get(0),
+ Err(err) => panic!("SELECT {}::NUMERIC({}, {}), error - {:#?}", sent, precision, scale, err),
+ };
+ assert_eq!(
+ expected,
+ result.to_string(),
+ "NUMERIC({}, {}) sent: {}",
+ precision,
+ scale,
+ sent
+ );
+ }
+ }
+
+ #[tokio::test]
+ #[cfg(feature = "tokio-pg")]
+ async fn async_read_numeric_type() {
+ use ::futures::future::FutureExt;
+ use ::tokio_postgres::connect;
+
+ let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();
+ let connection = connection.map(|e| e.unwrap());
+ tokio::spawn(connection);
+ for &(precision, scale, sent, expected) in TEST_DECIMALS.iter() {
+ let statement = client
+ .prepare(&*format!("SELECT {}::NUMERIC({}, {})", sent, precision, scale))
+ .await
+ .unwrap();
+ let rows = client.query(&statement, &[]).await.unwrap();
+ let result: Decimal = rows.iter().next().unwrap().get(0);
+
+ assert_eq!(expected, result.to_string(), "NUMERIC({}, {})", precision, scale);
+ }
+ }
+
+ #[test]
+ fn write_numeric_type() {
+ let mut client = match Client::connect(&get_postgres_url(), NoTls) {
+ Ok(x) => x,
+ Err(err) => panic!("{:#?}", err),
+ };
+ for &(precision, scale, sent, expected) in TEST_DECIMALS.iter() {
+ let number = Decimal::from_str(sent).unwrap();
+ let result: Decimal =
+ match client.query(&*format!("SELECT $1::NUMERIC({}, {})", precision, scale), &[&number]) {
+ Ok(x) => x.iter().next().unwrap().get(0),
+ Err(err) => panic!("{:#?}", err),
+ };
+ assert_eq!(expected, result.to_string(), "NUMERIC({}, {})", precision, scale);
+ }
+ }
+
+ #[tokio::test]
+ #[cfg(feature = "tokio-pg")]
+ async fn async_write_numeric_type() {
+ use ::futures::future::FutureExt;
+ use ::tokio_postgres::connect;
+
+ let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();
+ let connection = connection.map(|e| e.unwrap());
+ tokio::spawn(connection);
+
+ for &(precision, scale, sent, expected) in TEST_DECIMALS.iter() {
+ let statement = client
+ .prepare(&*format!("SELECT $1::NUMERIC({}, {})", precision, scale))
+ .await
+ .unwrap();
+ let number = Decimal::from_str(sent).unwrap();
+ let rows = client.query(&statement, &[&number]).await.unwrap();
+ let result: Decimal = rows.iter().next().unwrap().get(0);
+
+ assert_eq!(expected, result.to_string(), "NUMERIC({}, {})", precision, scale);
+ }
+ }
+
+ #[test]
+ fn numeric_overflow() {
+ let tests = [(4, 4, "3950.1234")];
+ let mut client = match Client::connect(&get_postgres_url(), NoTls) {
+ Ok(x) => x,
+ Err(err) => panic!("{:#?}", err),
+ };
+ for &(precision, scale, sent) in tests.iter() {
+ match client.query(&*format!("SELECT {}::NUMERIC({}, {})", sent, precision, scale), &[]) {
+ Ok(_) => panic!(
+ "Expected numeric overflow for {}::NUMERIC({}, {})",
+ sent, precision, scale
+ ),
+ Err(err) => {
+ assert_eq!("22003", err.code().unwrap().code(), "Unexpected error code");
+ }
+ };
+ }
+ }
+
+ #[tokio::test]
+ #[cfg(feature = "tokio-pg")]
+ async fn async_numeric_overflow() {
+ use ::futures::future::FutureExt;
+ use ::tokio_postgres::connect;
+
+ let tests = [(4, 4, "3950.1234")];
+ let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();
+ let connection = connection.map(|e| e.unwrap());
+ tokio::spawn(connection);
+
+ for &(precision, scale, sent) in tests.iter() {
+ let statement = client
+ .prepare(&*format!("SELECT {}::NUMERIC({}, {})", sent, precision, scale))
+ .await
+ .unwrap();
+
+ match client.query(&statement, &[]).await {
+ Ok(_) => panic!(
+ "Expected numeric overflow for {}::NUMERIC({}, {})",
+ sent, precision, scale
+ ),
+ Err(err) => assert_eq!("22003", err.code().unwrap().code(), "Unexpected error code"),
+ }
+ }
+ }
+ }
+}
diff --git a/third_party/rust/rust_decimal/src/serde_types.rs b/third_party/rust/rust_decimal/src/serde_types.rs
new file mode 100644
index 0000000000..a19174973f
--- /dev/null
+++ b/third_party/rust/rust_decimal/src/serde_types.rs
@@ -0,0 +1,218 @@
+use crate::Decimal;
+
+use num_traits::FromPrimitive;
+
+use serde::{self, de::Unexpected};
+
+use std::{fmt, str::FromStr};
+
+#[cfg(not(feature = "serde-bincode"))]
+impl<'de> serde::Deserialize<'de> for Decimal {
+ fn deserialize<D>(deserializer: D) -> Result<Decimal, D::Error>
+ where
+ D: serde::de::Deserializer<'de>,
+ {
+ deserializer.deserialize_any(DecimalVisitor)
+ }
+}
+
+#[cfg(all(feature = "serde-bincode", not(feature = "serde-float")))]
+impl<'de> serde::Deserialize<'de> for Decimal {
+ fn deserialize<D>(deserializer: D) -> Result<Decimal, D::Error>
+ where
+ D: serde::de::Deserializer<'de>,
+ {
+ deserializer.deserialize_str(DecimalVisitor)
+ }
+}
+
+#[cfg(all(feature = "serde-bincode", feature = "serde-float"))]
+impl<'de> serde::Deserialize<'de> for Decimal {
+ fn deserialize<D>(deserializer: D) -> Result<Decimal, D::Error>
+ where
+ D: serde::de::Deserializer<'de>,
+ {
+ deserializer.deserialize_f64(DecimalVisitor)
+ }
+}
+
+struct DecimalVisitor;
+
+impl<'de> serde::de::Visitor<'de> for DecimalVisitor {
+ type Value = Decimal;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "a Decimal type representing a fixed-point number")
+ }
+
+ fn visit_i64<E>(self, value: i64) -> Result<Decimal, E>
+ where
+ E: serde::de::Error,
+ {
+ match Decimal::from_i64(value) {
+ Some(s) => Ok(s),
+ None => Err(E::invalid_value(Unexpected::Signed(value), &self)),
+ }
+ }
+
+ fn visit_u64<E>(self, value: u64) -> Result<Decimal, E>
+ where
+ E: serde::de::Error,
+ {
+ match Decimal::from_u64(value) {
+ Some(s) => Ok(s),
+ None => Err(E::invalid_value(Unexpected::Unsigned(value), &self)),
+ }
+ }
+
+ fn visit_f64<E>(self, value: f64) -> Result<Decimal, E>
+ where
+ E: serde::de::Error,
+ {
+ Decimal::from_str(&value.to_string()).map_err(|_| E::invalid_value(Unexpected::Float(value), &self))
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Decimal, E>
+ where
+ E: serde::de::Error,
+ {
+ Decimal::from_str(value)
+ .or_else(|_| Decimal::from_scientific(value))
+ .map_err(|_| E::invalid_value(Unexpected::Str(value), &self))
+ }
+}
+
+#[cfg(not(feature = "serde-float"))]
+impl serde::Serialize for Decimal {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ serializer.serialize_str(&self.to_string())
+ }
+}
+
+#[cfg(feature = "serde-float")]
+impl serde::Serialize for Decimal {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ use num_traits::ToPrimitive;
+ serializer.serialize_f64(self.to_f64().unwrap())
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use super::*;
+
+ use serde_derive::{Deserialize, Serialize};
+
+ #[derive(Serialize, Deserialize, Debug)]
+ struct Record {
+ amount: Decimal,
+ }
+
+ #[test]
+ #[cfg(not(feature = "serde-bincode"))]
+ fn deserialize_valid_decimal() {
+ let data = [
+ ("{\"amount\":\"1.234\"}", "1.234"),
+ ("{\"amount\":1234}", "1234"),
+ ("{\"amount\":1234.56}", "1234.56"),
+ ("{\"amount\":\"1.23456e3\"}", "1234.56"),
+ ];
+ for &(serialized, value) in data.iter() {
+ let result = serde_json::from_str(serialized);
+ assert_eq!(
+ true,
+ result.is_ok(),
+ "expected successful deseralization for {}. Error: {:?}",
+ serialized,
+ result.err().unwrap()
+ );
+ let record: Record = result.unwrap();
+ assert_eq!(
+ value,
+ record.amount.to_string(),
+ "expected: {}, actual: {}",
+ value,
+ record.amount.to_string()
+ );
+ }
+ }
+
+ #[test]
+ #[should_panic]
+ fn deserialize_invalid_decimal() {
+ let serialized = "{\"amount\":\"foo\"}";
+ let _: Record = serde_json::from_str(serialized).unwrap();
+ }
+
+ #[test]
+ #[cfg(not(feature = "serde-float"))]
+ fn serialize_decimal() {
+ let record = Record {
+ amount: Decimal::new(1234, 3),
+ };
+ let serialized = serde_json::to_string(&record).unwrap();
+ assert_eq!("{\"amount\":\"1.234\"}", serialized);
+ }
+
+ #[test]
+ #[cfg(feature = "serde-float")]
+ fn serialize_decimal() {
+ let record = Record {
+ amount: Decimal::new(1234, 3),
+ };
+ let serialized = serde_json::to_string(&record).unwrap();
+ assert_eq!("{\"amount\":1.234}", serialized);
+ }
+
+ #[test]
+ #[cfg(all(feature = "serde-bincode", not(feature = "serde-float")))]
+ fn bincode_serialization() {
+ use bincode::{deserialize, serialize};
+
+ let data = [
+ "0",
+ "0.00",
+ "3.14159",
+ "-3.14159",
+ "1234567890123.4567890",
+ "-1234567890123.4567890",
+ ];
+ for &raw in data.iter() {
+ let value = Decimal::from_str(raw).unwrap();
+ let encoded = serialize(&value).unwrap();
+ let decoded: Decimal = deserialize(&encoded[..]).unwrap();
+ assert_eq!(value, decoded);
+ assert_eq!(8usize + raw.len(), encoded.len());
+ }
+ }
+
+ #[test]
+ #[cfg(all(feature = "serde-bincode", feature = "serde-float"))]
+ fn bincode_serialization() {
+ use bincode::{deserialize, serialize};
+
+ let data = [
+ ("0", "0"),
+ ("0.00", "0.00"),
+ ("3.14159", "3.14159"),
+ ("-3.14159", "-3.14159"),
+ ("1234567890123.4567890", "1234567890123.4568"),
+ ("-1234567890123.4567890", "-1234567890123.4568"),
+ ];
+ for &(value, expected) in data.iter() {
+ let value = Decimal::from_str(value).unwrap();
+ let expected = Decimal::from_str(expected).unwrap();
+ let encoded = serialize(&value).unwrap();
+ let decoded: Decimal = deserialize(&encoded[..]).unwrap();
+ assert_eq!(expected, decoded);
+ assert_eq!(8usize, encoded.len());
+ }
+ }
+}
diff --git a/third_party/rust/rust_decimal/tests/decimal_tests.rs b/third_party/rust/rust_decimal/tests/decimal_tests.rs
new file mode 100644
index 0000000000..4517254e35
--- /dev/null
+++ b/third_party/rust/rust_decimal/tests/decimal_tests.rs
@@ -0,0 +1,1633 @@
+use num_traits::{Signed, ToPrimitive, Zero};
+
+use rust_decimal::{Decimal, RoundingStrategy};
+
+use std::{
+ cmp::{Ordering, Ordering::*},
+ str::FromStr,
+};
+
+// Parsing
+
+#[test]
+fn it_creates_a_new_negative_decimal() {
+ let a = Decimal::new(-100, 2);
+ assert_eq!(a.is_sign_negative(), true);
+ assert_eq!(a.scale(), 2);
+ assert_eq!("-1.00", a.to_string());
+}
+
+#[test]
+fn it_creates_a_new_decimal_using_numeric_boundaries() {
+ let a = Decimal::new(i64::max_value(), 2);
+ assert_eq!(a.is_sign_negative(), false);
+ assert_eq!(a.scale(), 2);
+ assert_eq!("92233720368547758.07", a.to_string());
+
+ let b = Decimal::new(i64::min_value(), 2);
+ assert_eq!(b.is_sign_negative(), true);
+ assert_eq!(b.scale(), 2);
+ assert_eq!("-92233720368547758.08", b.to_string());
+}
+
+#[test]
+fn it_parses_empty_string() {
+ assert!(Decimal::from_str("").is_err());
+ assert!(Decimal::from_str(" ").is_err());
+}
+
+#[test]
+fn it_parses_positive_int_string() {
+ let a = Decimal::from_str("233").unwrap();
+ assert_eq!(a.is_sign_negative(), false);
+ assert_eq!(a.scale(), 0);
+ assert_eq!("233", a.to_string());
+}
+
+#[test]
+fn it_parses_negative_int_string() {
+ let a = Decimal::from_str("-233").unwrap();
+ assert_eq!(a.is_sign_negative(), true);
+ assert_eq!(a.scale(), 0);
+ println!("to_string");
+ assert_eq!("-233", a.to_string());
+}
+
+#[test]
+fn it_parses_positive_float_string() {
+ let a = Decimal::from_str("233.323223").unwrap();
+ assert_eq!(a.is_sign_negative(), false);
+ assert_eq!(a.scale(), 6);
+ assert_eq!("233.323223", a.to_string());
+}
+
+#[test]
+fn it_parses_negative_float_string() {
+ let a = Decimal::from_str("-233.43343").unwrap();
+ assert_eq!(a.is_sign_negative(), true);
+ assert_eq!(a.scale(), 5);
+ assert_eq!("-233.43343", a.to_string());
+}
+
+#[test]
+fn it_parses_positive_tiny_float_string() {
+ let a = Decimal::from_str(".000001").unwrap();
+ assert_eq!(a.is_sign_negative(), false);
+ assert_eq!(a.scale(), 6);
+ assert_eq!("0.000001", a.to_string());
+}
+
+#[test]
+fn it_parses_negative_tiny_float_string() {
+ let a = Decimal::from_str("-0.000001").unwrap();
+ assert_eq!(a.is_sign_negative(), true);
+ assert_eq!(a.scale(), 6);
+ assert_eq!("-0.000001", a.to_string());
+}
+
+#[test]
+fn it_parses_big_integer_string() {
+ let a = Decimal::from_str("79228162514264337593543950330").unwrap();
+ assert_eq!("79228162514264337593543950330", a.to_string());
+}
+
+#[test]
+fn it_parses_big_float_string() {
+ let a = Decimal::from_str("79.228162514264337593543950330").unwrap();
+ assert_eq!("79.228162514264337593543950330", a.to_string());
+}
+
+#[test]
+fn it_can_serialize_deserialize() {
+ let a = Decimal::from_str("12.3456789").unwrap();
+ let bytes = a.serialize();
+ let b = Decimal::deserialize(bytes);
+ assert_eq!("12.3456789", b.to_string());
+}
+
+// Formatting
+
+#[test]
+fn it_formats() {
+ let a = Decimal::from_str("233.323223").unwrap();
+ assert_eq!(format!("{}", a), "233.323223");
+ assert_eq!(format!("{:.9}", a), "233.323223000");
+ assert_eq!(format!("{:.0}", a), "233");
+ assert_eq!(format!("{:.2}", a), "233.32");
+ assert_eq!(format!("{:010.2}", a), "0000233.32");
+ assert_eq!(format!("{:0<10.2}", a), "233.320000");
+}
+#[test]
+fn it_formats_neg() {
+ let a = Decimal::from_str("-233.323223").unwrap();
+ assert_eq!(format!("{}", a), "-233.323223");
+ assert_eq!(format!("{:.9}", a), "-233.323223000");
+ assert_eq!(format!("{:.0}", a), "-233");
+ assert_eq!(format!("{:.2}", a), "-233.32");
+ assert_eq!(format!("{:010.2}", a), "-000233.32");
+ assert_eq!(format!("{:0<10.2}", a), "-233.32000");
+}
+#[test]
+fn it_formats_small() {
+ let a = Decimal::from_str("0.2223").unwrap();
+ assert_eq!(format!("{}", a), "0.2223");
+ assert_eq!(format!("{:.9}", a), "0.222300000");
+ assert_eq!(format!("{:.0}", a), "0");
+ assert_eq!(format!("{:.2}", a), "0.22");
+ assert_eq!(format!("{:010.2}", a), "0000000.22");
+ assert_eq!(format!("{:0<10.2}", a), "0.22000000");
+}
+#[test]
+fn it_formats_small_leading_zeros() {
+ let a = Decimal::from_str("0.0023554701772169").unwrap();
+ assert_eq!(format!("{}", a), "0.0023554701772169");
+ assert_eq!(format!("{:.9}", a), "0.002355470");
+ assert_eq!(format!("{:.0}", a), "0");
+ assert_eq!(format!("{:.2}", a), "0.00");
+ assert_eq!(format!("{:010.2}", a), "0000000.00");
+ assert_eq!(format!("{:0<10.2}", a), "0.00000000");
+}
+#[test]
+fn it_formats_small_neg() {
+ let a = Decimal::from_str("-0.2223").unwrap();
+ assert_eq!(format!("{}", a), "-0.2223");
+ assert_eq!(format!("{:.9}", a), "-0.222300000");
+ assert_eq!(format!("{:.0}", a), "-0");
+ assert_eq!(format!("{:.2}", a), "-0.22");
+ assert_eq!(format!("{:010.2}", a), "-000000.22");
+ assert_eq!(format!("{:0<10.2}", a), "-0.2200000");
+}
+#[test]
+fn it_formats_zero() {
+ let a = Decimal::from_str("0").unwrap();
+ assert_eq!(format!("{}", a), "0");
+ assert_eq!(format!("{:.9}", a), "0.000000000");
+ assert_eq!(format!("{:.0}", a), "0");
+ assert_eq!(format!("{:.2}", a), "0.00");
+ assert_eq!(format!("{:010.2}", a), "0000000.00");
+ assert_eq!(format!("{:0<10.2}", a), "0.00000000");
+}
+#[test]
+fn it_formats_int() {
+ let a = Decimal::from_str("5").unwrap();
+ assert_eq!(format!("{}", a), "5");
+ assert_eq!(format!("{:.9}", a), "5.000000000");
+ assert_eq!(format!("{:.0}", a), "5");
+ assert_eq!(format!("{:.2}", a), "5.00");
+ assert_eq!(format!("{:010.2}", a), "0000005.00");
+ assert_eq!(format!("{:0<10.2}", a), "5.00000000");
+}
+
+// Negation
+#[test]
+fn it_negates_decimals() {
+ fn neg(a: &str, b: &str) {
+ let a = Decimal::from_str(a).unwrap();
+ let result = -a;
+ assert_eq!(b, result.to_string(), "- {}", a.to_string());
+ }
+
+ let tests = &[
+ ("1", "-1"),
+ ("2", "-2"),
+ ("2454495034", "-2454495034"),
+ (".1", "-0.1"),
+ ("11.815126050420168067226890757", "-11.815126050420168067226890757"),
+ ];
+
+ for &(a, b) in tests {
+ neg(a, b);
+ }
+}
+
+// Addition
+
+#[test]
+fn it_adds_decimals() {
+ fn add(a: &str, b: &str, c: &str) {
+ let a = Decimal::from_str(a).unwrap();
+ let b = Decimal::from_str(b).unwrap();
+ let result = a + b;
+ assert_eq!(c, result.to_string(), "{} + {}", a.to_string(), b.to_string());
+ let result = b + a;
+ assert_eq!(c, result.to_string(), "{} + {}", b.to_string(), a.to_string());
+ }
+
+ let tests = &[
+ ("2", "3", "5"),
+ ("2454495034", "3451204593", "5905699627"),
+ ("24544.95034", ".3451204593", "24545.2954604593"),
+ (".1", ".1", "0.2"),
+ (".10", ".1", "0.20"),
+ (".1", "-.1", "0.0"),
+ ("0", "1.001", "1.001"),
+ ("2", "-3", "-1"),
+ ("-2", "3", "1"),
+ ("-2", "-3", "-5"),
+ ("3", "-2", "1"),
+ ("-3", "2", "-1"),
+ ("1.234", "2.4567", "3.6907"),
+ (
+ "11.815126050420168067226890757",
+ "0.6386554621848739495798319328",
+ "12.453781512605042016806722690",
+ ),
+ (
+ "-11.815126050420168067226890757",
+ "0.6386554621848739495798319328",
+ "-11.176470588235294117647058824",
+ ),
+ (
+ "11.815126050420168067226890757",
+ "-0.6386554621848739495798319328",
+ "11.176470588235294117647058824",
+ ),
+ (
+ "-11.815126050420168067226890757",
+ "-0.6386554621848739495798319328",
+ "-12.453781512605042016806722690",
+ ),
+ (
+ "11815126050420168067226890757",
+ "0.4386554621848739495798319328",
+ "11815126050420168067226890757",
+ ),
+ (
+ "-11815126050420168067226890757",
+ "0.4386554621848739495798319328",
+ "-11815126050420168067226890757",
+ ),
+ (
+ "11815126050420168067226890757",
+ "-0.4386554621848739495798319328",
+ "11815126050420168067226890757",
+ ),
+ (
+ "-11815126050420168067226890757",
+ "-0.4386554621848739495798319328",
+ "-11815126050420168067226890757",
+ ),
+ (
+ "0.0872727272727272727272727272",
+ "843.65000000",
+ "843.7372727272727272727272727",
+ ),
+ (
+ "7314.6229858868828353570724702",
+ "1000",
+ // Overflow causes this to round
+ "8314.622985886882835357072470",
+ ),
+ (
+ "108053.27500000000000000000000",
+ "0.00000000000000000000000",
+ "108053.27500000000000000000000",
+ ),
+ (
+ "108053.27500000000000000000000",
+ // This zero value has too high precision and will be trimmed
+ "0.000000000000000000000000",
+ "108053.27500000000000000000000",
+ ),
+ (
+ "108053.27500000000000000000000",
+ // This value has too high precision and will be rounded
+ "0.000000000000000000000001",
+ "108053.27500000000000000000000",
+ ),
+ (
+ "108053.27500000000000000000000",
+ // This value has too high precision and will be rounded
+ "0.000000000000000000000005",
+ "108053.27500000000000000000001",
+ ),
+ (
+ "8097370036018690744.2590371109596744091",
+ "3807285637671831400.15346897797550749555",
+ "11904655673690522144.412506089",
+ ),
+ ];
+ for &(a, b, c) in tests {
+ add(a, b, c);
+ }
+}
+
+#[test]
+fn it_can_addassign() {
+ let mut a = Decimal::from_str("1.01").unwrap();
+ let b = Decimal::from_str("0.99").unwrap();
+ a += b;
+ assert_eq!("2.00", a.to_string());
+
+ a += &b;
+ assert_eq!("2.99", a.to_string());
+
+ let mut c = &mut a;
+ c += b;
+ assert_eq!("3.98", a.to_string());
+
+ let mut c = &mut a;
+ c += &b;
+ assert_eq!("4.97", a.to_string());
+}
+
+// Subtraction
+
+#[test]
+fn it_subtracts_decimals() {
+ fn sub(a: &str, b: &str, c: &str) {
+ let a = Decimal::from_str(a).unwrap();
+ let b = Decimal::from_str(b).unwrap();
+ let result = a - b;
+ assert_eq!(c, result.to_string(), "{} - {}", a.to_string(), b.to_string());
+ }
+
+ let tests = &[
+ ("2", "3", "-1"),
+ ("3451204593", "2323322332", "1127882261"),
+ ("24544.95034", ".3451204593", "24544.6052195407"),
+ (".1", ".1", "0.0"),
+ (".1", "-.1", "0.2"),
+ ("1.001", "0", "1.001"),
+ ("2", "-3", "5"),
+ ("-2", "3", "-5"),
+ ("-2", "-3", "1"),
+ ("3", "-2", "5"),
+ ("-3", "2", "-5"),
+ ("1.234", "2.4567", "-1.2227"),
+ ("844.13000000", "843.65000000", "0.48000000"),
+ ("79228162514264337593543950335", "79228162514264337593543950335", "0"), // 0xFFFF_FFFF_FFFF_FFFF_FFF_FFFF - 0xFFFF_FFFF_FFFF_FFFF_FFF_FFFF
+ ("79228162514264337593543950335", "0", "79228162514264337593543950335"),
+ ("79228162514264337593543950335", "79228162514264337593543950333", "2"),
+ ("4951760157141521099596496896", "1", "4951760157141521099596496895"), // 0x1000_0000_0000_0000_0000_0000 - 1 = 0x0FFF_FFFF_FFFF_FFFF_FFF_FFFF
+ ("79228162514264337593543950334", "79228162514264337593543950335", "-1"),
+ ("1", "4951760157141521099596496895", "-4951760157141521099596496894"),
+ ("18446744073709551615", "-18446744073709551615", "36893488147419103230"), // 0xFFFF_FFFF_FFFF_FFFF - -0xFFFF_FFFF_FFFF_FFFF
+ ];
+ for &(a, b, c) in tests {
+ sub(a, b, c);
+ }
+}
+
+#[test]
+fn it_can_subassign() {
+ let mut a = Decimal::from_str("1.01").unwrap();
+ let b = Decimal::from_str("0.51").unwrap();
+ a -= b;
+ assert_eq!("0.50", a.to_string());
+
+ a -= &b;
+ assert_eq!("-0.01", a.to_string());
+
+ let mut c = &mut a;
+ c -= b;
+ assert_eq!("-0.52", a.to_string());
+
+ let mut c = &mut a;
+ c -= &b;
+ assert_eq!("-1.03", a.to_string());
+}
+
+// Multiplication
+
+#[test]
+fn it_multiplies_decimals() {
+ fn mul(a: &str, b: &str, c: &str) {
+ let a = Decimal::from_str(a).unwrap();
+ let b = Decimal::from_str(b).unwrap();
+ let result = a * b;
+ assert_eq!(c, result.to_string(), "{} * {}", a.to_string(), b.to_string());
+ let result = b * a;
+ assert_eq!(c, result.to_string(), "{} * {}", b.to_string(), a.to_string());
+ }
+
+ let tests = &[
+ ("2", "3", "6"),
+ ("2454495034", "3451204593", "8470964534836491162"),
+ ("24544.95034", ".3451204593", "8470.964534836491162"),
+ (".1", ".1", "0.01"),
+ ("0", "1.001", "0"),
+ ("2", "-3", "-6"),
+ ("-2", "3", "-6"),
+ ("-2", "-3", "6"),
+ ("1", "2.01", "2.01"),
+ ("1.0", "2.01", "2.010"), // Scale is always additive
+ (
+ "0.00000000000000001",
+ "0.00000000000000001",
+ "0.0000000000000000000000000000",
+ ),
+ ("0.0000000000000000000000000001", "0.0000000000000000000000000001", "0"),
+ (
+ "0.6386554621848739495798319328",
+ "11.815126050420168067226890757",
+ "7.5457947885036367488171739292",
+ ),
+ (
+ "2123456789012345678901234567.8",
+ "11.815126050420168067226890757",
+ "25088909624801327937270048761",
+ ),
+ (
+ "2123456789012345678901234567.8",
+ "-11.815126050420168067226890757",
+ "-25088909624801327937270048761",
+ ),
+ (
+ "2.1234567890123456789012345678",
+ "2.1234567890123456789012345678",
+ "4.5090687348026215523554336227",
+ ),
+ (
+ "0.48000000",
+ "0.1818181818181818181818181818",
+ "0.0872727272727272727272727272",
+ ),
+ ];
+ for &(a, b, c) in tests {
+ mul(a, b, c);
+ }
+}
+
+#[test]
+#[should_panic]
+fn it_panics_when_multiply_with_overflow() {
+ let a = Decimal::from_str("2000000000000000000001").unwrap();
+ let b = Decimal::from_str("3000000000000000000001").unwrap();
+ let _ = a * b;
+}
+
+#[test]
+fn it_can_mulassign() {
+ let mut a = Decimal::from_str("1.25").unwrap();
+ let b = Decimal::from_str("0.01").unwrap();
+
+ a *= b;
+ assert_eq!("0.0125", a.to_string());
+
+ a *= &b;
+ assert_eq!("0.000125", a.to_string());
+
+ let mut c = &mut a;
+ c *= b;
+ assert_eq!("0.00000125", a.to_string());
+
+ let mut c = &mut a;
+ c *= &b;
+ assert_eq!("0.0000000125", a.to_string());
+}
+
+// Division
+
+#[test]
+fn it_divides_decimals() {
+ fn div(a: &str, b: &str, c: &str) {
+ let a = Decimal::from_str(a).unwrap();
+ let b = Decimal::from_str(b).unwrap();
+ let result = a / b;
+ assert_eq!(c, result.to_string(), "{} / {}", a.to_string(), b.to_string());
+ }
+
+ let tests = &[
+ ("6", "3", "2"),
+ ("10", "2", "5"),
+ ("2.2", "1.1", "2"),
+ ("-2.2", "-1.1", "2"),
+ ("12.88", "5.6", "2.3"),
+ ("1023427554493", "43432632", "23563.562864276795382789603908"),
+ ("10000", "3", "3333.3333333333333333333333333"),
+ ("2", "3", "0.6666666666666666666666666667"),
+ ("1", "3", "0.3333333333333333333333333333"),
+ ("-2", "3", "-0.6666666666666666666666666667"),
+ ("2", "-3", "-0.6666666666666666666666666667"),
+ ("-2", "-3", "0.6666666666666666666666666667"),
+ ("1234.567890123456789012345678", "1.234567890123456789012345678", "1000"),
+ ];
+ for &(a, b, c) in tests {
+ div(a, b, c);
+ }
+}
+
+#[test]
+#[should_panic]
+fn it_can_divide_by_zero() {
+ let a = Decimal::from_str("2").unwrap();
+ let _ = a / Decimal::zero();
+}
+
+#[test]
+fn it_can_divassign() {
+ let mut a = Decimal::from_str("1.25").unwrap();
+ let b = Decimal::from_str("0.01").unwrap();
+
+ a /= b;
+ assert_eq!("125", a.to_string());
+
+ a /= &b;
+ assert_eq!("12500", a.to_string());
+
+ let mut c = &mut a;
+ c /= b;
+ assert_eq!("1250000", a.to_string());
+
+ let mut c = &mut a;
+ c /= &b;
+ assert_eq!("125000000", a.to_string());
+}
+
+// Modulus and Remainder are not the same thing!
+// https://math.stackexchange.com/q/801962/82277
+
+#[test]
+fn it_rems_decimals() {
+ fn rem(a: &str, b: &str, c: &str) {
+ let a = Decimal::from_str(a).unwrap();
+ let b = Decimal::from_str(b).unwrap();
+ // a = qb + r
+ let result = a % b;
+ assert_eq!(c, result.to_string(), "{} % {}", a.to_string(), b.to_string());
+ }
+
+ let tests = &[
+ ("2", "3", "2"),
+ ("-2", "3", "-2"),
+ ("2", "-3", "2"),
+ ("-2", "-3", "-2"),
+ ("6", "3", "0"),
+ ("42.2", "11.9", "6.5"),
+ ("2.1", "3", "2.1"),
+ ("2", "3.1", "2"),
+ ("2.0", "3.1", "2.0"),
+ ("4", "3.1", "0.9"),
+ ];
+ for &(a, b, c) in tests {
+ rem(a, b, c);
+ }
+}
+
+#[test]
+fn it_can_remassign() {
+ let mut a = Decimal::from_str("5").unwrap();
+ let b = Decimal::from_str("2").unwrap();
+
+ a %= b;
+ assert_eq!("1", a.to_string());
+
+ a %= &b;
+ assert_eq!("1", a.to_string());
+
+ let mut c = &mut a;
+ c %= b;
+ assert_eq!("1", a.to_string());
+
+ let mut c = &mut a;
+ c %= &b;
+ assert_eq!("1", a.to_string());
+}
+
+#[test]
+fn it_eqs_decimals() {
+ fn eq(a: &str, b: &str, c: bool) {
+ let a = Decimal::from_str(a).unwrap();
+ let b = Decimal::from_str(b).unwrap();
+ assert_eq!(c, a.eq(&b), "{} == {}", a.to_string(), b.to_string());
+ assert_eq!(c, b.eq(&a), "{} == {}", b.to_string(), a.to_string());
+ }
+
+ let tests = &[
+ ("1", "1", true),
+ ("1", "-1", false),
+ ("1", "1.00", true),
+ ("1.2345000000000", "1.2345", true),
+ ("1.0000000000000000000000000000", "1.0000000000000000000000000000", true),
+ (
+ "1.0000000000000000000000000001",
+ "1.0000000000000000000000000000",
+ false,
+ ),
+ ];
+ for &(a, b, c) in tests {
+ eq(a, b, c);
+ }
+}
+
+#[test]
+fn it_cmps_decimals() {
+ fn cmp(a: &str, b: &str, c: Ordering) {
+ let a = Decimal::from_str(a).unwrap();
+ let b = Decimal::from_str(b).unwrap();
+ assert_eq!(c, a.cmp(&b), "{} {:?} {}", a.to_string(), c, b.to_string());
+ }
+
+ let tests = &[
+ ("1", "1", Equal),
+ ("1", "-1", Greater),
+ ("1", "1.00", Equal),
+ ("1.2345000000000", "1.2345", Equal),
+ (
+ "1.0000000000000000000000000001",
+ "1.0000000000000000000000000000",
+ Greater,
+ ),
+ ("1.0000000000000000000000000000", "1.0000000000000000000000000001", Less),
+ ("-1", "100", Less),
+ ("-100", "1", Less),
+ ("0", "0.5", Less),
+ ("0.5", "0", Greater),
+ ("100", "0.0098", Greater),
+ ("1000000000000000", "999000000000000.0001", Greater),
+ ("2.0001", "2.0001", Equal),
+ (
+ "11.815126050420168067226890757",
+ "0.6386554621848739495798319328",
+ Greater,
+ ),
+ ("0.6386554621848739495798319328", "11.815126050420168067226890757", Less),
+ ("-0.5", "-0.01", Less),
+ ("-0.5", "-0.1", Less),
+ ("-0.01", "-0.5", Greater),
+ ("-0.1", "-0.5", Greater),
+ ];
+ for &(a, b, c) in tests {
+ cmp(a, b, c);
+ }
+}
+
+#[test]
+fn it_floors_decimals() {
+ let tests = &[
+ ("1", "1"),
+ ("1.00", "1"),
+ ("1.2345", "1"),
+ ("-1", "-1"),
+ ("-1.00", "-1"),
+ ("-1.2345", "-2"),
+ ];
+ for &(a, expected) in tests {
+ let a = Decimal::from_str(a).unwrap();
+ assert_eq!(expected, a.floor().to_string(), "Failed flooring {}", a);
+ }
+}
+
+#[test]
+fn it_ceils_decimals() {
+ let tests = &[
+ ("1", "1"),
+ ("1.00", "1"),
+ ("1.2345", "2"),
+ ("-1", "-1"),
+ ("-1.00", "-1"),
+ ("-1.2345", "-1"),
+ ];
+ for &(a, expected) in tests {
+ let a = Decimal::from_str(a).unwrap();
+ assert_eq!(expected, a.ceil().to_string(), "Failed ceiling {}", a);
+ }
+}
+
+#[test]
+fn it_finds_max_of_two() {
+ let tests = &[("1", "1", "1"), ("2", "1", "2"), ("1", "2", "2")];
+ for &(a, b, expected) in tests {
+ let a = Decimal::from_str(a).unwrap();
+ let b = Decimal::from_str(b).unwrap();
+ assert_eq!(expected, a.max(b).to_string());
+ }
+}
+
+#[test]
+fn it_finds_min_of_two() {
+ let tests = &[("1", "1", "1"), ("2", "1", "1"), ("1", "2", "1")];
+ for &(a, b, expected) in tests {
+ let a = Decimal::from_str(a).unwrap();
+ let b = Decimal::from_str(b).unwrap();
+ assert_eq!(expected, a.min(b).to_string());
+ }
+}
+
+#[test]
+fn test_max_compares() {
+ let x = "225.33543601344182".parse::<Decimal>().unwrap();
+ let y = Decimal::max_value();
+ assert!(x < y);
+ assert!(y > x);
+ assert_ne!(y, x);
+}
+
+#[test]
+fn test_min_compares() {
+ let x = "225.33543601344182".parse::<Decimal>().unwrap();
+ let y = Decimal::min_value();
+ assert!(x > y);
+ assert!(y < x);
+ assert_ne!(y, x);
+}
+
+#[test]
+fn it_can_parse_from_i32() {
+ use num_traits::FromPrimitive;
+
+ let tests = &[
+ (0i32, "0"),
+ (1i32, "1"),
+ (-1i32, "-1"),
+ (i32::max_value(), "2147483647"),
+ (i32::min_value(), "-2147483648"),
+ ];
+ for &(input, expected) in tests {
+ let parsed = Decimal::from_i32(input).unwrap();
+ assert_eq!(
+ expected,
+ parsed.to_string(),
+ "expected {} does not match parsed {}",
+ expected,
+ parsed
+ );
+ assert_eq!(
+ input.to_string(),
+ parsed.to_string(),
+ "i32 to_string {} does not match parsed {}",
+ input,
+ parsed
+ );
+ }
+}
+
+#[test]
+fn it_can_parse_from_i64() {
+ use num_traits::FromPrimitive;
+
+ let tests = &[
+ (0i64, "0"),
+ (1i64, "1"),
+ (-1i64, "-1"),
+ (i64::max_value(), "9223372036854775807"),
+ (i64::min_value(), "-9223372036854775808"),
+ ];
+ for &(input, expected) in tests {
+ let parsed = Decimal::from_i64(input).unwrap();
+ assert_eq!(
+ expected,
+ parsed.to_string(),
+ "expected {} does not match parsed {}",
+ expected,
+ parsed
+ );
+ assert_eq!(
+ input.to_string(),
+ parsed.to_string(),
+ "i64 to_string {} does not match parsed {}",
+ input,
+ parsed
+ );
+ }
+}
+
+#[test]
+fn it_can_round_to_2dp() {
+ let a = Decimal::from_str("6.12345").unwrap();
+ let b = (Decimal::from_str("100").unwrap() * a).round() / Decimal::from_str("100").unwrap();
+ assert_eq!("6.12", b.to_string());
+}
+
+#[test]
+fn it_can_round_using_bankers_rounding() {
+ let tests = &[
+ ("6.12345", 2, "6.12"),
+ ("6.126", 2, "6.13"),
+ ("-6.126", 2, "-6.13"),
+ ("6.5", 0, "6"),
+ ("7.5", 0, "8"),
+ ("1.2250", 2, "1.22"),
+ ("1.2252", 2, "1.23"),
+ ("1.2249", 2, "1.22"),
+ ("6.1", 2, "6.1"),
+ ("0.0000", 2, "0.00"),
+ ("0.6666666666666666666666666666", 2, "0.67"),
+ ("1.40", 0, "1"),
+ ("2.60", 0, "3"),
+ ("2.1234567890123456789012345678", 27, "2.123456789012345678901234568"),
+ ];
+ for &(input, dp, expected) in tests {
+ let a = Decimal::from_str(input).unwrap();
+ let b = a.round_dp_with_strategy(dp, RoundingStrategy::BankersRounding);
+ assert_eq!(expected, b.to_string());
+ }
+}
+
+#[test]
+fn it_can_round_complex_numbers_using_bankers_rounding() {
+ // Issue #71
+ let rate = Decimal::new(19, 2); // 0.19
+ let one = Decimal::new(1, 0); // 1
+ let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832
+ let part = part.round_dp_with_strategy(2, RoundingStrategy::BankersRounding); // 0.16
+ assert_eq!("0.16", part.to_string());
+}
+
+#[test]
+fn it_can_round_using_round_half_up() {
+ let tests = &[
+ ("0", 0, "0"),
+ ("1.234", 3, "1.234"),
+ ("1.12", 5, "1.12"),
+ ("6.34567", 2, "6.35"),
+ ("6.5", 0, "7"),
+ ("12.49", 0, "12"),
+ ("0.6666666666666666666666666666", 2, "0.67"),
+ ("1.40", 0, "1"),
+ ("2.60", 0, "3"),
+ ("2.1234567890123456789012345678", 27, "2.123456789012345678901234568"),
+ ];
+ for &(input, dp, expected) in tests {
+ let a = Decimal::from_str(input).unwrap();
+ let b = a.round_dp_with_strategy(dp, RoundingStrategy::RoundHalfUp);
+ assert_eq!(expected, b.to_string());
+ }
+}
+
+#[test]
+fn it_can_round_complex_numbers_using_round_half_up() {
+ // Issue #71
+ let rate = Decimal::new(19, 2); // 0.19
+ let one = Decimal::new(1, 0); // 1
+ let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832
+ let part = part.round_dp_with_strategy(2, RoundingStrategy::RoundHalfUp); // 0.16
+ assert_eq!("0.16", part.to_string());
+}
+
+#[test]
+fn it_can_round_using_round_half_down() {
+ let tests = &[
+ ("0", 0, "0"),
+ ("1.234", 3, "1.234"),
+ ("1.12", 5, "1.12"),
+ ("6.34567", 2, "6.35"),
+ ("6.51", 0, "7"),
+ ("12.5", 0, "12"),
+ ("0.6666666666666666666666666666", 2, "0.67"),
+ ("1.40", 0, "1"),
+ ("2.60", 0, "3"),
+ ("2.1234567890123456789012345678", 27, "2.123456789012345678901234568"),
+ ];
+ for &(input, dp, expected) in tests {
+ let a = Decimal::from_str(input).unwrap();
+ let b = a.round_dp_with_strategy(dp, RoundingStrategy::RoundHalfDown);
+ assert_eq!(expected, b.to_string());
+ }
+}
+
+#[test]
+fn it_can_round_complex_numbers_using_round_half_down() {
+ // Issue #71
+ let rate = Decimal::new(19, 2); // 0.19
+ let one = Decimal::new(1, 0); // 1
+ let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832
+ let part = part.round_dp_with_strategy(2, RoundingStrategy::RoundHalfDown); // 0.16
+ assert_eq!("0.16", part.to_string());
+}
+
+#[test]
+fn it_can_round_to_2dp_using_explicit_function() {
+ let a = Decimal::from_str("6.12345").unwrap();
+ let b = a.round_dp(2u32);
+ assert_eq!("6.12", b.to_string());
+}
+
+#[test]
+fn it_can_round_up_to_2dp_using_explicit_function() {
+ let a = Decimal::from_str("6.126").unwrap();
+ let b = a.round_dp(2u32);
+ assert_eq!("6.13", b.to_string());
+}
+
+#[test]
+fn it_can_round_down_to_2dp_using_explicit_function() {
+ let a = Decimal::from_str("-6.126").unwrap();
+ let b = a.round_dp(2u32);
+ assert_eq!("-6.13", b.to_string());
+}
+
+#[test]
+fn it_can_round_down_using_bankers_rounding() {
+ let a = Decimal::from_str("6.5").unwrap();
+ let b = a.round_dp(0u32);
+ assert_eq!("6", b.to_string());
+}
+
+#[test]
+fn it_can_round_up_using_bankers_rounding() {
+ let a = Decimal::from_str("7.5").unwrap();
+ let b = a.round_dp(0u32);
+ assert_eq!("8", b.to_string());
+}
+
+#[test]
+fn it_can_round_correctly_using_bankers_rounding_1() {
+ let a = Decimal::from_str("1.2250").unwrap();
+ let b = a.round_dp(2u32);
+ assert_eq!("1.22", b.to_string());
+}
+
+#[test]
+fn it_can_round_correctly_using_bankers_rounding_2() {
+ let a = Decimal::from_str("1.2251").unwrap();
+ let b = a.round_dp(2u32);
+ assert_eq!("1.23", b.to_string());
+}
+
+#[test]
+fn it_can_round_down_when_required() {
+ let a = Decimal::from_str("1.2249").unwrap();
+ let b = a.round_dp(2u32);
+ assert_eq!("1.22", b.to_string());
+}
+
+#[test]
+fn it_can_round_to_2dp_using_explicit_function_without_changing_value() {
+ let a = Decimal::from_str("6.1").unwrap();
+ let b = a.round_dp(2u32);
+ assert_eq!("6.1", b.to_string());
+}
+
+#[test]
+fn it_can_round_zero() {
+ let a = Decimal::from_str("0.0000").unwrap();
+ let b = a.round_dp(2u32);
+ assert_eq!("0.00", b.to_string());
+}
+
+#[test]
+fn it_can_round_large_decimals() {
+ let a = Decimal::from_str("0.6666666666666666666666666666").unwrap();
+ let b = a.round_dp(2u32);
+ assert_eq!("0.67", b.to_string());
+}
+
+#[test]
+fn it_can_round_simple_numbers_down() {
+ let a = Decimal::from_str("1.40").unwrap();
+ let b = a.round_dp(0u32);
+ assert_eq!("1", b.to_string());
+}
+
+#[test]
+fn it_can_round_simple_numbers_up() {
+ let a = Decimal::from_str("2.60").unwrap();
+ let b = a.round_dp(0u32);
+ assert_eq!("3", b.to_string());
+}
+
+#[test]
+fn it_can_round_simple_numbers_with_high_precision() {
+ let a = Decimal::from_str("2.1234567890123456789012345678").unwrap();
+ let b = a.round_dp(27u32);
+ assert_eq!("2.123456789012345678901234568", b.to_string());
+}
+
+#[test]
+fn it_can_round_complex_numbers() {
+ // Issue #71
+ let rate = Decimal::new(19, 2); // 0.19
+ let one = Decimal::new(1, 0); // 1
+ let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832
+ let part = part.round_dp(2); // 0.16
+ assert_eq!("0.16", part.to_string());
+}
+
+#[test]
+fn it_can_round_down() {
+ let a = Decimal::new(470, 3).round_dp_with_strategy(1, RoundingStrategy::RoundDown);
+ assert_eq!("0.4", a.to_string());
+}
+
+#[test]
+fn it_only_rounds_down_when_needed() {
+ let a = Decimal::new(400, 3).round_dp_with_strategy(1, RoundingStrategy::RoundDown);
+ assert_eq!("0.4", a.to_string());
+}
+
+#[test]
+fn it_can_round_up() {
+ let a = Decimal::new(320, 3).round_dp_with_strategy(1, RoundingStrategy::RoundUp);
+ assert_eq!("0.4", a.to_string());
+}
+
+#[test]
+fn it_only_rounds_up_when_needed() {
+ let a = Decimal::new(300, 3).round_dp_with_strategy(1, RoundingStrategy::RoundUp);
+ assert_eq!("0.3", a.to_string());
+}
+
+#[test]
+fn it_can_trunc() {
+ let tests = &[("1.00000000000000000000", "1"), ("1.000000000000000000000001", "1")];
+
+ for &(value, expected) in tests {
+ let value = Decimal::from_str(value).unwrap();
+ let expected = Decimal::from_str(expected).unwrap();
+ let trunc = value.trunc();
+ assert_eq!(expected.to_string(), trunc.to_string());
+ }
+}
+
+#[test]
+fn it_can_fract() {
+ let tests = &[
+ ("1.00000000000000000000", "0.00000000000000000000"),
+ ("1.000000000000000000000001", "0.000000000000000000000001"),
+ ];
+
+ for &(value, expected) in tests {
+ let value = Decimal::from_str(value).unwrap();
+ let expected = Decimal::from_str(expected).unwrap();
+ let fract = value.fract();
+ assert_eq!(expected.to_string(), fract.to_string());
+ }
+}
+
+#[test]
+fn it_can_normalize() {
+ let tests = &[
+ ("1.00000000000000000000", "1"),
+ ("1.10000000000000000000000", "1.1"),
+ ("1.00010000000000000000000", "1.0001"),
+ ("1", "1"),
+ ("1.1", "1.1"),
+ ("1.0001", "1.0001"),
+ ("-0", "0"),
+ ("-0.0", "0"),
+ ("-0.010", "-0.01"),
+ ("0.0", "0"),
+ ];
+
+ for &(value, expected) in tests {
+ let value = Decimal::from_str(value).unwrap();
+ let expected = Decimal::from_str(expected).unwrap();
+ let normalized = value.normalize();
+ assert_eq!(expected.to_string(), normalized.to_string());
+ }
+}
+
+#[test]
+fn it_can_return_the_max_value() {
+ assert_eq!("79228162514264337593543950335", Decimal::max_value().to_string());
+}
+
+#[test]
+fn it_can_return_the_min_value() {
+ assert_eq!("-79228162514264337593543950335", Decimal::min_value().to_string());
+}
+
+#[test]
+fn it_can_go_from_and_into() {
+ let d = Decimal::from_str("5").unwrap();
+ let di8 = 5u8.into();
+ let di32 = 5i32.into();
+ let disize = 5isize.into();
+ let di64 = 5i64.into();
+ let du8 = 5u8.into();
+ let du32 = 5u32.into();
+ let dusize = 5usize.into();
+ let du64 = 5u64.into();
+
+ assert_eq!(d, di8);
+ assert_eq!(di8, di32);
+ assert_eq!(di32, disize);
+ assert_eq!(disize, di64);
+ assert_eq!(di64, du8);
+ assert_eq!(du8, du32);
+ assert_eq!(du32, dusize);
+ assert_eq!(dusize, du64);
+}
+
+#[test]
+fn it_converts_to_f64() {
+ assert_eq!(5f64, Decimal::from_str("5").unwrap().to_f64().unwrap());
+ assert_eq!(-5f64, Decimal::from_str("-5").unwrap().to_f64().unwrap());
+ assert_eq!(0.1f64, Decimal::from_str("0.1").unwrap().to_f64().unwrap());
+ assert_eq!(0f64, Decimal::from_str("0.0").unwrap().to_f64().unwrap());
+ assert_eq!(0f64, Decimal::from_str("-0.0").unwrap().to_f64().unwrap());
+ assert_eq!(
+ 0.25e-11f64,
+ Decimal::from_str("0.0000000000025").unwrap().to_f64().unwrap(),
+ );
+ assert_eq!(
+ 1e6f64,
+ Decimal::from_str("1000000.0000000000025").unwrap().to_f64().unwrap()
+ );
+ assert_eq!(
+ 0.25e-25_f64,
+ Decimal::from_str("0.000000000000000000000000025")
+ .unwrap()
+ .to_f64()
+ .unwrap(),
+ );
+ assert_eq!(
+ 2.1234567890123456789012345678_f64,
+ Decimal::from_str("2.1234567890123456789012345678")
+ .unwrap()
+ .to_f64()
+ .unwrap(),
+ );
+
+ assert_eq!(
+ None,
+ // Cannot be represented in an f64
+ Decimal::from_str("21234567890123456789012345678").unwrap().to_f64(),
+ );
+}
+
+#[test]
+fn it_converts_to_i64() {
+ assert_eq!(5i64, Decimal::from_str("5").unwrap().to_i64().unwrap());
+ assert_eq!(-5i64, Decimal::from_str("-5").unwrap().to_i64().unwrap());
+ assert_eq!(5i64, Decimal::from_str("5.12345").unwrap().to_i64().unwrap());
+ assert_eq!(-5i64, Decimal::from_str("-5.12345").unwrap().to_i64().unwrap());
+ assert_eq!(
+ 0x7FFF_FFFF_FFFF_FFFF,
+ Decimal::from_str("9223372036854775807").unwrap().to_i64().unwrap()
+ );
+ assert_eq!(None, Decimal::from_str("92233720368547758089").unwrap().to_i64());
+}
+
+#[test]
+fn it_converts_to_u64() {
+ assert_eq!(5u64, Decimal::from_str("5").unwrap().to_u64().unwrap());
+ assert_eq!(None, Decimal::from_str("-5").unwrap().to_u64());
+ assert_eq!(5u64, Decimal::from_str("5.12345").unwrap().to_u64().unwrap());
+ assert_eq!(
+ 0xFFFF_FFFF_FFFF_FFFF,
+ Decimal::from_str("18446744073709551615").unwrap().to_u64().unwrap()
+ );
+ assert_eq!(None, Decimal::from_str("18446744073709551616").unwrap().to_u64());
+}
+
+#[test]
+fn it_converts_from_f32() {
+ fn from_f32(f: f32) -> Option<Decimal> {
+ num_traits::FromPrimitive::from_f32(f)
+ }
+
+ assert_eq!("1", from_f32(1f32).unwrap().to_string());
+ assert_eq!("0", from_f32(0f32).unwrap().to_string());
+ assert_eq!("0.12345", from_f32(0.12345f32).unwrap().to_string());
+ assert_eq!(
+ "0.12345678",
+ from_f32(0.1234567800123456789012345678f32).unwrap().to_string()
+ );
+ assert_eq!(
+ "0.12345679",
+ from_f32(0.12345678901234567890123456789f32).unwrap().to_string()
+ );
+ assert_eq!("0", from_f32(0.00000000000000000000000000001f32).unwrap().to_string());
+
+ assert!(from_f32(std::f32::NAN).is_none());
+ assert!(from_f32(std::f32::INFINITY).is_none());
+
+ // These both overflow
+ assert!(from_f32(std::f32::MAX).is_none());
+ assert!(from_f32(std::f32::MIN).is_none());
+}
+
+#[test]
+fn it_converts_from_f64() {
+ fn from_f64(f: f64) -> Option<Decimal> {
+ num_traits::FromPrimitive::from_f64(f)
+ }
+
+ assert_eq!("1", from_f64(1f64).unwrap().to_string());
+ assert_eq!("0", from_f64(0f64).unwrap().to_string());
+ assert_eq!("0.12345", from_f64(0.12345f64).unwrap().to_string());
+ assert_eq!(
+ "0.1234567890123456",
+ from_f64(0.1234567890123456089012345678f64).unwrap().to_string()
+ );
+ assert_eq!(
+ "0.1234567890123457",
+ from_f64(0.12345678901234567890123456789f64).unwrap().to_string()
+ );
+ assert_eq!("0", from_f64(0.00000000000000000000000000001f64).unwrap().to_string());
+ assert_eq!("0.6927", from_f64(0.6927f64).unwrap().to_string());
+ assert_eq!("0.00006927", from_f64(0.00006927f64).unwrap().to_string());
+ assert_eq!("0.000000006927", from_f64(0.000000006927f64).unwrap().to_string());
+
+ assert!(from_f64(std::f64::NAN).is_none());
+ assert!(from_f64(std::f64::INFINITY).is_none());
+
+ // These both overflow
+ assert!(from_f64(std::f64::MAX).is_none());
+ assert!(from_f64(std::f64::MIN).is_none());
+}
+
+#[test]
+fn it_handles_simple_underflow() {
+ // Issue #71
+ let rate = Decimal::new(19, 2); // 0.19
+ let one = Decimal::new(1, 0); // 1
+ let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832
+ let result = one * part;
+ assert_eq!("0.1596638655462184873949579832", result.to_string());
+
+ // 169 * 0.1596638655462184873949579832 = 26.983193277310924
+ let result = part * Decimal::new(169, 0);
+ assert_eq!("26.983193277310924369747899161", result.to_string());
+ let result = Decimal::new(169, 0) * part;
+ assert_eq!("26.983193277310924369747899161", result.to_string());
+}
+
+#[test]
+fn it_can_parse_highly_significant_numbers() {
+ let tests = &[
+ ("11.111111111111111111111111111", "11.111111111111111111111111111"),
+ ("11.11111111111111111111111111111", "11.111111111111111111111111111"),
+ ("11.1111111111111111111111111115", "11.111111111111111111111111112"),
+ ("115.111111111111111111111111111", "115.11111111111111111111111111"),
+ ("1115.11111111111111111111111111", "1115.1111111111111111111111111"),
+ ("11.1111111111111111111111111195", "11.111111111111111111111111120"),
+ ("99.9999999999999999999999999995", "100.00000000000000000000000000"),
+ ("-11.1111111111111111111111111195", "-11.111111111111111111111111120"),
+ ("-99.9999999999999999999999999995", "-100.00000000000000000000000000"),
+ ("3.1415926535897932384626433832", "3.1415926535897932384626433832"),
+ (
+ "8808257419827262908.5944405087133154018",
+ "8808257419827262908.594440509",
+ ),
+ (
+ "8097370036018690744.2590371109596744091",
+ "8097370036018690744.259037111",
+ ),
+ (
+ "8097370036018690744.2590371149596744091",
+ "8097370036018690744.259037115",
+ ),
+ (
+ "8097370036018690744.2590371159596744091",
+ "8097370036018690744.259037116",
+ ),
+ ];
+ for &(value, expected) in tests {
+ assert_eq!(expected, Decimal::from_str(value).unwrap().to_string());
+ }
+}
+
+#[test]
+fn it_can_parse_alternative_formats() {
+ let tests = &[
+ ("1_000", "1000"),
+ ("1_000_000", "1000000"),
+ ("10_000_000", "10000000"),
+ ("100_000", "100000"),
+ // At the moment, we'll accept this
+ ("1_____________0", "10"),
+ ];
+ for &(value, expected) in tests {
+ assert_eq!(expected, Decimal::from_str(value).unwrap().to_string());
+ }
+}
+
+#[test]
+fn it_can_parse_fractional_numbers_with_underscore_separators() {
+ let a = Decimal::from_str("0.1_23_456").unwrap();
+ assert_eq!(a.is_sign_negative(), false);
+ assert_eq!(a.scale(), 6);
+ assert_eq!("0.123456", a.to_string());
+}
+
+#[test]
+fn it_can_parse_numbers_with_underscore_separators_before_decimal_point() {
+ let a = Decimal::from_str("1_234.56").unwrap();
+ assert_eq!(a.is_sign_negative(), false);
+ assert_eq!(a.scale(), 2);
+ assert_eq!("1234.56", a.to_string());
+}
+
+#[test]
+fn it_can_parse_numbers_and_round_correctly_with_underscore_separators_before_decimal_point() {
+ let tests = &[
+ (
+ "8_097_370_036_018_690_744.2590371159596744091",
+ "8097370036018690744.259037116",
+ ),
+ (
+ "8097370036018690744.259_037_115_959_674_409_1",
+ "8097370036018690744.259037116",
+ ),
+ (
+ "8_097_370_036_018_690_744.259_037_115_959_674_409_1",
+ "8097370036018690744.259037116",
+ ),
+ ];
+ for &(value, expected) in tests {
+ assert_eq!(expected, Decimal::from_str(value).unwrap().to_string());
+ }
+}
+
+#[test]
+fn it_can_reject_invalid_formats() {
+ let tests = &["_1", "1.0.0", "10_00.0_00.0"];
+ for &value in tests {
+ assert!(
+ Decimal::from_str(value).is_err(),
+ "This succeeded unexpectedly: {}",
+ value
+ );
+ }
+}
+
+#[test]
+fn it_can_reject_large_numbers_with_panic() {
+ let tests = &[
+ // The maximum number supported is 79,228,162,514,264,337,593,543,950,335
+ "79228162514264337593543950336",
+ "79228162514264337593543950337",
+ "79228162514264337593543950338",
+ "79228162514264337593543950339",
+ "79228162514264337593543950340",
+ ];
+ for &value in tests {
+ assert!(
+ Decimal::from_str(value).is_err(),
+ "This succeeded unexpectedly: {}",
+ value
+ );
+ }
+}
+
+#[test]
+fn it_can_parse_individual_parts() {
+ let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28);
+ assert_eq!(pi.to_string(), "3.1415926535897932384626433832");
+}
+
+#[test]
+fn it_can_parse_scientific_notation() {
+ let tests = &[
+ ("9.7e-7", "0.00000097"),
+ ("9e-7", "0.0000009"),
+ ("1.2e10", "12000000000"),
+ ("1.2e+10", "12000000000"),
+ ("12e10", "120000000000"),
+ ("9.7E-7", "0.00000097"),
+ ];
+
+ for &(value, expected) in tests {
+ assert_eq!(expected, Decimal::from_scientific(value).unwrap().to_string());
+ }
+}
+
+#[test]
+fn it_can_parse_different_radix() {
+ use num_traits::Num;
+
+ let tests = &[
+ // Input, Radix, Success, to_string()
+ ("123", 10, true, "123"),
+ ("123", 8, true, "83"),
+ ("123", 16, true, "291"),
+ ("abc", 10, false, ""),
+ ("abc", 16, true, "2748"),
+ ("78", 10, true, "78"),
+ ("78", 8, false, ""),
+ ("101", 2, true, "5"),
+ // Parse base 2
+ ("1111_1111_1111_1111_1111_1111_1111_1111", 2, true, "4294967295"),
+ // Max supported value
+ (
+ "1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_\
+ 1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111",
+ 2,
+ true,
+ &Decimal::max_value().to_string(),
+ ),
+ // We limit to 28 dp
+ (
+ "843.6500000000000000000000000000",
+ 10,
+ true,
+ "843.6500000000000000000000000",
+ ),
+ ];
+
+ for &(input, radix, success, expected) in tests {
+ let result = Decimal::from_str_radix(input, radix);
+ assert_eq!(
+ success,
+ result.is_ok(),
+ "Failed to parse: {} radix {}: {:?}",
+ input,
+ radix,
+ result.err()
+ );
+ if result.is_ok() {
+ assert_eq!(
+ expected,
+ result.unwrap().to_string(),
+ "Original input: {} radix {}",
+ input,
+ radix
+ );
+ }
+ }
+}
+
+#[test]
+fn it_can_calculate_signum() {
+ let tests = &[("123", 1), ("-123", -1), ("0", 0)];
+
+ for &(input, expected) in tests {
+ let input = Decimal::from_str(input).unwrap();
+ assert_eq!(expected, input.signum().to_i32().unwrap(), "Input: {}", input);
+ }
+}
+
+#[test]
+fn it_can_calculate_abs_sub() {
+ let tests = &[
+ ("123", "124", 0),
+ ("123", "123", 0),
+ ("123", "122", 123),
+ ("-123", "-124", 123),
+ ("-123", "-123", 0),
+ ("-123", "-122", 0),
+ ];
+
+ for &(input1, input2, expected) in tests {
+ let input1 = Decimal::from_str(input1).unwrap();
+ let input2 = Decimal::from_str(input2).unwrap();
+ assert_eq!(
+ expected,
+ input1.abs_sub(&input2).to_i32().unwrap(),
+ "Input: {} {}",
+ input1,
+ input2
+ );
+ }
+}
+
+#[test]
+#[should_panic]
+fn it_panics_when_scale_too_large() {
+ let _ = Decimal::new(1, 29);
+}
+
+#[test]
+fn test_zero_eq_negative_zero() {
+ let zero: Decimal = 0.into();
+
+ assert!(zero == zero);
+ assert!(-zero == zero);
+ assert!(zero == -zero);
+}
+
+#[cfg(feature = "postgres")]
+#[test]
+fn to_from_sql() {
+ use bytes::BytesMut;
+ use postgres::types::{FromSql, Kind, ToSql, Type};
+
+ let tests = &[
+ "3950.123456",
+ "3950",
+ "0.1",
+ "0.01",
+ "0.001",
+ "0.0001",
+ "0.00001",
+ "0.000001",
+ "1",
+ "-100",
+ "-123.456",
+ "119996.25",
+ "1000000",
+ "9999999.99999",
+ "12340.56789",
+ "79228162514264337593543950335", // 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF (96 bit)
+ "4951760157141521099596496895", // 0x0FFF_FFFF_FFFF_FFFF_FFFF_FFFF (95 bit)
+ "4951760157141521099596496896", // 0x1000_0000_0000_0000_0000_0000
+ "18446744073709551615",
+ "-18446744073709551615",
+ ];
+
+ let t = Type::new("".into(), 0, Kind::Simple, "".into());
+
+ for test in tests {
+ let input = Decimal::from_str(test).unwrap();
+ let mut bytes = BytesMut::new();
+ input.to_sql(&t, &mut bytes).unwrap();
+ let output = Decimal::from_sql(&t, &bytes).unwrap();
+
+ assert_eq!(input, output);
+ }
+}
+
+fn hash_it(d: Decimal) -> u64 {
+ use std::collections::hash_map::DefaultHasher;
+ use std::hash::Hash;
+ use std::hash::Hasher;
+
+ let mut h = DefaultHasher::new();
+ d.hash(&mut h);
+ h.finish()
+}
+
+#[test]
+fn it_computes_equal_hashes_for_equal_values() {
+ // From the Rust Hash docs:
+ //
+ // "When implementing both Hash and Eq, it is important that the following property holds:
+ //
+ // k1 == k2 -> hash(k1) == hash(k2)"
+
+ let k1 = Decimal::from_str("1").unwrap();
+ let k2 = Decimal::from_str("1.0").unwrap();
+ let k3 = Decimal::from_str("1.00").unwrap();
+ let k4 = Decimal::from_str("1.01").unwrap();
+
+ assert_eq!(k1, k2);
+ assert_eq!(k1, k3);
+ assert_ne!(k1, k4);
+
+ let h1 = hash_it(k1);
+ let h2 = hash_it(k2);
+ let h3 = hash_it(k3);
+ let h4 = hash_it(k4);
+
+ assert_eq!(h1, h2);
+ assert_eq!(h1, h3);
+ assert_ne!(h1, h4);
+
+ // Test the application of Hash calculation to a HashMap.
+
+ use std::collections::HashMap;
+
+ let mut map = HashMap::new();
+
+ map.insert(k1, k1.to_string());
+ // map[k2] should overwrite map[k1] because k1 == k2.
+ map.insert(k2, k2.to_string());
+
+ assert_eq!("1.0", map.get(&k3).expect("could not get k3"));
+ assert_eq!(1, map.len());
+
+ // map[k3] should overwrite map[k2] because k3 == k2.
+ map.insert(k3, k3.to_string());
+ // map[k4] should not overwrite map[k3] because k4 != k3.
+ map.insert(k4, k4.to_string());
+
+ assert_eq!(2, map.len());
+ assert_eq!("1.00", map.get(&k1).expect("could not get k1"));
+}
+
+#[test]
+fn it_computes_equal_hashes_for_positive_and_negative_zero() {
+ // Verify 0 and -0 have the same hash
+ let k1 = Decimal::from_str("0").unwrap();
+ let k2 = Decimal::from_str("-0").unwrap();
+ assert_eq!("-0", k2.to_string());
+ assert_eq!(k1, k2);
+ let h1 = hash_it(k1);
+ let h2 = hash_it(k2);
+ assert_eq!(h1, h2);
+
+ // Verify 0 and -0.0 have the same hash
+ let k1 = Decimal::from_str("0").unwrap();
+ let k2 = Decimal::from_str("-0.0").unwrap();
+ assert_eq!("-0.0", k2.to_string());
+ assert_eq!(k1, k2);
+ let h1 = hash_it(k1);
+ let h2 = hash_it(k2);
+ assert_eq!(h1, h2);
+}
+
+#[test]
+#[should_panic]
+fn it_handles_i128_min() {
+ Decimal::from_i128_with_scale(std::i128::MIN, 0);
+}
+
+#[test]
+fn it_can_rescale() {
+ let tests = &[
+ ("0", 6, "0.000000"),
+ ("0.000000", 2, "0.00"),
+ ("0.12345600000", 6, "0.123456"),
+ ("0.123456", 12, "0.123456000000"),
+ ("0.123456", 0, "0"),
+ ("0.000001", 4, "0.0000"),
+ ("1233456", 4, "1233456.0000"),
+ ("1.2", 30, "1.2000000000000000000000000000"),
+ ("79228162514264337593543950335", 0, "79228162514264337593543950335"),
+ ("4951760157141521099596496895", 1, "4951760157141521099596496895.0"),
+ ("4951760157141521099596496896", 1, "4951760157141521099596496896.0"),
+ ("18446744073709551615", 6, "18446744073709551615.000000"),
+ ("-18446744073709551615", 6, "-18446744073709551615.000000"),
+ ];
+
+ for &(value_raw, new_scale, expected_value) in tests {
+ let new_value = Decimal::from_str(expected_value).unwrap();
+ let mut value = Decimal::from_str(value_raw).unwrap();
+ value.rescale(new_scale);
+ assert_eq!(new_value.to_string(), value.to_string());
+ }
+}