Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Macros: remove circular dependency from macros feature #644

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ proptest = { default-features = false, optional = true, features = ["std"], vers
rand = { default-features = false, optional = true, version = "0.8" }
rkyv = { default-features = false, features = ["size_32", "std"], optional = true, version = "0.7.42" }
rocket = { default-features = false, optional = true, version = "0.5.0-rc.3" }
#rust_decimal_macros = { default-features = false, optional = true, version = "1.34" } # This needs to a published version
rust_decimal_macros = { default-features = false, optional = true, path = "macros" }
serde = { default-features = false, optional = true, version = "1.0" }
serde_json = { default-features = false, optional = true, version = "1.0" }
tokio-postgres = { default-features = false, optional = true, version = "0.7" }
Expand All @@ -44,16 +44,15 @@ criterion = { default-features = false, version = "0.5" }
csv = "1"
futures = { default-features = false, version = "0.3" }
rand = { default-features = false, features = ["getrandom"], version = "0.8" }
rust_decimal_macros = { default-features = false, version = "1.33" }
rust_decimal_macros = { default-features = false, path = "macros" }
serde = { default-features = false, features = ["derive"], version = "1.0" }
serde_json = "1.0"
tokio = { default-features = false, features = ["macros", "rt-multi-thread", "test-util"], version = "1.0" }
version-sync = { default-features = false, features = ["html_root_url_updated", "markdown_deps_updated"], version = "0.9" }

[features]
default = ["serde", "std"]
# Removed in 1.34.2 due to an issue during version resolution
#macros = ["dep:rust_decimal_macros"]
macros = ["dep:rust_decimal_macros"]

borsh = ["dep:borsh", "std"]
c-repr = [] # Force Decimal to be repr(C)
Expand Down Expand Up @@ -94,6 +93,6 @@ path = "benches/comparison.rs"
[workspace]
members = [
".",
"./macros"
"macros"
]
resolver = "2"
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,27 @@ The binary representation consists of a 96 bit integer number, a scaling factor
$ cargo add rust_decimal
```

In addition, if you would like to use the optimized macro for convenient creation of decimals:
If you would like to use the optimized macro for convenient creation of decimals you can add `rust_decimal` with the `macros` feature flag:

```sh
$ cargo add rust_decimal_macros
$ cargo add rust_decimal --features macros
```

Alternatively, you can edit your `Cargo.toml` directly and run `cargo update`:

```toml
[dependencies]
rust_decimal = "1.34"
rust_decimal_macros = "1.34"
rust_decimal = { version = "1.34", features = ["macros"] }
```

## Usage

Decimal numbers can be created in a few distinct ways. The easiest and most efficient method of creating a Decimal is to use the procedural macro that can be enabled using the `macros` feature:

```rust
// Import the `rust_decimal_macros` crate and use the macro directly from there.
// The macros feature exposes a `dec` macro which will parse the input into a raw decimal number at compile time.
// It is also exposed when using `rust_decimal::prelude::*`. That said, you can also import the
// `rust_decimal_macros` crate and use the macro directly from there.
use rust_decimal_macros::dec;

let number = dec!(-1.23) + dec!(3.45);
Expand Down
38 changes: 38 additions & 0 deletions benches/lib_benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,24 @@ const SAMPLE_STRS: &[&str] = &[
"12340.56789",
];

const SAMPLE_SCIENTIFIC_STRS: &[&str] = &[
"3950123456e-6",
"3950e0",
"1e-1",
"1e-2",
"1e-3",
"1e-4",
"1e-5",
"1e-6",
"1e0",
"-1e2",
"-12.3456e1",
"1.1999625e7",
"1e6",
"9.99999999999e12",
"1.234056789e9",
];

#[bench]
fn serialize_bincode(b: &mut test::Bencher) {
let decimals: Vec<Decimal> = SAMPLE_STRS.iter().map(|s| Decimal::from_str(s).unwrap()).collect();
Expand Down Expand Up @@ -198,6 +216,26 @@ fn decimal_from_str(b: &mut test::Bencher) {
})
}

#[bench]
fn decimal_from_str_exact(b: &mut test::Bencher) {
b.iter(|| {
for s in SAMPLE_STRS {
let result = Decimal::from_str_exact(s).unwrap();
test::black_box(result);
}
})
}

#[bench]
fn decimal_scientific_from_str(b: &mut test::Bencher) {
b.iter(|| {
for s in SAMPLE_SCIENTIFIC_STRS {
let result = Decimal::from_scientific(s).unwrap();
test::black_box(result);
}
})
}

#[bench]
fn decimal_to_string(b: &mut test::Bencher) {
let decimals: Vec<Decimal> = SAMPLE_STRS.iter().map(|s| Decimal::from_str(s).unwrap()).collect();
Expand Down
3 changes: 1 addition & 2 deletions examples/serde-json-scenarios/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ publish = false
[workspace]

[dependencies]
rust_decimal = { path = "../..", features = ["serde-with-arbitrary-precision"] }
rust_decimal_macros = { path = "../../macros" }
rust_decimal = { path = "../..", features = ["serde-with-arbitrary-precision", "macros"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["arbitrary_precision"]}
1 change: 0 additions & 1 deletion examples/serde-json-scenarios/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use rust_decimal::prelude::*;
use rust_decimal_macros::dec;

type ExampleResult = Result<(), Box<dyn std::error::Error>>;

Expand Down
2 changes: 1 addition & 1 deletion macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ categories = ["science","data-structures"]
license = "MIT"

[dependencies]
rust_decimal = { version = "1.33", default-features = false }
quote = "1.0"

[dev-dependencies]
rust_decimal = { path = ".." }
trybuild = "1.0.55"

[features]
Expand Down
70 changes: 59 additions & 11 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@
//! ```
//!

mod parser;

use proc_macro::TokenStream;
use quote::quote;
use rust_decimal::Decimal;

/// Convenience function for creating decimal numbers
///
Expand Down Expand Up @@ -64,25 +65,44 @@ pub fn dec(input: TokenStream) -> TokenStream {
}

let decimal = if source.contains('e') || source.contains('E') {
match Decimal::from_scientific(&source[..]) {
match parser::parse_scientific(&source[..]) {
Ok(d) => d,
Err(e) => panic!("{}", e),
}
} else {
match Decimal::from_str_exact(&source[..]) {
match parser::parse_radix_10_exact(&source[..]) {
Ok(d) => d,
Err(e) => panic!("{}", e),
}
};
let lo = decimal.lo();
let mid = decimal.mid();
let hi = decimal.hi();
if mid == 0 && hi == 0 {
match (lo, decimal.scale, decimal.negative) {
(0, 0, _) => return constant(Constant::Zero),
(1, 0, false) => return constant(Constant::One),
(1, 0, true) => return constant(Constant::NegativeOne),
(2, 0, false) => return constant(Constant::Two),
(10, 0, false) => return constant(Constant::Ten),
(100, 0, false) => return constant(Constant::OneHundred),
(1000, 0, false) => return constant(Constant::OneThousand),
_ => {}
}
}

let unpacked = decimal.unpack();
expand(
unpacked.lo,
unpacked.mid,
unpacked.hi,
unpacked.negative,
unpacked.scale,
)
expand(lo, mid, hi, decimal.negative, decimal.scale)
}

#[derive(Debug)]
enum Constant {
Zero,
One,
Two,
Ten,
OneHundred,
OneThousand,
NegativeOne,
}

#[cfg(not(feature = "reexportable"))]
Expand All @@ -100,3 +120,31 @@ fn expand(lo: u32, mid: u32, hi: u32, negative: bool, scale: u32) -> TokenStream
};
expanded.into()
}

#[cfg(not(feature = "reexportable"))]
fn constant(constant: Constant) -> TokenStream {
match constant {
Constant::Zero => quote! { ::rust_decimal::Decimal::ZERO },
Constant::One => quote! { ::rust_decimal::Decimal::ONE },
Constant::Two => quote! { ::rust_decimal::Decimal::TWO },
Constant::Ten => quote! { ::rust_decimal::Decimal::TEN },
Constant::OneHundred => quote! { ::rust_decimal::Decimal::ONE_HUNDRED },
Constant::OneThousand => quote! { ::rust_decimal::Decimal::ONE_THOUSAND },
Constant::NegativeOne => quote! { ::rust_decimal::Decimal::NEGATIVE_ONE },
}
.into()
}

#[cfg(feature = "reexportable")]
fn constant(constant: Constant) -> TokenStream {
match constant {
Constant::Zero => quote! { Decimal::ZERO },
Constant::One => quote! { Decimal::ONE },
Constant::Two => quote! { Decimal::TWO },
Constant::Ten => quote! { Decimal::TEN },
Constant::OneHundred => quote! { Decimal::ONE_HUNDRED },
Constant::OneThousand => quote! { Decimal::ONE_THOUSAND },
Constant::NegativeOne => quote! { Decimal::NEGATIVE_ONE },
}
.into()
}
1 change: 1 addition & 0 deletions macros/src/parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../parser/mod.rs"));
2 changes: 1 addition & 1 deletion macros/tests/invalid/large_scale.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ error: proc macro panicked
4 | let _ = dec!(0.00000_00000_00000_00000_00000_0001);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Number has a high precision that can not be represented.
= help: message: number has a high precision that can not be represented
2 changes: 1 addition & 1 deletion macros/tests/invalid/too_big.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ error: proc macro panicked
4 | let _ = dec!(79_228_162_514_264_337_593_543_950_336);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Invalid decimal: overflow from too many digits
= help: message: overflow from too many digits
2 changes: 1 addition & 1 deletion macros/tests/invalid/too_small.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ error: proc macro panicked
4 | let _ = dec!(-79_228_162_514_264_337_593_543_950_336);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Invalid decimal: overflow from too many digits
= help: message: overflow from too many digits
7 changes: 7 additions & 0 deletions macros/tests/macro_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ fn it_can_parse_standard_decimal() {
(dec!(-1.23), "-1.23"),
(dec!(1.1234567890123456789012345678), "1.1234567890123456789012345678"),
(dec!(1_000_000), "1000000"),
(dec!(0), "0"),
(dec!(1), "1"),
(dec!(2), "2"),
(dec!(10), "10"),
(dec!(100), "100"),
(dec!(1000), "1000"),
(dec!(-1), "-1"),
];
for &(a, b) in tests {
assert_eq!(a.to_string(), b);
Expand Down
Loading
Loading