# The `d*!` macros
The crate exposes one proc-macro per public width — `d9!`, `d18!`,
`d38!`, plus `d76!` / `d153!` / `d307!` under the wide-tier feature
flags. Each parses a numeric literal (or inline expression),
picks or is told a scale, and expands to a
`D<N><SCALE>::from_bits(...)` call. There is no runtime parsing and
the scale lands in the type.
This page focuses on `d38!` because most examples in the crate use
the 128-bit tier; everything below applies identically to the other
entry points (substitute `MAX_SCALE` per-width). The full
specification — including radix-prefix integers and the curated
per-scale wrappers (`d38s12!`, `d18s6!`, …) — lives in
[`macros/README.md`](../macros/README.md).
Enable the macros with the `macros` feature (off by default):
```toml
[dependencies]
decimal-scaled = { version = "0.2.3", features = ["macros"] }
```
```rust
use decimal_scaled::d38;
```
## Automatic scale inference
With no qualifier, the scale is the number of fractional digits you
wrote — trailing zeros are significant:
```rust
# use decimal_scaled::d38;
# use decimal_scaled::{D38, D38s0, D38s2, D38s5};
let a = d38!(1.23); // D38<2>
let b = d38!(123); // D38<0>
let c = d38!(1.0); // D38<1> — the written `.0` counts
let d = d38!(1.230); // D38<3> — trailing zero preserved
let e = d38!(0.001); // D38<3>
let f = d38!(-1.23); // D38<2>
let g = d38!(1_234.567_89); // D38<5> — underscores allowed
# assert_eq!(a, D38s2::from_bits(123));
# assert_eq!(b, D38s0::from_bits(123));
```
## Scientific notation
`e` notation is supported; the resulting scale is whatever is needed to
represent the value exactly:
```rust
# use decimal_scaled::d38;
# use decimal_scaled::{D38, D38s0};
let a = d38!(1.5e3); // 1500 -> D38<0>
let b = d38!(1.5e-3); // 0.0015 -> D38<4>
let c = d38!(1e6); // 1000000 -> D38<0>
let d = d38!(-2.5e-2); // -0.025 -> D38<3>
# assert_eq!(a, D38s0::from_bits(1500));
```
## The `scale N` qualifier
Force a specific target scale. Scaling *up* pads with zeros (lossless):
```rust
# use decimal_scaled::d38;
# use decimal_scaled::D38;
let a = d38!(1.23, scale 4); // D38<4>, raw 12_300
let b = d38!(42, scale 0); // D38<0>, raw 42
let c = d38!(1.5e3, scale 5); // D38<5>, raw 150_000_000
```
Scaling *down* with `scale N` alone is a compile error if it would lose
digits — add `rounded` to opt in.
## The `rounded` qualifier
Combine with `scale N` to round (half-to-even) when the target scale has
fewer digits than the literal:
```rust
# use decimal_scaled::d38;
# use decimal_scaled::D38s2;
let a = d38!(1.234999, scale 2, rounded); // 1.23
let b = d38!(1.235001, scale 2, rounded); // 1.24
let c = d38!(1.235, scale 2, rounded); // 1.24 (tie -> even)
let d = d38!(1.225, scale 2, rounded); // 1.22 (tie -> even)
# assert_eq!(a, D38s2::from_bits(123));
```
## Inline expressions
The first argument can be an integer expression; combine with
`scale N` to land it in a typed `D38`:
```rust
# use decimal_scaled::d38;
# use decimal_scaled::{D38, D38s0};
let a = d38!(10 * 12 + 3, scale 0); // D38<0>, raw 123
let b = d38!(5, scale 4); // D38<4>, raw 50_000
# assert_eq!(a, D38s0::from_bits(123));
```
---
# How the type family is generated — the `decl_*!` macros
This section is for *contributors*, not users of the crate.
Hand-writing six near-identical impl surfaces (`D9` … `D307`) would be
unmaintainable, so the per-width surface is generated by a family of
internal declarative macros in `src/macros/`. Each file owns one
surface — `arithmetic.rs`, `basics.rs`, `conversions.rs`, `display.rs`,
`overflow.rs`, `rescale.rs`, … — and exports one `decl_decimal_*!`
macro. `core_type.rs` is then largely a list of macro invocations, one
group per width:
```rust,ignore
crate::macros::basics::decl_decimal_basics!(D38, i128, 38);
crate::macros::arithmetic::decl_decimal_arithmetic!(D18, i64, i128);
crate::macros::basics::decl_decimal_basics!(wide D76, crate::wide::I256, 76);
```
Most macros have two front-end arms:
- a **native** arm for primitive-integer storage (`i32` / `i64` /
`i128`), which uses `as`-casts and integer literals;
- a **`wide`** arm for the in-tree wide-integer storage (`D76` /
`D153` / `D307`), which has no `as`-casts from literals — it builds
constants via `from_str_radix` and widens via `crate::wide_int::wide_cast`.
Both arms forward to a shared `@impl` / `@common` arm wherever the logic
is genuinely identical, so each operation is written once.
The discipline: anything uniform across widths lives in a macro;
anything genuinely width-specific (e.g. `D38`'s hand-rolled
`mg_divide` multiply/divide path) stays hand-coded. See
[`macros/README.md`](../macros/README.md) for the full specification.