1# Decimal   [![Build Status]][actions] [![Latest Version]][crates.io] [![Docs Badge]][docs] 2 3[Build Status]: https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fpaupino%2Frust-decimal%2Fbadge&label=build&logo=none 4[actions]: https://actions-badge.atrox.dev/paupino/rust-decimal/goto 5[Latest Version]: https://img.shields.io/crates/v/rust-decimal.svg 6[crates.io]: https://crates.io/crates/rust-decimal 7[Docs Badge]: https://docs.rs/rust_decimal/badge.svg 8[docs]: https://docs.rs/rust_decimal 9 10A Decimal implementation written in pure Rust suitable for financial calculations that require significant integral and fractional digits with no round-off errors. 11 12The 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. 13 14## Getting started 15 16To get started, add `rust_decimal` and optionally `rust_decimal_macros` to your `Cargo.toml`: 17 18```toml 19[dependencies] 20rust_decimal = "1.20" 21rust_decimal_macros = "1.20" 22``` 23 24## Usage 25 26Decimal 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: 27 28```rust 29// Procedural macros need importing directly 30use rust_decimal_macros::dec; 31 32let number = dec!(-1.23); 33assert_eq!("-1.23", number.to_string()); 34``` 35 36Alternatively you can also use one of the Decimal number convenience functions: 37 38```rust 39// Using the prelude can help importing trait based functions (e.g. core::str::FromStr). 40use rust_decimal::prelude::*; 41 42// Using an integer followed by the decimal points 43let scaled = Decimal::new(202, 2); 44assert_eq!("2.02", scaled.to_string()); 45 46// From a string representation 47let from_string = Decimal::from_str("2.02").unwrap(); 48assert_eq!("2.02", from_string.to_string()); 49 50// From a string representation in a different base 51let from_string_base16 = Decimal::from_str_radix("ffff", 16).unwrap(); 52assert_eq!("65535", from_string_base16.to_string()); 53 54// Using the `Into` trait 55let my_int: Decimal = 3i32.into(); 56assert_eq!("3", my_int.to_string()); 57 58// Using the raw decimal representation 59let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28); 60assert_eq!("3.1415926535897932384626433832", pi.to_string()); 61``` 62 63Once you have instantiated your `Decimal` number you can perform calculations with it just like any other number: 64 65```rust 66use rust_decimal::prelude::*; 67 68let amount = Decimal::from_str("25.12").unwrap(); 69let tax = Decimal::from_str("0.085").unwrap(); 70let total = amount + (amount * tax).round_dp(2); 71assert_eq!(total.to_string(), "27.26"); 72``` 73 74## Features 75 76**Behavior / Functionality** 77 78* [c-repr](#c-repr) 79* [legacy-ops](#legacy-ops) 80* [maths](#maths) 81* [rocket-traits](#rocket-traits) 82* [rust-fuzz](#rust-fuzz) 83* [std](#std) 84 85**Database** 86 87* [db-postgres](#db-postgres) 88* [db-tokio-postgres](#db-tokio-postgres) 89* [db-diesel-postgres](#db-diesel-postgres) 90* [db-diesel-mysql](#db-diesel-mysql) 91 92**Serde** 93 94* [serde-float](#serde-float) 95* [serde-str](#serde-str) 96* [serde-arbitrary-precision](#serde-arbitrary-precision) 97* [serde-with-float](#serde-with-float) 98* [serde-with-str](#serde-with-str) 99* [serde-with-arbitrary-precision](#serde-with-arbitrary-precision) 100 101### `c-repr` 102 103Forces `Decimal` to use `[repr(C)]`. The corresponding target layout is 128 bit aligned. 104 105### `db-postgres` 106 107This feature enables a PostgreSQL communication module. It allows for reading and writing the `Decimal` 108type by transparently serializing/deserializing into the `NUMERIC` data type within PostgreSQL. 109 110### `db-tokio-postgres` 111 112Enables the tokio postgres module allowing for async communication with PostgreSQL. 113 114### `db-diesel-postgres` 115 116Enable `diesel` PostgreSQL support. 117 118### `db-diesel-mysql` 119 120Enable `diesel` MySQL support. 121 122### `legacy-ops` 123 124As of `1.10` the algorithms used to perform basic operations have changed which has benefits of significant speed improvements. 125To maintain backwards compatibility this can be opted out of by enabling the `legacy-ops` feature. 126 127### `maths` 128 129The `maths` feature enables additional complex mathematical functions such as `pow`, `ln`, `enf`, `exp` etc. 130Documentation detailing the additional functions can be found on the 131[`MathematicalOps`](https://docs.rs/rust_decimal/latest/rust_decimal/trait.MathematicalOps.html) trait. 132 133Please note that `ln` and `log10` will panic on invalid input with `checked_ln` and `checked_log10` the preferred functions 134to curb against this. When the `maths` feature was first developed the library would return `0` on invalid input. To re-enable this 135non-panicking behavior, please use the feature: `maths-nopanic`. 136 137### `rocket-traits` 138 139Enable support for Rocket forms by implementing the `FromFormField` trait. 140 141### `rust-fuzz` 142 143Enable `rust-fuzz` support by implementing the `Arbitrary` trait. 144 145### `serde-float` 146 147**Note:** it is recommended to use the `serde-with-*` features for greater control. This allows configurability at the data 148level. 149 150Enable this so that JSON serialization of `Decimal` types are sent as a float instead of a string (default). 151 152e.g. with this turned on, JSON serialization would output: 153```json 154{ 155 "value": 1.234 156} 157``` 158 159### `serde-str` 160 161**Note:** it is recommended to use the `serde-with-*` features for greater control. This allows configurability at the data 162level. 163 164This is typically useful for `bincode` or `csv` like implementations. 165 166Since `bincode` does not specify type information, we need to ensure that a type hint is provided in order to 167correctly be able to deserialize. Enabling this feature on its own will force deserialization to use `deserialize_str` 168instead of `deserialize_any`. 169 170If, for some reason, you also have `serde-float` enabled then this will use `deserialize_f64` as a type hint. Because 171converting to `f64` _loses_ precision, it's highly recommended that you do NOT enable this feature when working with 172`bincode`. That being said, this will only use 8 bytes so is slightly more efficient in terms of storage size. 173 174### `serde-arbitrary-precision` 175 176**Note:** it is recommended to use the `serde-with-*` features for greater control. This allows configurability at the data 177level. 178 179This is used primarily with `serde_json` and consequently adds it as a "weak dependency". This supports the 180`arbitrary_precision` feature inside `serde_json` when parsing decimals. 181 182This is recommended when parsing "float" looking data as it will prevent data loss. 183 184### `serde-with-float` 185 186Enable this to access the module for serialising `Decimal` types to a float. This can be use in `struct` definitions like so: 187 188```rust 189#[derive(Serialize, Deserialize)] 190pub struct FloatExample { 191 #[serde(with = "rust_decimal::serde::float")] 192 value: Decimal, 193} 194``` 195 196### `serde-with-str` 197 198Enable this to access the module for serialising `Decimal` types to a `String`. This can be use in `struct` definitions like so: 199 200```rust 201#[derive(Serialize, Deserialize)] 202pub struct StrExample { 203 #[serde(with = "rust_decimal::serde::str")] 204 value: Decimal, 205} 206``` 207 208### `serde-with-arbitrary-precision` 209 210Enable this to access the module for serialising `Decimal` types to a `String`. This can be use in `struct` definitions like so: 211 212```rust 213#[derive(Serialize, Deserialize)] 214pub struct ArbitraryExample { 215 #[serde(with = "rust_decimal::serde::arbitrary_precision")] 216 value: Decimal, 217} 218``` 219 220 221### `std` 222 223Enable `std` library support. This is enabled by default, however in the future will be opt in. For now, to support `no_std` 224libraries, this crate can be compiled with `--no-default-features`. 225 226## Building 227 228Please refer to the [Build document](BUILD.md) for more information on building and testing Rust Decimal. 229 230## Minimum Rust Compiler Version 231 232The current _minimum_ compiler version is [`1.51.0`](https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1510-2021-03-25) 233which was released on `2021-03-25` and included support for "const generics". 234 235### Updating the minimum supported version 236 237This library maintains support for rust compiler versions that are 5 minor versions away from the current stable rust compiler version. 238For example, if the current stable compiler version is `1.50.0` then we will guarantee support up to and including `1.45.0`. 239Of note, we will only update the minimum supported version if and when required. 240