Skip to main content

decimal_scaled/types/
widths.rs

1// SPDX-FileCopyrightText: 2026 John Moxley
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Core type definitions for every decimal width and their scale aliases.
5//!
6//! Each width is a `#[repr(transparent)]` newtype around an integer
7//! storage of the matching size. The stored integer equals
8//! `actual_value * 10^SCALE`. Widths:
9//!
10//! `MAX_SCALE = name - 1` for every width (the scale cap guaranteeing
11//! at least one integer digit of headroom at every legal `SCALE`):
12//!
13//! | Type | Storage | `MAX_SCALE` |
14//! |------|---------|-------------|
15//! | [`D18<SCALE>`] | `i64`             | 17  |
16//! | [`D38<SCALE>`] | `i128`            | 37  |
17//! | [`D76<SCALE>`] | `crate::int::types::Int<4>` | 75 |
18//! | [`D153<SCALE>`] | `crate::int::types::Int<8>` | 152 |
19//! | [`D307<SCALE>`] | `crate::int::types::Int<16>` | 306 |
20//!
21//! The `#[repr(transparent)]` annotation is load-bearing: it guarantees
22//! the same ABI as the underlying integer, so `from_bits` / `to_bits`
23//! round-trips are exact and the types are safe to embed in C-ABI
24//! plugin payloads when the underlying integer matches a primitive.
25
26/// Scaled fixed-point decimal with 128-bit storage. A type alias
27/// of the unified [`crate::D`] generic decimal type: `D38<S>` is
28/// `D<i128, S>`. Both spellings are interchangeable.
29///
30/// `SCALE` is the base-10 exponent. A logical value `v` is stored as
31/// `v * 10^SCALE` in the underlying `i128`. For example, with `SCALE = 12`
32/// the number `1.5` is stored as `i128(1_500_000_000_000)`.
33///
34/// The `#[repr(transparent)]` layout over `i128` is preserved through
35/// the alias because the underlying [`crate::D`] is itself
36/// `#[repr(transparent)]` over its storage parameter.
37///
38/// # Precision
39///
40/// N/A: type definition, no arithmetic performed.
41///
42/// # Determinism
43///
44/// All arithmetic is integer arithmetic on `i128`. The same inputs produce
45/// the same bit-pattern on every platform.
46///
47/// # Equality and ordering
48///
49/// `Hash`, `Eq`, and `Ord` are derived from `i128`. Two `D38<S>` values
50/// are equal if and only if their underlying `i128` fields are bit-equal.
51/// This works because the scale is fixed at compile time -- each logical
52/// value has exactly one representation.
53///
54/// # Const-generic scale
55///
56/// The const generic allows scale variants (`D38<9>`, `D38<6>`, etc.)
57/// as trivial type aliases without duplicating any method implementations.
58/// Mixed-scale arithmetic is deliberately not provided; callers convert
59/// explicitly.
60pub type D38<const SCALE: u32> = crate::D<crate::int::types::Int<2>, SCALE>;
61
62// Manual `Debug` is implemented in `display.rs` (via the
63// `decl_decimal_display!` macro) and renders via `Display` so the
64// canonical decimal string is shown rather than the raw i128.
65
66/// `Default` returns `ZERO`, matching `i128::default() == 0`.
67///
68/// This lets `#[derive(Default)]` work correctly on structs that contain
69/// `D38<S>` fields.
70///
71/// Implemented on the underlying `crate::D<decimal_scaled::Int<2>, SCALE>` because
72/// `D38<SCALE>` is an alias of that type. `ZERO` is emitted by
73/// the basics macro further down in this file.
74impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<2>, SCALE> {
75    #[inline]
76    fn default() -> Self {
77        Self::ZERO
78    }
79}
80
81// Scale aliases: D38s0 through D38s38.
82//
83// Each alias names a specific SCALE value. The const-generic impl block
84// makes every method generic, so adding aliases is purely additive.
85//
86// Representable integer range is approximately `i128::MAX / 10^SCALE`.
87// `i128::MAX` is approximately 1.7e38.
88//
89// SCALE = 0 is supported (mg_divide special-cases it to plain i128
90// arithmetic). SCALE = 38 is the upper bound: 10^38 < i128::MAX, but
91// 10^39 overflows. The math constants (pi, tau, e, golden) have a
92// 35-digit reference in consts.rs (SCALE_REF = 35); at SCALE > 35
93// they are zero-extended and gain no real precision.
94
95/// Scale alias: `D38<0>`. 1 LSB = 1 (thin `i128` wrapper, no rescale).
96/// Range ~+/-1.7e38.
97///
98/// # Precision
99///
100/// N/A: constant value, no arithmetic performed.
101pub type D38s0 = D38<0>;
102
103/// Scale alias: `D38<1>`. 1 LSB = 10^-1 (1 decimal digit).
104/// Range ~+/-1.7e37.
105///
106/// # Precision
107///
108/// N/A: constant value, no arithmetic performed.
109pub type D38s1 = D38<1>;
110
111/// Scale alias: `D38<2>`. 1 LSB = 10^-2 (cents). Range ~+/-1.7e36.
112///
113/// # Precision
114///
115/// N/A: constant value, no arithmetic performed.
116pub type D38s2 = D38<2>;
117
118/// Scale alias: `D38<3>`. 1 LSB = 10^-3 (thousandths; 1 mm at m units).
119/// Range ~+/-1.7e35.
120///
121/// # Precision
122///
123/// N/A: constant value, no arithmetic performed.
124pub type D38s3 = D38<3>;
125
126/// Scale alias: `D38<4>`. 1 LSB = 10^-4 (basis points). Range ~+/-1.7e34.
127///
128/// # Precision
129///
130/// N/A: constant value, no arithmetic performed.
131pub type D38s4 = D38<4>;
132
133/// Scale alias: `D38<5>`. 1 LSB = 10^-5. Range ~+/-1.7e33.
134///
135/// # Precision
136///
137/// N/A: constant value, no arithmetic performed.
138pub type D38s5 = D38<5>;
139
140/// Scale alias: `D38<6>`. 1 LSB = 10^-6 (1 um at mm units; ppm).
141/// Range ~+/-1.7e32.
142///
143/// # Precision
144///
145/// N/A: constant value, no arithmetic performed.
146pub type D38s6 = D38<6>;
147
148/// Scale alias: `D38<7>`. 1 LSB = 10^-7. Range ~+/-1.7e31.
149///
150/// # Precision
151///
152/// N/A: constant value, no arithmetic performed.
153pub type D38s7 = D38<7>;
154
155/// Scale alias: `D38<8>`. 1 LSB = 10^-8 (satoshi-grade). Range ~+/-1.7e30.
156///
157/// # Precision
158///
159/// N/A: constant value, no arithmetic performed.
160pub type D38s8 = D38<8>;
161
162/// Scale alias: `D38<9>`. 1 LSB = 10^-9 (1 nm at mm units; ppb).
163/// Range ~+/-1.7e29.
164///
165/// # Precision
166///
167/// N/A: constant value, no arithmetic performed.
168pub type D38s9 = D38<9>;
169
170/// Scale alias: `D38<10>`. 1 LSB = 10^-10. Range ~+/-1.7e28.
171///
172/// # Precision
173///
174/// N/A: constant value, no arithmetic performed.
175pub type D38s10 = D38<10>;
176
177/// Scale alias: `D38<11>`. 1 LSB = 10^-11. Range ~+/-1.7e27.
178///
179/// # Precision
180///
181/// N/A: constant value, no arithmetic performed.
182pub type D38s11 = D38<11>;
183
184/// Scale alias: `D38<12>`. 1 LSB = 10^-12 (1 pm at mm units).
185/// Range ~+/-1.7e14 model units.
186///
187/// This is the primary concrete alias for general use. At `SCALE = 12`:
188/// - 1 LSB is `10^-12` model units.
189/// - The representable integer range is approximately +/-1.7e14 model units.
190/// - Squared-component operations (e.g. dot products) overflow beyond
191/// roughly 13,000 km at mm units.
192///
193/// # Precision
194///
195/// N/A: constant value, no arithmetic performed.
196pub type D38s12 = D38<12>;
197
198/// Scale alias: `D38<13>`. 1 LSB = 10^-13. Range ~+/-1.7e25.
199///
200/// # Precision
201///
202/// N/A: constant value, no arithmetic performed.
203pub type D38s13 = D38<13>;
204
205/// Scale alias: `D38<14>`. 1 LSB = 10^-14. Range ~+/-1.7e24.
206///
207/// # Precision
208///
209/// N/A: constant value, no arithmetic performed.
210pub type D38s14 = D38<14>;
211
212/// Scale alias: `D38<15>`. 1 LSB = 10^-15 (femto). Range ~+/-1.7e23.
213///
214/// # Precision
215///
216/// N/A: constant value, no arithmetic performed.
217pub type D38s15 = D38<15>;
218
219/// Scale alias: `D38<16>`. 1 LSB = 10^-16. Range ~+/-1.7e22.
220///
221/// # Precision
222///
223/// N/A: constant value, no arithmetic performed.
224pub type D38s16 = D38<16>;
225
226/// Scale alias: `D38<17>`. 1 LSB = 10^-17. Range ~+/-1.7e21.
227///
228/// # Precision
229///
230/// N/A: constant value, no arithmetic performed.
231pub type D38s17 = D38<17>;
232
233/// Scale alias: `D38<18>`. 1 LSB = 10^-18 (atto; high-precision scientific).
234/// Range ~+/-1.7e20.
235///
236/// # Precision
237///
238/// N/A: constant value, no arithmetic performed.
239pub type D38s18 = D38<18>;
240
241/// Scale alias: `D38<19>`. 1 LSB = 10^-19. Range ~+/-1.7e19.
242///
243/// # Precision
244///
245/// N/A: constant value, no arithmetic performed.
246pub type D38s19 = D38<19>;
247
248/// Scale alias: `D38<20>`. 1 LSB = 10^-20. Range ~+/-1.7e18.
249///
250/// # Precision
251///
252/// N/A: constant value, no arithmetic performed.
253pub type D38s20 = D38<20>;
254
255/// Scale alias: `D38<21>`. 1 LSB = 10^-21 (zepto). Range ~+/-1.7e17.
256///
257/// # Precision
258///
259/// N/A: constant value, no arithmetic performed.
260pub type D38s21 = D38<21>;
261
262/// Scale alias: `D38<22>`. 1 LSB = 10^-22. Range ~+/-1.7e16.
263///
264/// # Precision
265///
266/// N/A: constant value, no arithmetic performed.
267pub type D38s22 = D38<22>;
268
269/// Scale alias: `D38<23>`. 1 LSB = 10^-23. Range ~+/-1.7e15.
270///
271/// # Precision
272///
273/// N/A: constant value, no arithmetic performed.
274pub type D38s23 = D38<23>;
275
276/// Scale alias: `D38<24>`. 1 LSB = 10^-24 (yocto). Range ~+/-1.7e14.
277///
278/// # Precision
279///
280/// N/A: constant value, no arithmetic performed.
281pub type D38s24 = D38<24>;
282
283/// Scale alias: `D38<25>`. 1 LSB = 10^-25. Range ~+/-1.7e13.
284///
285/// # Precision
286///
287/// N/A: constant value, no arithmetic performed.
288pub type D38s25 = D38<25>;
289
290/// Scale alias: `D38<26>`. 1 LSB = 10^-26. Range ~+/-1.7e12.
291///
292/// # Precision
293///
294/// N/A: constant value, no arithmetic performed.
295pub type D38s26 = D38<26>;
296
297/// Scale alias: `D38<27>`. 1 LSB = 10^-27. Range ~+/-1.7e11.
298///
299/// # Precision
300///
301/// N/A: constant value, no arithmetic performed.
302pub type D38s27 = D38<27>;
303
304/// Scale alias: `D38<28>`. 1 LSB = 10^-28. Range ~+/-1.7e10.
305///
306/// # Precision
307///
308/// N/A: constant value, no arithmetic performed.
309pub type D38s28 = D38<28>;
310
311/// Scale alias: `D38<29>`. 1 LSB = 10^-29. Range ~+/-1.7e9.
312///
313/// # Precision
314///
315/// N/A: constant value, no arithmetic performed.
316pub type D38s29 = D38<29>;
317
318/// Scale alias: `D38<30>`. 1 LSB = 10^-30. Range ~+/-1.7e8.
319///
320/// # Precision
321///
322/// N/A: constant value, no arithmetic performed.
323pub type D38s30 = D38<30>;
324
325/// Scale alias: `D38<31>`. 1 LSB = 10^-31. Range ~+/-1.7e7.
326///
327/// # Precision
328///
329/// N/A: constant value, no arithmetic performed.
330pub type D38s31 = D38<31>;
331
332/// Scale alias: `D38<32>`. 1 LSB = 10^-32. Range ~+/-1.7e6.
333///
334/// # Precision
335///
336/// N/A: constant value, no arithmetic performed.
337pub type D38s32 = D38<32>;
338
339/// Scale alias: `D38<33>`. 1 LSB = 10^-33. Range ~+/-1.7e5.
340///
341/// # Precision
342///
343/// N/A: constant value, no arithmetic performed.
344pub type D38s33 = D38<33>;
345
346/// Scale alias: `D38<34>`. 1 LSB = 10^-34. Range ~+/-1.7e4.
347///
348/// # Precision
349///
350/// N/A: constant value, no arithmetic performed.
351pub type D38s34 = D38<34>;
352
353/// Scale alias: `D38<35>`. 1 LSB = 10^-35. Range ~+/-1.7e3.
354///
355/// Matches `SCALE_REF` in `consts.rs`: the math constants `pi`, `tau`,
356/// `e`, and `golden` are stored at this reference scale internally, so
357/// at `SCALE = 35` they round-trip without precision loss.
358///
359/// # Precision
360///
361/// N/A: constant value, no arithmetic performed.
362pub type D38s35 = D38<35>;
363
364/// Scale alias: `D38<36>`. 1 LSB = 10^-36. Range ~+/-170.
365///
366/// The math constants (`pi`, `tau`, `e`, `golden`) are stored at a
367/// 35-digit reference. Above `SCALE = 35` they are scaled up from that
368/// reference, so trailing digits are zero-extended rather than
369/// meaningfully precise.
370///
371/// # Precision
372///
373/// N/A: constant value, no arithmetic performed.
374pub type D38s36 = D38<36>;
375
376/// Scale alias: `D38<37>`. 1 LSB = 10^-37. Range ~+/-17.
377///
378/// This is the maximum supported scale: `MAX_SCALE = 37` guarantees at
379/// least one integer digit (`|x| >= 1`) for every representable value.
380/// `10^38 < i128::MAX < 10^39`, so the storage could in principle hold a
381/// scale-38 representation, but doing so would leave `|x| < 1.7` with no
382/// integer-digit headroom -- the scale cap rules this out by design.
383/// Math constants lose precision above `SCALE = 35`; see `D38s36`.
384///
385/// # Precision
386///
387/// N/A: constant value, no arithmetic performed.
388pub type D38s37 = D38<37>;
389
390// The `ParseError` enum lives in `src/error.rs` and is re-exported
391// from the crate root. It is not width-specific.
392pub use crate::support::error::ParseError;
393
394// Inherent basics + Decimal trait impl: emitted by the macro generator
395// (one invocation per width). See src/decimal_macro.rs for the macro
396// definition and the surface it produces.
397crate::macros::basics::decl_decimal_basics!(wide D38, crate::int::types::Int<2>, 37);
398crate::macros::display::decl_decimal_display!(wide D38, crate::int::types::Uint<2>);
399// FromStr and the raw-storage hex / octal / binary formatters: the
400// shared macros. D38's hand-coded versions were equivalent (`FromStr`
401// delegated to the same `parse_decimal` path; the formatters delegate
402// straight to the `i128` formatter).
403crate::macros::from_str::decl_decimal_from_str!(wide D38, crate::int::types::Int<2>);
404crate::macros::storage_formatters::decl_decimal_storage_formatters!(D38);
405// Bitwise operators (BitAnd/Or/Xor/Not, Shl/Shr) and bit-manipulation
406// methods (unsigned_shr, rotate_*, *_zeros, count_*, *_power_of_two) on
407// the raw storage. A shared macro gives every width the surface.
408crate::macros::bitwise::decl_decimal_bitwise!(wide D38, crate::int::types::Int<2>);
409// Euclidean / floor / ceil division, abs_diff, midpoint, and the
410// is_zero / is_normal / is_nan / is_infinite / is_finite predicates.
411crate::macros::int_methods::decl_decimal_int_methods!(wide D38, crate::int::types::Int<2>);
412// FromPrimitive / ToPrimitive / NumCast via the shared macro.
413crate::macros::num_traits::decl_decimal_num_traits_conversions!(wide D38, crate::int::types::Int<2>);
414crate::macros::float_bridge::decl_decimal_float_bridge!(wide D38, crate::int::types::Int<2>);
415crate::macros::conversions::decl_try_from_primitive!(wide D38, crate::int::types::Int<2>, i8);
416crate::macros::conversions::decl_try_from_primitive!(wide D38, crate::int::types::Int<2>, i16);
417crate::macros::conversions::decl_try_from_primitive!(wide D38, crate::int::types::Int<2>, i32);
418crate::macros::conversions::decl_try_from_primitive!(wide D38, crate::int::types::Int<2>, i64);
419crate::macros::conversions::decl_try_from_primitive!(wide D38, crate::int::types::Int<2>, u8);
420crate::macros::conversions::decl_try_from_primitive!(wide D38, crate::int::types::Int<2>, u16);
421crate::macros::conversions::decl_try_from_primitive!(wide D38, crate::int::types::Int<2>, u32);
422crate::macros::conversions::decl_try_from_primitive!(wide D38, crate::int::types::Int<2>, u64);
423crate::macros::conversions::decl_try_from_i128!(wide D38, crate::int::types::Int<2>);
424crate::macros::conversions::decl_try_from_u128!(wide D38, crate::int::types::Int<2>);
425crate::macros::conversions::decl_try_from_i128!(wide D18, crate::int::types::Int<1>);
426crate::macros::conversions::decl_try_from_u128!(wide D18, crate::int::types::Int<1>);
427// D18 (i64 storage): `i64` / `u64` get a dedicated `TryFrom` here rather
428// than going through `decl_try_from_primitive!` because `value * 10^SCALE`
429// overflows the 64-bit storage for SCALE >= 1 (and a `u64` above
430// `i64::MAX` overflows even at SCALE 0). The wider tiers (D38+) get their
431// `i64` / `u64` `TryFrom` from `decl_try_from_primitive!`, so wiring these
432// only for D18 keeps any `(Src, Dest)` pair from getting two impls.
433crate::macros::conversions::decl_try_from_i64!(wide D18, crate::int::types::Int<1>);
434crate::macros::conversions::decl_try_from_u64!(wide D18, crate::int::types::Int<1>);
435crate::macros::conversions::decl_try_from_f64!(wide D38, crate::int::types::Int<2>);
436crate::macros::conversions::decl_try_from_f32!(wide D38, crate::int::types::Int<2>);
437crate::macros::conversions::decl_try_from_f64!(wide D18, crate::int::types::Int<1>);
438crate::macros::conversions::decl_try_from_f32!(wide D18, crate::int::types::Int<1>);
439crate::macros::conversions::decl_decimal_int_conversion_methods!(wide D38, crate::int::types::Int<2>);
440// abs / signum / is_positive / is_negative, min / max / clamp / recip /
441// copysign, and floor / ceil / round / trunc / fract are emitted by the
442// shared macros — D38's hand-coded versions were byte-identical to the
443// macro output (see `src/macros/{sign,helpers,rounding_methods}.rs`).
444crate::macros::sign::decl_decimal_sign_methods!(wide D38, crate::int::types::Int<2>);
445crate::macros::helpers::decl_decimal_helpers!(wide D38);
446crate::macros::rounding_methods::decl_decimal_rounding_methods!(wide D38);
447// Overflow-variant families for add / sub / neg / rem: the macro's
448// shared `@common` arm. D38's hand-coded versions were byte-identical.
449// The mul / div variants come from the macro's `wide` arm, which runs
450// the intermediate product/quotient in the `$Wider` integer.
451crate::macros::overflow::decl_decimal_overflow_variants!(wide D38, crate::int::types::Int<2>, crate::int::types::Int<4>);
452// Add / Sub / Neg / Rem operator impls (and their `*Assign` forms): the
453// arithmetic macro's shared `@common` arm. Mul / Div come from the
454// macro's `wide` arm (the `$Wider` 256-bit-widening path).
455crate::macros::arithmetic::decl_decimal_arithmetic!(wide D38, crate::int::types::Int<2>, crate::int::types::Int<4>);
456// num-traits: Zero / One / Num / Bounded / Signed / Checked{Add,Sub,Mul,
457// Div,Rem,Neg} via the shared macro — D38's hand-coded impls were
458// equivalent. FromPrimitive / ToPrimitive / NumCast come from
459// `decl_decimal_num_traits_conversions!` above.
460crate::macros::num_traits::decl_decimal_num_traits_basics!(D38);
461crate::macros::transcendental_trait::decl_decimal_transcendental_impl!(D38);
462
463// D38 strict transcendentals: hand-tuned per-type kernels.
464//
465// The canonical public `*_strict` surface (`ln_strict`, `exp_strict`,
466// `sin_strict`, `powf_strict`, …) is emitted by the per-type files
467// `types/log_exp.rs` / `types/trig.rs` / `types/powers.rs` using
468// the hand-tuned 256-bit `algos::support::fixed::Fixed` work integer. They
469// are the **chosen winners** per the per-type-kernel policy:
470//
471// - `decl_wide_transcendental!(D38, crate::int::types::Int<2>, Int<8>, …)` would deliver
472//   the same surface using the generic limb arithmetic. Bench
473//   analysis (ln 29 µs hand-tuned vs ≈ 100+ µs macro path) puts the
474//   macro firmly past the 1.5× crossover, so the hand-tuned kernel
475//   wins.
476//
477// The alternative macro implementation is **not compiled** in normal
478// builds — invoking the macro here unconditionally would emit
479// duplicate-name methods that conflict with the canonical override.
480// Under a future `bench-alt` feature the macro can be re-invoked
481// with a renamed-suffix shape (`*_strict_macro_alt`) so a benchmark
482// can compare both paths in one binary; until that knob exists the
483// macro path stays dormant for D38.
484//
485// Same naming convention applies to per-type lossy overrides as
486// they land: `*_lossy_override` opt-in companion, canonical name
487// reserved for the chosen-winner implementation.
488
489crate::macros::conversions::decl_decimal_int_conversion_methods!(wide D18, crate::int::types::Int<1>);
490
491// ─── D38 narrow ───────────────────────────────────────────────────────
492// D38::widen is wide-tier-only and is emitted further down in the
493// wide block. D38::narrow is always available.
494
495impl<const SCALE: u32> crate::D<crate::int::types::Int<2>, SCALE> {
496    /// Demote to the previous storage tier ([`D18`]) at the same
497    /// `SCALE`. Returns `Err(ConvertError::OutOfRange)` if the value
498    /// doesn't fit `i64`'s range at the given scale.
499    ///
500    /// ```
501    /// use decimal_scaled::D38s9;
502    /// let a = D38s9::try_from(1_000_000).unwrap();
503    /// let b = a.narrow().unwrap();
504    /// assert_eq!(i128::from(b.to_bits()), i128::from(a.to_bits()));
505    /// ```
506    #[inline]
507    pub fn narrow(self) -> Result<crate::D<crate::int::types::Int<1>, SCALE>, crate::support::error::ConvertError> {
508        self.try_into()
509    }
510}
511
512// ---------------------------------------------------------------------
513// D18 — 64-bit storage, scale 0..=18. Interchange size; fits a GPR on
514// 64-bit hosts and maps cleanly to ANSI / SQL `DECIMAL(18, S)` columns.
515// ---------------------------------------------------------------------
516
517/// Scaled fixed-point decimal with 64-bit storage. See [`D38`] for the
518/// shape documentation; D18 has the same surface scaled to `i64` and
519/// `MAX_SCALE = 17` (the scale cap: `MAX_SCALE = name - 1`).
520///
521/// A type alias of the unified [`crate::D`] generic decimal type:
522/// `D18<S>` is `D<i64, S>`. Both spellings are interchangeable. The
523/// `#[repr(transparent)]` layout over `i64` is preserved through the
524/// alias because the underlying [`crate::D`] is itself
525/// `#[repr(transparent)]` over its storage parameter.
526pub type D18<const SCALE: u32> = crate::D<crate::int::types::Int<1>, SCALE>;
527
528/// `Default` returns `ZERO`.
529///
530/// Implemented on the underlying `crate::D<Int<1>, SCALE>` because
531/// `D18<SCALE>` is an alias of that type. `ZERO` is emitted by
532/// the basics macro further down in this file.
533impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<1>, SCALE> {
534    #[inline]
535    fn default() -> Self {
536        Self::ZERO
537    }
538}
539
540crate::macros::basics::decl_decimal_basics!(wide D18, crate::int::types::Int<1>, 17);
541crate::macros::arithmetic::decl_decimal_arithmetic!(wide D18, crate::int::types::Int<1>, crate::int::types::Int<2>);
542crate::macros::conversions::decl_try_from_primitive!(wide D18, crate::int::types::Int<1>, i8);
543crate::macros::conversions::decl_try_from_primitive!(wide D18, crate::int::types::Int<1>, i16);
544crate::macros::conversions::decl_try_from_primitive!(wide D18, crate::int::types::Int<1>, i32);
545crate::macros::conversions::decl_try_from_primitive!(wide D18, crate::int::types::Int<1>, u8);
546crate::macros::conversions::decl_try_from_primitive!(wide D18, crate::int::types::Int<1>, u16);
547crate::macros::conversions::decl_try_from_primitive!(wide D18, crate::int::types::Int<1>, u32);
548crate::macros::display::decl_decimal_display!(wide D18, crate::int::types::Uint<1>);
549crate::macros::overflow::decl_decimal_overflow_variants!(wide D18, crate::int::types::Int<1>, crate::int::types::Int<2>);
550crate::macros::num_traits::decl_decimal_num_traits_basics!(D18);
551crate::macros::sign::decl_decimal_sign_methods!(wide D18, crate::int::types::Int<1>);
552// D18 (Int<1>) `DecimalConstants` comes from the single generic impl in
553// `src/types/consts/d38.rs` (sourced from the unified `consts` table) — no
554// per-tier macro invocation.
555crate::macros::from_str::decl_decimal_from_str!(wide D18, crate::int::types::Int<1>);
556crate::macros::float_bridge::decl_decimal_float_bridge!(wide D18, crate::int::types::Int<1>);
557crate::macros::storage_formatters::decl_decimal_storage_formatters!(D18);
558crate::macros::strict_transcendentals::decl_strict_transcendentals_via_d38!(D18);
559crate::macros::transcendental_trait::decl_decimal_transcendental_impl!(D18);
560crate::macros::fast_transcendentals::decl_fast_transcendentals_via_f64!(D18);
561crate::macros::pow::decl_decimal_pow!(D18);
562crate::macros::rounding_methods::decl_decimal_rounding_methods!(wide D18);
563crate::macros::helpers::decl_decimal_helpers!(wide D18);
564crate::macros::bitwise::decl_decimal_bitwise!(wide D18, crate::int::types::Int<1>);
565crate::macros::int_methods::decl_decimal_int_methods!(wide D18, crate::int::types::Int<1>);
566crate::macros::num_traits::decl_decimal_num_traits_conversions!(wide D18, crate::int::types::Int<1>);
567
568// Cross-width widening (lossless). D18 -> D38.
569crate::macros::conversions::decl_cross_width_widening!(wide D38, crate::int::types::Int<2>, D18, crate::int::types::Int<1>);
570
571// Cross-width narrowing (fallible). D38 -> D18.
572crate::macros::conversions::decl_cross_width_narrowing!(wide D18, crate::int::types::Int<1>, D38, crate::int::types::Int<2>);
573
574// ─── `widen` — hop one storage tier up ────────────────────────────────
575//
576// `widen` always succeeds (the next-larger storage strictly covers every
577// value the smaller one can hold). It keeps the scale unchanged; combine
578// with `rescale` if you need to change scale and width together. D18 is
579// the narrowest tier, so it has no `narrow`.
580
581impl<const SCALE: u32> crate::D<crate::int::types::Int<1>, SCALE> {
582    /// Promote to the next storage tier ([`D38`]) at the same `SCALE`.
583    /// Lossless.
584    ///
585    /// ```
586    /// use decimal_scaled::D18s9;
587    /// let a = D18s9::try_from(7).unwrap();
588    /// let b = a.widen();              // D38<9>
589    /// assert_eq!(i128::from(b.to_bits()), i128::from(a.to_bits()));
590    /// ```
591    #[inline]
592    #[must_use]
593    pub fn widen(self) -> crate::D<crate::int::types::Int<2>, SCALE> {
594        self.into()
595    }
596}
597
598/// Scale alias: `D18<0>`. 1 LSB = 1. Range ±9.2 × 10¹⁸.
599pub type D18s0 = D18<0>;
600/// Scale alias: `D18<1>`. 1 LSB = 10^-1. Range ±9.2 × 10¹⁷.
601pub type D18s1 = D18<1>;
602/// Scale alias: `D18<2>`. 1 LSB = 10^-2 (cents). Range ±9.2 × 10¹⁶.
603pub type D18s2 = D18<2>;
604/// Scale alias: `D18<3>`. 1 LSB = 10^-3 (mills). Range ±9.2 × 10¹⁵.
605pub type D18s3 = D18<3>;
606/// Scale alias: `D18<4>`. 1 LSB = 10^-4 (basis points). Range ±9.2 × 10¹⁴.
607pub type D18s4 = D18<4>;
608/// Scale alias: `D18<5>`. 1 LSB = 10^-5. Range ±9.2 × 10¹³.
609pub type D18s5 = D18<5>;
610/// Scale alias: `D18<6>`. 1 LSB = 10^-6 (ppm). Range ±9.2 × 10¹².
611pub type D18s6 = D18<6>;
612/// Scale alias: `D18<7>`. 1 LSB = 10^-7. Range ±9.2 × 10¹¹.
613pub type D18s7 = D18<7>;
614/// Scale alias: `D18<8>`. 1 LSB = 10^-8 (satoshi). Range ±9.2 × 10¹⁰.
615pub type D18s8 = D18<8>;
616/// Scale alias: `D18<9>`. 1 LSB = 10^-9 (nano). Range ±9.2 × 10⁹.
617pub type D18s9 = D18<9>;
618/// Scale alias: `D18<10>`. 1 LSB = 10^-10. Range ±9.2 × 10⁸.
619pub type D18s10 = D18<10>;
620/// Scale alias: `D18<11>`. 1 LSB = 10^-11. Range ±9.2 × 10⁷.
621pub type D18s11 = D18<11>;
622/// Scale alias: `D18<12>`. 1 LSB = 10^-12 (pico). Range ±9.2 × 10⁶.
623pub type D18s12 = D18<12>;
624/// Scale alias: `D18<13>`. 1 LSB = 10^-13. Range ±9.2 × 10⁵.
625pub type D18s13 = D18<13>;
626/// Scale alias: `D18<14>`. 1 LSB = 10^-14. Range ±9.2 × 10⁴.
627pub type D18s14 = D18<14>;
628/// Scale alias: `D18<15>`. 1 LSB = 10^-15 (femto). Range ±9200.
629pub type D18s15 = D18<15>;
630/// Scale alias: `D18<16>`. 1 LSB = 10^-16. Range ±920.
631pub type D18s16 = D18<16>;
632/// Scale alias: `D18<17>`. 1 LSB = 10^-17. Range ±92.
633///
634/// Maximum supported scale (scale cap: `MAX_SCALE = name - 1`
635/// guarantees at least one integer digit at every legal SCALE).
636pub type D18s17 = D18<17>;
637
638// ---------------------------------------------------------------------
639// D76 — 256-bit storage (`Int<4>`), scale 0..=76. First of the
640// wide tier; gated behind the `d76` / `wide` Cargo features. Covers
641// the full IEEE-754 decimal128 range and gives 35-digit fractional
642// precision with integer-part headroom (see research doc §1).
643// ---------------------------------------------------------------------
644
645/// Scaled fixed-point decimal with 256-bit storage. See [`D38`] for the
646/// shape documentation; D76 has the same surface scaled to a 256-bit
647/// signed integer and `MAX_SCALE = 75`. A type alias of the unified
648/// [`crate::D`] generic decimal type: `D76<S>` is
649/// `D<crate::int::types::Int<4>, S>`. Both spellings are interchangeable.
650///
651/// The `#[repr(transparent)]` layout over `Int<4>` is preserved through
652/// the alias because the underlying [`crate::D`] is itself
653/// `#[repr(transparent)]` over its storage parameter.
654///
655/// Gated behind the `d76` (or umbrella `wide`) Cargo feature. The
656/// storage backend is `Int<4>`.
657#[cfg(any(feature = "d76", feature = "wide"))]
658pub type D76<const SCALE: u32> = crate::D<crate::int::types::Int<4>, SCALE>;
659
660/// `Default` returns `ZERO`, matching the all-zero limb pattern of
661/// `Int<4>`.
662///
663/// Implemented on the underlying `crate::D<crate::int::types::Int<4>, SCALE>`
664/// because `D76<SCALE>` is an alias of that type. `ZERO` is emitted
665/// by the basics macro further down in this file.
666#[cfg(any(feature = "d76", feature = "wide"))]
667impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<4>, SCALE> {
668    #[inline]
669    fn default() -> Self {
670        Self::ZERO
671    }
672}
673
674#[cfg(any(feature = "d76", feature = "wide"))]
675crate::macros::full::decl_decimal_full!(
676    wide D76,
677    crate::int::types::Int<4>,
678    crate::int::types::Uint<4>,
679    crate::int::types::Int<8>,
680    crate::int::types::Int<8>,
681    crate::int::types::Int<16>,
682    crate::int::types::Int<16>,
683    crate::int::types::Int<32>,
684    crate::int::types::Int<16>,
685    wide_trig_d76,
686    75,
687    4,
688    400,
689    512
690);
691// Cross-width widening into D76 (lossless): D18 / D38 -> D76.
692#[cfg(any(feature = "d76", feature = "wide"))]
693#[cfg(any(feature = "d76", feature = "wide"))]
694crate::macros::conversions::decl_cross_width_widening!(wide D76, crate::int::types::Int<4>, D18, crate::int::types::Int<1>);
695#[cfg(any(feature = "d76", feature = "wide"))]
696crate::macros::conversions::decl_cross_width_widening!(wide D76, crate::int::types::Int<4>, D38, crate::int::types::Int<2>);
697// Cross-width narrowing from D76 (fallible): D76 -> D38 / D18.
698#[cfg(any(feature = "d76", feature = "wide"))]
699crate::macros::conversions::decl_cross_width_narrowing!(wide D38, crate::int::types::Int<2>, D76, crate::int::types::Int<4>);
700#[cfg(any(feature = "d76", feature = "wide"))]
701crate::macros::conversions::decl_cross_width_narrowing!(wide D18, crate::int::types::Int<1>, D76, crate::int::types::Int<4>);
702#[cfg(any(feature = "d76", feature = "wide"))]
703
704// ─── D38::widen / D76 hop methods ─────────────────────────────────────
705
706#[cfg(any(feature = "d57", feature = "wide"))]
707impl<const SCALE: u32> crate::D<crate::int::types::Int<2>, SCALE> {
708    /// Promote to the next storage tier ([`D57`]) at the same `SCALE`.
709    /// Lossless. Available with the `d57` (or umbrella `wide`) Cargo
710    /// feature enabled.
711    ///
712    /// ```
713    /// # #[cfg(feature = "wide")] {
714    /// use decimal_scaled::D38s12;
715    /// let a = D38s12::try_from(1_000_000).unwrap();
716    /// let _wider = a.widen();  // D57<12>
717    /// # }
718    /// ```
719    #[inline]
720    #[must_use]
721    pub fn widen(self) -> crate::D<crate::int::types::Int<3>, SCALE> {
722        self.into()
723    }
724}
725
726#[cfg(all(
727    any(feature = "d76", feature = "wide"),
728    any(feature = "d57", feature = "wide"),
729))]
730impl<const SCALE: u32> crate::D<crate::int::types::Int<4>, SCALE> {
731    /// Demote to the previous storage tier ([`D57`]) at the same
732    /// `SCALE`. Returns `Err(ConvertError::Overflow)` if the value
733    /// doesn't fit `D57`'s range at the given scale.
734    #[inline]
735    pub fn narrow(self) -> Result<crate::D<crate::int::types::Int<3>, SCALE>, crate::support::error::ConvertError> {
736        self.try_into()
737    }
738}
739
740/// Scale alias: `D76<0>`. 1 LSB = 1 (256-bit integer ledger).
741#[cfg(any(feature = "d76", feature = "wide"))]
742pub type D76s0 = D76<0>;
743/// Scale alias: `D76<1>`. 1 LSB = 10^-1 (tenths).
744#[cfg(any(feature = "d76", feature = "wide"))]
745pub type D76s1 = D76<1>;
746/// Scale alias: `D76<2>`. 1 LSB = 10^-2 (cents).
747#[cfg(any(feature = "d76", feature = "wide"))]
748pub type D76s2 = D76<2>;
749#[cfg(any(feature = "d76", feature = "wide"))]
750pub type D76s3 = D76<3>;
751#[cfg(any(feature = "d76", feature = "wide"))]
752pub type D76s4 = D76<4>;
753/// Scale alias: `D76<6>`. 1 LSB = 10^-6 (ppm).
754#[cfg(any(feature = "d76", feature = "wide"))]
755pub type D76s6 = D76<6>;
756#[cfg(any(feature = "d76", feature = "wide"))]
757pub type D76s9 = D76<9>;
758/// Scale alias: `D76<12>`. 1 LSB = 10^-12 (pico; financial standard).
759#[cfg(any(feature = "d76", feature = "wide"))]
760pub type D76s12 = D76<12>;
761#[cfg(any(feature = "d76", feature = "wide"))]
762pub type D76s15 = D76<15>;
763/// Scale alias: `D76<18>`. 1 LSB = 10^-18 (atto).
764#[cfg(any(feature = "d76", feature = "wide"))]
765pub type D76s18 = D76<18>;
766#[cfg(any(feature = "d76", feature = "wide"))]
767pub type D76s20 = D76<20>;
768#[cfg(any(feature = "d76", feature = "wide"))]
769pub type D76s24 = D76<24>;
770#[cfg(any(feature = "d76", feature = "wide"))]
771pub type D76s28 = D76<28>;
772#[cfg(any(feature = "d76", feature = "wide"))]
773pub type D76s32 = D76<32>;
774/// Scale alias: `D76<35>`. 1 LSB = 10^-35 (matches `SCALE_REF`).
775#[cfg(any(feature = "d76", feature = "wide"))]
776pub type D76s35 = D76<35>;
777#[cfg(any(feature = "d76", feature = "wide"))]
778pub type D76s38 = D76<38>;
779#[cfg(any(feature = "d76", feature = "wide"))]
780pub type D76s42 = D76<42>;
781#[cfg(any(feature = "d76", feature = "wide"))]
782pub type D76s48 = D76<48>;
783/// Scale alias: `D76<50>`. 1 LSB = 10^-50 (deep scientific precision).
784#[cfg(any(feature = "d76", feature = "wide"))]
785pub type D76s50 = D76<50>;
786#[cfg(any(feature = "d76", feature = "wide"))]
787pub type D76s56 = D76<56>;
788#[cfg(any(feature = "d76", feature = "wide"))]
789pub type D76s64 = D76<64>;
790#[cfg(any(feature = "d76", feature = "wide"))]
791pub type D76s70 = D76<70>;
792/// Scale alias: `D76<75>`. 1 LSB = 10^-75. Maximum supported scale
793/// (scale cap: `MAX_SCALE = name - 1`).
794#[cfg(any(feature = "d76", feature = "wide"))]
795pub type D76s75 = D76<75>;
796
797// ---------------------------------------------------------------------
798// D153 — 512-bit storage (`Int<8>`), scale 0..=153. Wide-scientific
799// tier; gated behind the `d153` / `wide` Cargo features.
800// ---------------------------------------------------------------------
801
802/// Scaled fixed-point decimal with 512-bit storage. See [`D38`] for the
803/// shape documentation; D153 has the same surface scaled to a 512-bit
804/// signed integer and `MAX_SCALE = 152`. A type alias of the unified
805/// [`crate::D`] generic decimal type: `D153<S>` is
806/// `D<crate::int::types::Int<8>, S>`. Both spellings are interchangeable.
807///
808/// The `#[repr(transparent)]` layout over `Int<8>` is preserved through
809/// the alias because the underlying [`crate::D`] is itself
810/// `#[repr(transparent)]` over its storage parameter.
811///
812/// Gated behind the `d153` (or umbrella `wide`) Cargo feature. The
813/// storage backend is `Int<8>`.
814#[cfg(any(feature = "d153", feature = "wide"))]
815pub type D153<const SCALE: u32> = crate::D<crate::int::types::Int<8>, SCALE>;
816
817/// `Default` returns `ZERO`, matching the all-zero limb pattern of
818/// `Int<8>`.
819///
820/// Implemented on the underlying `crate::D<crate::int::types::Int<8>, SCALE>`
821/// because `D153<SCALE>` is an alias of that type. `ZERO` is emitted
822/// by the basics macro further down in this file.
823#[cfg(any(feature = "d153", feature = "wide"))]
824impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<8>, SCALE> {
825    #[inline]
826    fn default() -> Self {
827        Self::ZERO
828    }
829}
830
831#[cfg(any(feature = "d153", feature = "wide"))]
832crate::macros::full::decl_decimal_full!(
833    wide D153,
834    crate::int::types::Int<8>,
835    crate::int::types::Uint<8>,
836    crate::int::types::Int<16>,
837    crate::int::types::Int<16>,
838    crate::int::types::Int<32>,
839    crate::int::types::Int<32>,
840    crate::int::types::Int<64>,
841    crate::int::types::Int<32>,
842    wide_trig_d153,
843    152,
844    8,
845    200,
846    512
847);
848// Cross-width widening into D153 (lossless): D38 / D76 -> D153.
849#[cfg(any(feature = "d153", feature = "wide"))]
850crate::macros::conversions::decl_cross_width_widening!(wide D153, crate::int::types::Int<8>, D38, crate::int::types::Int<2>);
851#[cfg(all(
852    any(feature = "d153", feature = "wide"),
853    any(feature = "d76", feature = "wide")
854))]
855crate::macros::conversions::decl_cross_width_widening!(wide D153, crate::int::types::Int<8>, D76, crate::int::types::Int<4>);
856// Cross-width narrowing from D153 (fallible): D153 -> D76 / D38.
857#[cfg(all(
858    any(feature = "d153", feature = "wide"),
859    any(feature = "d76", feature = "wide")
860))]
861crate::macros::conversions::decl_cross_width_narrowing!(wide D76, crate::int::types::Int<4>, D153, crate::int::types::Int<8>);
862#[cfg(any(feature = "d153", feature = "wide"))]
863crate::macros::conversions::decl_cross_width_narrowing!(wide D38, crate::int::types::Int<2>, D153, crate::int::types::Int<8>);
864
865// ─── D76::widen / D153 hop methods ────────────────────────────────────
866
867#[cfg(all(
868    any(feature = "d76", feature = "wide"),
869    any(feature = "d115", feature = "wide")
870))]
871impl<const SCALE: u32> crate::D<crate::int::types::Int<4>, SCALE> {
872    /// Promote to the next storage tier ([`D115`]) at the same
873    /// `SCALE`. Lossless.
874    #[inline]
875    #[must_use]
876    pub fn widen(self) -> crate::D<crate::int::types::Int<6>, SCALE> {
877        self.into()
878    }
879}
880
881#[cfg(any(feature = "d153", feature = "wide"))]
882impl<const SCALE: u32> crate::D<crate::int::types::Int<8>, SCALE> {
883    /// Demote to the previous storage tier ([`D115`]) at the same
884    /// `SCALE`. Returns `Err(ConvertError::Overflow)` if the value
885    /// doesn't fit the narrower storage's range at the given scale.
886    #[cfg(any(feature = "d115", feature = "wide"))]
887    #[inline]
888    pub fn narrow(self) -> Result<crate::D<crate::int::types::Int<6>, SCALE>, crate::support::error::ConvertError> {
889        self.try_into()
890    }
891}
892
893/// Scale alias: `D153<0>`. 1 LSB = 1 (512-bit integer ledger).
894#[cfg(any(feature = "d153", feature = "wide"))]
895pub type D153s0 = D153<0>;
896#[cfg(any(feature = "d153", feature = "wide"))]
897pub type D153s1 = D153<1>;
898#[cfg(any(feature = "d153", feature = "wide"))]
899pub type D153s2 = D153<2>;
900#[cfg(any(feature = "d153", feature = "wide"))]
901pub type D153s4 = D153<4>;
902#[cfg(any(feature = "d153", feature = "wide"))]
903pub type D153s6 = D153<6>;
904#[cfg(any(feature = "d153", feature = "wide"))]
905pub type D153s9 = D153<9>;
906#[cfg(any(feature = "d153", feature = "wide"))]
907pub type D153s12 = D153<12>;
908#[cfg(any(feature = "d153", feature = "wide"))]
909pub type D153s15 = D153<15>;
910#[cfg(any(feature = "d153", feature = "wide"))]
911pub type D153s18 = D153<18>;
912#[cfg(any(feature = "d153", feature = "wide"))]
913pub type D153s20 = D153<20>;
914#[cfg(any(feature = "d153", feature = "wide"))]
915pub type D153s24 = D153<24>;
916#[cfg(any(feature = "d153", feature = "wide"))]
917pub type D153s28 = D153<28>;
918#[cfg(any(feature = "d153", feature = "wide"))]
919pub type D153s32 = D153<32>;
920/// Scale alias: `D153<35>`. 1 LSB = 10^-35 (matches D38 `SCALE_REF`).
921#[cfg(any(feature = "d153", feature = "wide"))]
922pub type D153s35 = D153<35>;
923#[cfg(any(feature = "d153", feature = "wide"))]
924pub type D153s38 = D153<38>;
925#[cfg(any(feature = "d153", feature = "wide"))]
926pub type D153s50 = D153<50>;
927#[cfg(any(feature = "d153", feature = "wide"))]
928pub type D153s57 = D153<57>;
929/// Scale alias: `D153<75>`. 1 LSB = 10^-75 (wide-scientific midpoint).
930#[cfg(any(feature = "d153", feature = "wide"))]
931pub type D153s75 = D153<75>;
932#[cfg(any(feature = "d153", feature = "wide"))]
933pub type D153s76 = D153<76>;
934#[cfg(any(feature = "d153", feature = "wide"))]
935pub type D153s100 = D153<100>;
936#[cfg(any(feature = "d153", feature = "wide"))]
937pub type D153s115 = D153<115>;
938#[cfg(any(feature = "d153", feature = "wide"))]
939pub type D153s140 = D153<140>;
940/// Scale alias: `D153<150>`. 1 LSB = 10^-150.
941#[cfg(any(feature = "d153", feature = "wide"))]
942pub type D153s150 = D153<150>;
943/// Scale alias: `D153<152>`. 1 LSB = 10^-152. Maximum supported scale
944/// (scale cap: `MAX_SCALE = name - 1`).
945#[cfg(any(feature = "d153", feature = "wide"))]
946pub type D153s152 = D153<152>;
947
948// ---------------------------------------------------------------------
949// D307 — 1024-bit storage (`Int<16>`), scale 0..=307. Deep
950// arbitrary-precision tier; gated behind the `d307` / `wide` features.
951// ---------------------------------------------------------------------
952
953/// Scaled fixed-point decimal with 1024-bit storage. See [`D38`] for
954/// the shape documentation; D307 has the same surface scaled to a
955/// 1024-bit signed integer and `MAX_SCALE = 306`. A type alias of
956/// the unified [`crate::D`] generic decimal type: `D307<S>` is
957/// `D<crate::int::types::Int<16>, S>`. Both spellings are interchangeable.
958///
959/// The `#[repr(transparent)]` layout over `Int<16>` is preserved through
960/// the alias because the underlying [`crate::D`] is itself
961/// `#[repr(transparent)]` over its storage parameter.
962///
963/// Gated behind the `d307` (or umbrella `wide`) Cargo feature. The
964/// storage backend is `Int<16>`.
965#[cfg(any(feature = "d307", feature = "wide"))]
966pub type D307<const SCALE: u32> = crate::D<crate::int::types::Int<16>, SCALE>;
967
968/// `Default` returns `ZERO`, matching the all-zero limb pattern of
969/// `Int<16>`.
970///
971/// Implemented on the underlying `crate::D<crate::int::types::Int<16>, SCALE>`
972/// because `D307<SCALE>` is an alias of that type. `ZERO` is emitted
973/// by the basics macro further down in this file.
974#[cfg(any(feature = "d307", feature = "wide"))]
975impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<16>, SCALE> {
976    #[inline]
977    fn default() -> Self {
978        Self::ZERO
979    }
980}
981
982#[cfg(any(feature = "d307", feature = "wide"))]
983crate::macros::full::decl_decimal_full!(
984    wide D307,
985    crate::int::types::Int<16>,
986    crate::int::types::Uint<16>,
987    crate::int::types::Int<32>,
988    crate::int::types::Int<32>,
989    crate::int::types::Int<64>,
990    crate::int::types::Int<64>,
991    crate::int::types::Int<128>,
992    crate::int::types::Int<64>,
993    wide_trig_d307,
994    306,
995    16,
996    400,
997    512
998);
999// Cross-width widening into D307 (lossless): D76 / D153 -> D307.
1000#[cfg(all(
1001    any(feature = "d307", feature = "wide"),
1002    any(feature = "d76", feature = "wide")
1003))]
1004crate::macros::conversions::decl_cross_width_widening!(wide D307, crate::int::types::Int<16>, D76, crate::int::types::Int<4>);
1005#[cfg(all(
1006    any(feature = "d307", feature = "wide"),
1007    any(feature = "d153", feature = "wide")
1008))]
1009crate::macros::conversions::decl_cross_width_widening!(wide D307, crate::int::types::Int<16>, D153, crate::int::types::Int<8>);
1010// Cross-width narrowing from D307 (fallible): D307 -> D153 / D76.
1011#[cfg(all(
1012    any(feature = "d307", feature = "wide"),
1013    any(feature = "d153", feature = "wide")
1014))]
1015crate::macros::conversions::decl_cross_width_narrowing!(wide D153, crate::int::types::Int<8>, D307, crate::int::types::Int<16>);
1016#[cfg(all(
1017    any(feature = "d307", feature = "wide"),
1018    any(feature = "d76", feature = "wide")
1019))]
1020crate::macros::conversions::decl_cross_width_narrowing!(wide D76, crate::int::types::Int<4>, D307, crate::int::types::Int<16>);
1021
1022// ─── D153::widen / D307 hop methods ───────────────────────────────────
1023
1024#[cfg(all(
1025    any(feature = "d153", feature = "wide"),
1026    any(feature = "d230", feature = "wide")
1027))]
1028impl<const SCALE: u32> crate::D<crate::int::types::Int<8>, SCALE> {
1029    /// Promote to the next storage tier ([`D230`]) at the same
1030    /// `SCALE`. Lossless.
1031    #[inline]
1032    #[must_use]
1033    pub fn widen(self) -> crate::D<crate::int::types::Int<12>, SCALE> {
1034        self.into()
1035    }
1036}
1037
1038#[cfg(any(feature = "d307", feature = "wide"))]
1039impl<const SCALE: u32> crate::D<crate::int::types::Int<16>, SCALE> {
1040    /// Demote to the previous storage tier ([`D230`]) at the same
1041    /// `SCALE`. Returns `Err(ConvertError::Overflow)` if the value
1042    /// doesn't fit the narrower storage's range at the given scale.
1043    #[cfg(any(feature = "d230", feature = "wide"))]
1044    #[inline]
1045    pub fn narrow(self) -> Result<crate::D<crate::int::types::Int<12>, SCALE>, crate::support::error::ConvertError> {
1046        self.try_into()
1047    }
1048
1049    /// Promote to the next storage tier ([`D462`]) at the same
1050    /// `SCALE`. Lossless. Requires `d462` / `x-wide`.
1051    #[cfg(any(feature = "d462", feature = "x-wide"))]
1052    #[inline]
1053    #[must_use]
1054    pub fn widen(self) -> crate::D<crate::int::types::Int<24>, SCALE> {
1055        self.into()
1056    }
1057}
1058
1059/// Scale alias: `D307<0>`. 1 LSB = 1 (1024-bit integer ledger).
1060#[cfg(any(feature = "d307", feature = "wide"))]
1061pub type D307s0 = D307<0>;
1062#[cfg(any(feature = "d307", feature = "wide"))]
1063pub type D307s1 = D307<1>;
1064#[cfg(any(feature = "d307", feature = "wide"))]
1065pub type D307s2 = D307<2>;
1066#[cfg(any(feature = "d307", feature = "wide"))]
1067pub type D307s4 = D307<4>;
1068#[cfg(any(feature = "d307", feature = "wide"))]
1069pub type D307s6 = D307<6>;
1070#[cfg(any(feature = "d307", feature = "wide"))]
1071pub type D307s9 = D307<9>;
1072#[cfg(any(feature = "d307", feature = "wide"))]
1073pub type D307s12 = D307<12>;
1074#[cfg(any(feature = "d307", feature = "wide"))]
1075pub type D307s15 = D307<15>;
1076#[cfg(any(feature = "d307", feature = "wide"))]
1077pub type D307s18 = D307<18>;
1078#[cfg(any(feature = "d307", feature = "wide"))]
1079pub type D307s20 = D307<20>;
1080#[cfg(any(feature = "d307", feature = "wide"))]
1081pub type D307s24 = D307<24>;
1082#[cfg(any(feature = "d307", feature = "wide"))]
1083pub type D307s28 = D307<28>;
1084#[cfg(any(feature = "d307", feature = "wide"))]
1085pub type D307s32 = D307<32>;
1086/// Scale alias: `D307<35>`. 1 LSB = 10^-35 (matches D38 `SCALE_REF`).
1087#[cfg(any(feature = "d307", feature = "wide"))]
1088pub type D307s35 = D307<35>;
1089#[cfg(any(feature = "d307", feature = "wide"))]
1090pub type D307s38 = D307<38>;
1091#[cfg(any(feature = "d307", feature = "wide"))]
1092pub type D307s50 = D307<50>;
1093#[cfg(any(feature = "d307", feature = "wide"))]
1094pub type D307s75 = D307<75>;
1095#[cfg(any(feature = "d307", feature = "wide"))]
1096pub type D307s100 = D307<100>;
1097#[cfg(any(feature = "d307", feature = "wide"))]
1098pub type D307s115 = D307<115>;
1099/// Scale alias: `D307<150>`. 1 LSB = 10^-150.
1100#[cfg(any(feature = "d307", feature = "wide"))]
1101pub type D307s150 = D307<150>;
1102#[cfg(any(feature = "d307", feature = "wide"))]
1103pub type D307s153 = D307<153>;
1104#[cfg(any(feature = "d307", feature = "wide"))]
1105pub type D307s200 = D307<200>;
1106#[cfg(any(feature = "d307", feature = "wide"))]
1107pub type D307s230 = D307<230>;
1108#[cfg(any(feature = "d307", feature = "wide"))]
1109pub type D307s275 = D307<275>;
1110/// Scale alias: `D307<300>`. 1 LSB = 10^-300.
1111#[cfg(any(feature = "d307", feature = "wide"))]
1112pub type D307s300 = D307<300>;
1113/// Scale alias: `D307<306>`. 1 LSB = 10^-306. Maximum supported scale
1114/// (scale cap: `MAX_SCALE = name - 1`).
1115#[cfg(any(feature = "d307", feature = "wide"))]
1116pub type D307s306 = D307<306>;
1117
1118// ─── Half-width and wider tiers (D57 / D115 / D230 / D462 / D616 / D924 / D1232) ───
1119//
1120// These fill the (2^n + 2^(n+1))/2 gaps between the existing
1121// power-of-two storage tiers, plus extend the top end past D307.
1122// Each tier has the same surface as D76 / D153 / D307: full
1123// `decl_decimal_full!` emission (every arithmetic / transcendental
1124// method), plus scale aliases at 0 / mid / max.
1125//
1126// Cross-width widening / narrowing methods are emitted to the
1127// immediate-neighbour tiers only — `D57 ↔ D38`, `D57 ↔ D76`, etc.
1128// Multi-tier hops go via the chain (e.g. D57 → D76 → D153) at the
1129// cost of one intermediate.
1130
1131// ── D57 (192-bit / 3 u64 limbs) ────────────────────────────────────────
1132
1133/// Scaled fixed-point decimal with 192-bit storage. Half-width tier
1134/// between D38 and D76 — useful when the D38 i128 ceiling is in
1135/// reach but D76's 256-bit storage is wasteful. A type alias of
1136/// the unified [`crate::D`] generic decimal type: `D57<S>` is
1137/// `D<crate::int::types::Int<3>, S>`. Both spellings are interchangeable.
1138///
1139/// The `#[repr(transparent)]` layout over `Int<3>` is preserved
1140/// through the alias because the underlying [`crate::D`] is itself
1141/// `#[repr(transparent)]` over its storage parameter.
1142///
1143/// Gated behind the `d57` (or umbrella `wide`) Cargo feature.
1144#[cfg(any(feature = "d57", feature = "wide"))]
1145pub type D57<const SCALE: u32> = crate::D<crate::int::types::Int<3>, SCALE>;
1146
1147/// `Default` returns `ZERO`, matching the all-zero limb pattern of
1148/// `Int<3>`.
1149///
1150/// Implemented on the underlying `crate::D<crate::int::types::Int<3>, SCALE>`
1151/// because `D57<SCALE>` is an alias of that type. `ZERO` is emitted
1152/// by the basics macro further down in this file.
1153#[cfg(any(feature = "d57", feature = "wide"))]
1154impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<3>, SCALE> {
1155    #[inline]
1156    fn default() -> Self {
1157        Self::ZERO
1158    }
1159}
1160
1161#[cfg(any(feature = "d57", feature = "wide"))]
1162crate::macros::full::decl_decimal_full!(
1163    wide D57,
1164    crate::int::types::Int<3>,
1165    crate::int::types::Uint<3>,
1166    crate::int::types::Int<6>,
1167    crate::int::types::Int<6>,
1168    crate::int::types::Int<8>,
1169    crate::int::types::Int<16>,
1170    crate::int::types::Int<32>,
1171    crate::int::types::Int<16>,
1172    wide_trig_d57,
1173    56,
1174    3,
1175    100,
1176    128
1177);
1178#[cfg(any(feature = "d57", feature = "wide"))]
1179pub type D57s0 = D57<0>;
1180#[cfg(any(feature = "d57", feature = "wide"))]
1181pub type D57s1 = D57<1>;
1182#[cfg(any(feature = "d57", feature = "wide"))]
1183pub type D57s2 = D57<2>;
1184#[cfg(any(feature = "d57", feature = "wide"))]
1185pub type D57s4 = D57<4>;
1186#[cfg(any(feature = "d57", feature = "wide"))]
1187pub type D57s6 = D57<6>;
1188#[cfg(any(feature = "d57", feature = "wide"))]
1189pub type D57s9 = D57<9>;
1190#[cfg(any(feature = "d57", feature = "wide"))]
1191pub type D57s12 = D57<12>;
1192#[cfg(any(feature = "d57", feature = "wide"))]
1193pub type D57s18 = D57<18>;
1194#[cfg(any(feature = "d57", feature = "wide"))]
1195pub type D57s20 = D57<20>;
1196#[cfg(any(feature = "d57", feature = "wide"))]
1197pub type D57s24 = D57<24>;
1198#[cfg(any(feature = "d57", feature = "wide"))]
1199pub type D57s28 = D57<28>;
1200#[cfg(any(feature = "d57", feature = "wide"))]
1201pub type D57s32 = D57<32>;
1202#[cfg(any(feature = "d57", feature = "wide"))]
1203pub type D57s38 = D57<38>;
1204#[cfg(any(feature = "d57", feature = "wide"))]
1205pub type D57s42 = D57<42>;
1206#[cfg(any(feature = "d57", feature = "wide"))]
1207pub type D57s48 = D57<48>;
1208#[cfg(any(feature = "d57", feature = "wide"))]
1209pub type D57s52 = D57<52>;
1210/// Scale alias: `D57<56>`. 1 LSB = 10^-56. Maximum supported scale
1211/// (scale cap: `MAX_SCALE = name - 1`).
1212#[cfg(any(feature = "d57", feature = "wide"))]
1213pub type D57s56 = D57<56>;
1214
1215// ── D115 (384-bit / 6 u64 limbs) ───────────────────────────────────────
1216
1217/// Scaled fixed-point decimal with 384-bit storage. Half-width tier
1218/// between D76 and D153. A type alias of the unified [`crate::D`]
1219/// generic decimal type: `D115<S>` is `D<crate::int::types::Int<6>, S>`.
1220/// Both spellings are interchangeable.
1221///
1222/// The `#[repr(transparent)]` layout over `Int<6>` is preserved through
1223/// the alias because the underlying [`crate::D`] is itself
1224/// `#[repr(transparent)]` over its storage parameter.
1225///
1226/// Gated behind the `d115` (or umbrella `wide`) Cargo feature.
1227#[cfg(any(feature = "d115", feature = "wide"))]
1228pub type D115<const SCALE: u32> = crate::D<crate::int::types::Int<6>, SCALE>;
1229
1230/// `Default` returns `ZERO`, matching the all-zero limb pattern of
1231/// `Int<6>`.
1232///
1233/// Implemented on the underlying `crate::D<crate::int::types::Int<6>, SCALE>`
1234/// because `D115<SCALE>` is an alias of that type. `ZERO` is emitted
1235/// by the basics macro further down in this file.
1236#[cfg(any(feature = "d115", feature = "wide"))]
1237impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<6>, SCALE> {
1238    #[inline]
1239    fn default() -> Self {
1240        Self::ZERO
1241    }
1242}
1243
1244#[cfg(any(feature = "d115", feature = "wide"))]
1245crate::macros::full::decl_decimal_full!(
1246    wide D115,
1247    crate::int::types::Int<6>,
1248    crate::int::types::Uint<6>,
1249    crate::int::types::Int<12>,
1250    crate::int::types::Int<12>,
1251    crate::int::types::Int<16>,
1252    crate::int::types::Int<32>,
1253    crate::int::types::Int<64>,
1254    crate::int::types::Int<32>,
1255    wide_trig_d115,
1256    114,
1257    6,
1258    200,
1259    512
1260);
1261#[cfg(any(feature = "d115", feature = "wide"))]
1262pub type D115s0 = D115<0>;
1263#[cfg(any(feature = "d115", feature = "wide"))]
1264pub type D115s1 = D115<1>;
1265#[cfg(any(feature = "d115", feature = "wide"))]
1266pub type D115s4 = D115<4>;
1267#[cfg(any(feature = "d115", feature = "wide"))]
1268pub type D115s8 = D115<8>;
1269#[cfg(any(feature = "d115", feature = "wide"))]
1270pub type D115s16 = D115<16>;
1271#[cfg(any(feature = "d115", feature = "wide"))]
1272pub type D115s24 = D115<24>;
1273#[cfg(any(feature = "d115", feature = "wide"))]
1274pub type D115s32 = D115<32>;
1275#[cfg(any(feature = "d115", feature = "wide"))]
1276pub type D115s38 = D115<38>;
1277#[cfg(any(feature = "d115", feature = "wide"))]
1278pub type D115s50 = D115<50>;
1279#[cfg(any(feature = "d115", feature = "wide"))]
1280pub type D115s57 = D115<57>;
1281#[cfg(any(feature = "d115", feature = "wide"))]
1282pub type D115s64 = D115<64>;
1283#[cfg(any(feature = "d115", feature = "wide"))]
1284pub type D115s76 = D115<76>;
1285#[cfg(any(feature = "d115", feature = "wide"))]
1286pub type D115s90 = D115<90>;
1287#[cfg(any(feature = "d115", feature = "wide"))]
1288pub type D115s100 = D115<100>;
1289#[cfg(any(feature = "d115", feature = "wide"))]
1290pub type D115s110 = D115<110>;
1291/// Scale alias: `D115<114>`. 1 LSB = 10^-114. Maximum supported scale
1292/// (scale cap: `MAX_SCALE = name - 1`).
1293#[cfg(any(feature = "d115", feature = "wide"))]
1294pub type D115s114 = D115<114>;
1295
1296// ── D230 (768-bit / 12 u64 limbs) ──────────────────────────────────────
1297
1298/// Scaled fixed-point decimal with 768-bit storage. Half-width tier
1299/// between D153 and D307. A type alias of the unified [`crate::D`]
1300/// generic decimal type: `D230<S>` is `D<crate::int::types::Int<12>, S>`.
1301/// Both spellings are interchangeable.
1302///
1303/// The `#[repr(transparent)]` layout over `Int<12>` is preserved through
1304/// the alias because the underlying [`crate::D`] is itself
1305/// `#[repr(transparent)]` over its storage parameter.
1306///
1307/// Gated behind the `d230` (or umbrella `wide`) Cargo feature.
1308#[cfg(any(feature = "d230", feature = "wide"))]
1309pub type D230<const SCALE: u32> = crate::D<crate::int::types::Int<12>, SCALE>;
1310
1311/// `Default` returns `ZERO`, matching the all-zero limb pattern of
1312/// `Int<12>`.
1313///
1314/// Implemented on the underlying `crate::D<crate::int::types::Int<12>, SCALE>`
1315/// because `D230<SCALE>` is an alias of that type. `ZERO` is emitted
1316/// by the basics macro further down in this file.
1317#[cfg(any(feature = "d230", feature = "wide"))]
1318impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<12>, SCALE> {
1319    #[inline]
1320    fn default() -> Self {
1321        Self::ZERO
1322    }
1323}
1324
1325#[cfg(any(feature = "d230", feature = "wide"))]
1326crate::macros::full::decl_decimal_full!(
1327    wide D230,
1328    crate::int::types::Int<12>,
1329    crate::int::types::Uint<12>,
1330    crate::int::types::Int<24>,
1331    crate::int::types::Int<24>,
1332    crate::int::types::Int<48>,
1333    crate::int::types::Int<48>,
1334    crate::int::types::Int<96>,
1335    crate::int::types::Int<48>,
1336    wide_trig_d230,
1337    229,
1338    12,
1339    400,
1340    512
1341);
1342#[cfg(any(feature = "d230", feature = "wide"))]
1343pub type D230s0 = D230<0>;
1344#[cfg(any(feature = "d230", feature = "wide"))]
1345pub type D230s1 = D230<1>;
1346#[cfg(any(feature = "d230", feature = "wide"))]
1347pub type D230s6 = D230<6>;
1348#[cfg(any(feature = "d230", feature = "wide"))]
1349pub type D230s18 = D230<18>;
1350#[cfg(any(feature = "d230", feature = "wide"))]
1351pub type D230s38 = D230<38>;
1352#[cfg(any(feature = "d230", feature = "wide"))]
1353pub type D230s57 = D230<57>;
1354#[cfg(any(feature = "d230", feature = "wide"))]
1355pub type D230s75 = D230<75>;
1356#[cfg(any(feature = "d230", feature = "wide"))]
1357pub type D230s100 = D230<100>;
1358#[cfg(any(feature = "d230", feature = "wide"))]
1359pub type D230s115 = D230<115>;
1360#[cfg(any(feature = "d230", feature = "wide"))]
1361pub type D230s140 = D230<140>;
1362#[cfg(any(feature = "d230", feature = "wide"))]
1363pub type D230s153 = D230<153>;
1364#[cfg(any(feature = "d230", feature = "wide"))]
1365pub type D230s175 = D230<175>;
1366#[cfg(any(feature = "d230", feature = "wide"))]
1367pub type D230s200 = D230<200>;
1368#[cfg(any(feature = "d230", feature = "wide"))]
1369pub type D230s215 = D230<215>;
1370#[cfg(any(feature = "d230", feature = "wide"))]
1371pub type D230s225 = D230<225>;
1372/// Scale alias: `D230<229>`. 1 LSB = 10^-229. Maximum supported scale
1373/// (scale cap: `MAX_SCALE = name - 1`).
1374#[cfg(any(feature = "d230", feature = "wide"))]
1375pub type D230s229 = D230<229>;
1376
1377// ── D462 (1536-bit / 24 u64 limbs) ─────────────────────────────────────
1378
1379/// Scaled fixed-point decimal with 1536-bit storage. Half-width tier
1380/// between D307 and D616. A type alias of the unified [`crate::D`]
1381/// generic decimal type: `D462<S>` is `D<crate::int::types::Int<24>, S>`.
1382/// Both spellings are interchangeable.
1383///
1384/// The `#[repr(transparent)]` layout over `Int<24>` is preserved through
1385/// the alias because the underlying [`crate::D`] is itself
1386/// `#[repr(transparent)]` over its storage parameter.
1387///
1388/// Gated behind the `d462` (or umbrella `x-wide`) Cargo feature.
1389#[cfg(any(feature = "d462", feature = "x-wide"))]
1390pub type D462<const SCALE: u32> = crate::D<crate::int::types::Int<24>, SCALE>;
1391
1392/// `Default` returns `ZERO`, matching the all-zero limb pattern of
1393/// `Int<24>`.
1394///
1395/// Implemented on the underlying `crate::D<crate::int::types::Int<24>, SCALE>`
1396/// because `D462<SCALE>` is an alias of that type. `ZERO` is emitted
1397/// by the basics macro further down in this file.
1398#[cfg(any(feature = "d462", feature = "x-wide"))]
1399impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<24>, SCALE> {
1400    #[inline]
1401    fn default() -> Self {
1402        Self::ZERO
1403    }
1404}
1405
1406#[cfg(any(feature = "d462", feature = "x-wide"))]
1407crate::macros::full::decl_decimal_full!(
1408    wide D462,
1409    crate::int::types::Int<24>,
1410    crate::int::types::Uint<24>,
1411    crate::int::types::Int<48>,
1412    crate::int::types::Int<48>,
1413    crate::int::types::Int<64>,
1414    crate::int::types::Int<64>,
1415    crate::int::types::Int<128>,
1416    crate::int::types::Int<64>,
1417    wide_trig_d462,
1418    461,
1419    24,
1420    400,
1421    512
1422);
1423#[cfg(any(feature = "d462", feature = "x-wide"))]
1424pub type D462s0 = D462<0>;
1425#[cfg(any(feature = "d462", feature = "x-wide"))]
1426pub type D462s1 = D462<1>;
1427#[cfg(any(feature = "d462", feature = "x-wide"))]
1428pub type D462s18 = D462<18>;
1429#[cfg(any(feature = "d462", feature = "x-wide"))]
1430pub type D462s38 = D462<38>;
1431#[cfg(any(feature = "d462", feature = "x-wide"))]
1432pub type D462s75 = D462<75>;
1433#[cfg(any(feature = "d462", feature = "x-wide"))]
1434pub type D462s115 = D462<115>;
1435#[cfg(any(feature = "d462", feature = "x-wide"))]
1436pub type D462s153 = D462<153>;
1437#[cfg(any(feature = "d462", feature = "x-wide"))]
1438pub type D462s200 = D462<200>;
1439#[cfg(any(feature = "d462", feature = "x-wide"))]
1440pub type D462s230 = D462<230>;
1441#[cfg(any(feature = "d462", feature = "x-wide"))]
1442pub type D462s275 = D462<275>;
1443#[cfg(any(feature = "d462", feature = "x-wide"))]
1444pub type D462s307 = D462<307>;
1445#[cfg(any(feature = "d462", feature = "x-wide"))]
1446pub type D462s350 = D462<350>;
1447#[cfg(any(feature = "d462", feature = "x-wide"))]
1448pub type D462s400 = D462<400>;
1449#[cfg(any(feature = "d462", feature = "x-wide"))]
1450pub type D462s440 = D462<440>;
1451#[cfg(any(feature = "d462", feature = "x-wide"))]
1452pub type D462s460 = D462<460>;
1453/// Scale alias: `D462<461>`. 1 LSB = 10^-461. Maximum supported scale
1454/// (scale cap: `MAX_SCALE = name - 1`).
1455#[cfg(any(feature = "d462", feature = "x-wide"))]
1456pub type D462s461 = D462<461>;
1457
1458// ── D616 (2048-bit / 32 u64 limbs) ─────────────────────────────────────
1459
1460/// Scaled fixed-point decimal with 2048-bit storage. New top tier
1461/// beyond D307; supports correctly-rounded transcendentals at scale
1462/// up to 616 decimal digits. A type alias of the unified
1463/// [`crate::D`] generic decimal type: `D616<S>` is
1464/// `D<crate::int::types::Int<32>, S>`. Both spellings are interchangeable.
1465///
1466/// The `#[repr(transparent)]` layout over `Int<32>` is preserved through
1467/// the alias because the underlying [`crate::D`] is itself
1468/// `#[repr(transparent)]` over its storage parameter.
1469///
1470/// Gated behind the `d616` (or umbrella `x-wide`) Cargo feature.
1471#[cfg(any(feature = "d616", feature = "x-wide"))]
1472pub type D616<const SCALE: u32> = crate::D<crate::int::types::Int<32>, SCALE>;
1473
1474/// `Default` returns `ZERO`, matching the all-zero limb pattern of
1475/// `Int<32>`.
1476///
1477/// Implemented on the underlying `crate::D<crate::int::types::Int<32>, SCALE>`
1478/// because `D616<SCALE>` is an alias of that type. `ZERO` is emitted
1479/// by the basics macro further down in this file.
1480#[cfg(any(feature = "d616", feature = "x-wide"))]
1481impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<32>, SCALE> {
1482    #[inline]
1483    fn default() -> Self {
1484        Self::ZERO
1485    }
1486}
1487
1488#[cfg(any(feature = "d616", feature = "x-wide"))]
1489crate::macros::full::decl_decimal_full!(
1490    wide D616,
1491    crate::int::types::Int<32>,
1492    crate::int::types::Uint<32>,
1493    crate::int::types::Int<64>,
1494    crate::int::types::Int<64>,
1495    crate::int::types::Int<128>,
1496    crate::int::types::Int<96>,
1497    crate::int::types::Int<256>,
1498    crate::int::types::Int<128>,
1499    wide_trig_d616,
1500    615,
1501    32,
1502    400,
1503    512
1504);
1505#[cfg(any(feature = "d616", feature = "x-wide"))]
1506pub type D616s0 = D616<0>;
1507#[cfg(any(feature = "d616", feature = "x-wide"))]
1508pub type D616s1 = D616<1>;
1509#[cfg(any(feature = "d616", feature = "x-wide"))]
1510pub type D616s38 = D616<38>;
1511#[cfg(any(feature = "d616", feature = "x-wide"))]
1512pub type D616s75 = D616<75>;
1513#[cfg(any(feature = "d616", feature = "x-wide"))]
1514pub type D616s115 = D616<115>;
1515#[cfg(any(feature = "d616", feature = "x-wide"))]
1516pub type D616s153 = D616<153>;
1517#[cfg(any(feature = "d616", feature = "x-wide"))]
1518pub type D616s200 = D616<200>;
1519#[cfg(any(feature = "d616", feature = "x-wide"))]
1520pub type D616s230 = D616<230>;
1521#[cfg(any(feature = "d616", feature = "x-wide"))]
1522pub type D616s275 = D616<275>;
1523#[cfg(any(feature = "d616", feature = "x-wide"))]
1524pub type D616s308 = D616<308>;
1525#[cfg(any(feature = "d616", feature = "x-wide"))]
1526pub type D616s380 = D616<380>;
1527#[cfg(any(feature = "d616", feature = "x-wide"))]
1528pub type D616s462 = D616<462>;
1529#[cfg(any(feature = "d616", feature = "x-wide"))]
1530pub type D616s500 = D616<500>;
1531#[cfg(any(feature = "d616", feature = "x-wide"))]
1532pub type D616s555 = D616<555>;
1533#[cfg(any(feature = "d616", feature = "x-wide"))]
1534pub type D616s600 = D616<600>;
1535/// Scale alias: `D616<615>`. 1 LSB = 10^-615. Maximum supported scale
1536/// (scale cap: `MAX_SCALE = name - 1`).
1537#[cfg(any(feature = "d616", feature = "x-wide"))]
1538pub type D616s615 = D616<615>;
1539
1540// ── D924 (3072-bit / 48 u64 limbs) ─────────────────────────────────────
1541
1542/// Scaled fixed-point decimal with 3072-bit storage. Half-width tier
1543/// between D616 and D1232; supports SCALE up to 924 digits. A type
1544/// alias of the unified [`crate::D`] generic decimal type: `D924<S>`
1545/// is `D<crate::int::types::Int<48>, S>`. Both spellings are interchangeable.
1546///
1547/// The `#[repr(transparent)]` layout over `Int<48>` is preserved through
1548/// the alias because the underlying [`crate::D`] is itself
1549/// `#[repr(transparent)]` over its storage parameter.
1550///
1551/// Gated behind the `d924` (or umbrella `xx-wide`) Cargo feature.
1552#[cfg(any(feature = "d924", feature = "xx-wide"))]
1553pub type D924<const SCALE: u32> = crate::D<crate::int::types::Int<48>, SCALE>;
1554
1555/// `Default` returns `ZERO`, matching the all-zero limb pattern of
1556/// `Int<48>`.
1557///
1558/// Implemented on the underlying `crate::D<crate::int::types::Int<48>, SCALE>`
1559/// because `D924<SCALE>` is an alias of that type. `ZERO` is emitted
1560/// by the basics macro further down in this file.
1561#[cfg(any(feature = "d924", feature = "xx-wide"))]
1562impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<48>, SCALE> {
1563    #[inline]
1564    fn default() -> Self {
1565        Self::ZERO
1566    }
1567}
1568
1569#[cfg(any(feature = "d924", feature = "xx-wide"))]
1570// `no_const_table`: 953-entry `Int<192>` POW10_TABLE build exceeds
1571// the stable-rust const-eval step budget, so `10^w` is recomputed on
1572// the stack each call instead of read from a compile-time table.
1573crate::macros::full::decl_decimal_full!(
1574    wide D924,
1575    crate::int::types::Int<48>,
1576    crate::int::types::Uint<48>,
1577    crate::int::types::Int<96>,
1578    crate::int::types::Int<96>,
1579    crate::int::types::Int<192>,
1580    crate::int::types::Int<128>,
1581    crate::int::types::Int<256>,
1582    crate::int::types::Int<192>,
1583    wide_trig_d924,
1584    923,
1585    48,
1586    400,
1587    512,
1588    no_const_table
1589);
1590#[cfg(any(feature = "d924", feature = "xx-wide"))]
1591pub type D924s0 = D924<0>;
1592#[cfg(any(feature = "d924", feature = "xx-wide"))]
1593pub type D924s1 = D924<1>;
1594#[cfg(any(feature = "d924", feature = "xx-wide"))]
1595pub type D924s75 = D924<75>;
1596#[cfg(any(feature = "d924", feature = "xx-wide"))]
1597pub type D924s153 = D924<153>;
1598#[cfg(any(feature = "d924", feature = "xx-wide"))]
1599pub type D924s230 = D924<230>;
1600#[cfg(any(feature = "d924", feature = "xx-wide"))]
1601pub type D924s307 = D924<307>;
1602#[cfg(any(feature = "d924", feature = "xx-wide"))]
1603pub type D924s400 = D924<400>;
1604#[cfg(any(feature = "d924", feature = "xx-wide"))]
1605pub type D924s461 = D924<461>;
1606#[cfg(any(feature = "d924", feature = "xx-wide"))]
1607pub type D924s462 = D924<462>;
1608#[cfg(any(feature = "d924", feature = "xx-wide"))]
1609pub type D924s500 = D924<500>;
1610#[cfg(any(feature = "d924", feature = "xx-wide"))]
1611pub type D924s616 = D924<616>;
1612#[cfg(any(feature = "d924", feature = "xx-wide"))]
1613pub type D924s700 = D924<700>;
1614#[cfg(any(feature = "d924", feature = "xx-wide"))]
1615pub type D924s800 = D924<800>;
1616#[cfg(any(feature = "d924", feature = "xx-wide"))]
1617pub type D924s860 = D924<860>;
1618#[cfg(any(feature = "d924", feature = "xx-wide"))]
1619pub type D924s900 = D924<900>;
1620#[cfg(any(feature = "d924", feature = "xx-wide"))]
1621pub type D924s920 = D924<920>;
1622/// Scale alias: `D924<923>`. 1 LSB = 10^-923. Maximum supported scale
1623/// (scale cap: `MAX_SCALE = name - 1`).
1624#[cfg(any(feature = "d924", feature = "xx-wide"))]
1625pub type D924s923 = D924<923>;
1626
1627// ── D1232 (4096-bit / 64 u64 limbs) ────────────────────────────────────
1628
1629/// Scaled fixed-point decimal with 4096-bit storage. Widest tier
1630/// shipped; supports SCALE up to 1232 digits. A type alias of the
1631/// unified [`crate::D`] generic decimal type: `D1232<S>` is
1632/// `D<crate::int::types::Int<64>, S>`. Both spellings are interchangeable.
1633///
1634/// The `#[repr(transparent)]` layout over `Int<64>` is preserved through
1635/// the alias because the underlying [`crate::D`] is itself
1636/// `#[repr(transparent)]` over its storage parameter.
1637///
1638/// Gated behind the `d1232` (or umbrella `xx-wide`) Cargo feature.
1639#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1640pub type D1232<const SCALE: u32> = crate::D<crate::int::types::Int<64>, SCALE>;
1641
1642/// `Default` returns `ZERO`, matching the all-zero limb pattern of
1643/// `Int<64>`.
1644///
1645/// Implemented on the underlying `crate::D<crate::int::types::Int<64>, SCALE>`
1646/// because `D1232<SCALE>` is an alias of that type. `ZERO` is emitted
1647/// by the basics macro further down in this file.
1648#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1649impl<const SCALE: u32> Default for crate::D<crate::int::types::Int<64>, SCALE> {
1650    #[inline]
1651    fn default() -> Self {
1652        Self::ZERO
1653    }
1654}
1655
1656#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1657// `no_const_table`: 1262-entry `Int<256>` POW10_TABLE build exceeds
1658// the stable-rust const-eval step budget, so `10^w` is recomputed on
1659// the stack each call instead of read from a compile-time table.
1660crate::macros::full::decl_decimal_full!(
1661    wide D1232,
1662    crate::int::types::Int<64>,
1663    crate::int::types::Uint<64>,
1664    crate::int::types::Int<128>,
1665    crate::int::types::Int<128>,
1666    crate::int::types::Int<256>,
1667    crate::int::types::Int<176>,
1668    crate::int::types::Int<512>,
1669    crate::int::types::Int<256>,
1670    wide_trig_d1232,
1671    1231,
1672    64,
1673    400,
1674    512,
1675    no_const_table
1676);
1677#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1678pub type D1232s0 = D1232<0>;
1679#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1680pub type D1232s1 = D1232<1>;
1681#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1682pub type D1232s75 = D1232<75>;
1683#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1684pub type D1232s153 = D1232<153>;
1685#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1686pub type D1232s230 = D1232<230>;
1687#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1688pub type D1232s307 = D1232<307>;
1689#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1690pub type D1232s461 = D1232<461>;
1691#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1692pub type D1232s616 = D1232<616>;
1693#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1694pub type D1232s700 = D1232<700>;
1695#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1696pub type D1232s800 = D1232<800>;
1697#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1698pub type D1232s900 = D1232<900>;
1699#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1700pub type D1232s924 = D1232<924>;
1701#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1702pub type D1232s1000 = D1232<1000>;
1703#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1704pub type D1232s1100 = D1232<1100>;
1705#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1706pub type D1232s1180 = D1232<1180>;
1707#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1708pub type D1232s1220 = D1232<1220>;
1709#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1710pub type D1232s1230 = D1232<1230>;
1711/// Scale alias: `D1232<1231>`. 1 LSB = 10^-1231. Maximum supported scale
1712/// (scale cap: `MAX_SCALE = name - 1`).
1713#[cfg(any(feature = "d1232", feature = "xx-wide"))]
1714pub type D1232s1231 = D1232<1231>;
1715
1716// ─── Cross-tier next-neighbour widen/narrow chain ─────────────────────
1717//
1718// The .widen() / .narrow() methods on D38/D76/D153/D307
1719// follow the power-of-two storage sequence (D38→D76→D153→D307). The
1720// full tier ladder fills in half-widths between each pair and
1721// extends to D1232:
1722//
1723//   D18 → D38 → D57 → D76 → D115 → D153 → D230 → D307 →
1724//   D462 → D616 → D924 → D1232
1725//
1726// The next-neighbour .widen() / .narrow() methods on the half-width tiers go
1727// to the immediate adjacent rung (D57.widen() → D76, D76.widen()
1728// already returns D153 which is the existing power-of-two next-up,
1729// etc.). The cross-tier From / TryFrom impls below cover the
1730// neighbour pairs that weren't already declared by the power-of-two
1731// D38/D76/D153/D307 blocks.
1732//
1733// Coverage strategy: declare every half-width adjacent pair both ways. The
1734// power-of-two-sequence declarations (D18/D18/D38↔D76, D38/D76↔D153,
1735// D76/D153↔D307) stay where they are; this block adds the conversions
1736// that hop through the half-width tiers (D38↔D57, D57↔D76, D76↔D115, etc.).
1737
1738// D38 ↔ D57
1739#[cfg(any(feature = "d57", feature = "wide"))]
1740crate::macros::conversions::decl_cross_width_widening!(wide D57, crate::int::types::Int<3>, D38, crate::int::types::Int<2>);
1741#[cfg(any(feature = "d57", feature = "wide"))]
1742crate::macros::conversions::decl_cross_width_narrowing!(wide D38, crate::int::types::Int<2>, D57, crate::int::types::Int<3>);
1743
1744// D57 ↔ D76
1745#[cfg(all(
1746    any(feature = "d57", feature = "wide"),
1747    any(feature = "d76", feature = "wide")
1748))]
1749crate::macros::conversions::decl_cross_width_widening!(wide D76, crate::int::types::Int<4>, D57, crate::int::types::Int<3>);
1750#[cfg(all(
1751    any(feature = "d57", feature = "wide"),
1752    any(feature = "d76", feature = "wide")
1753))]
1754crate::macros::conversions::decl_cross_width_narrowing!(wide D57, crate::int::types::Int<3>, D76, crate::int::types::Int<4>);
1755
1756// D76 ↔ D115
1757#[cfg(all(
1758    any(feature = "d76", feature = "wide"),
1759    any(feature = "d115", feature = "wide")
1760))]
1761crate::macros::conversions::decl_cross_width_widening!(wide D115, crate::int::types::Int<6>, D76, crate::int::types::Int<4>);
1762#[cfg(all(
1763    any(feature = "d76", feature = "wide"),
1764    any(feature = "d115", feature = "wide")
1765))]
1766crate::macros::conversions::decl_cross_width_narrowing!(wide D76, crate::int::types::Int<4>, D115, crate::int::types::Int<6>);
1767
1768// D115 ↔ D153
1769#[cfg(all(
1770    any(feature = "d115", feature = "wide"),
1771    any(feature = "d153", feature = "wide")
1772))]
1773crate::macros::conversions::decl_cross_width_widening!(wide D153, crate::int::types::Int<8>, D115, crate::int::types::Int<6>);
1774#[cfg(all(
1775    any(feature = "d115", feature = "wide"),
1776    any(feature = "d153", feature = "wide")
1777))]
1778crate::macros::conversions::decl_cross_width_narrowing!(wide D115, crate::int::types::Int<6>, D153, crate::int::types::Int<8>);
1779
1780// D153 ↔ D230
1781#[cfg(all(
1782    any(feature = "d153", feature = "wide"),
1783    any(feature = "d230", feature = "wide")
1784))]
1785crate::macros::conversions::decl_cross_width_widening!(wide D230, crate::int::types::Int<12>, D153, crate::int::types::Int<8>);
1786#[cfg(all(
1787    any(feature = "d153", feature = "wide"),
1788    any(feature = "d230", feature = "wide")
1789))]
1790crate::macros::conversions::decl_cross_width_narrowing!(wide D153, crate::int::types::Int<8>, D230, crate::int::types::Int<12>);
1791
1792// D230 ↔ D307
1793#[cfg(all(
1794    any(feature = "d230", feature = "wide"),
1795    any(feature = "d307", feature = "wide")
1796))]
1797crate::macros::conversions::decl_cross_width_widening!(wide D307, crate::int::types::Int<16>, D230, crate::int::types::Int<12>);
1798#[cfg(all(
1799    any(feature = "d230", feature = "wide"),
1800    any(feature = "d307", feature = "wide")
1801))]
1802crate::macros::conversions::decl_cross_width_narrowing!(wide D230, crate::int::types::Int<12>, D307, crate::int::types::Int<16>);
1803
1804// D307 ↔ D462
1805#[cfg(all(
1806    any(feature = "d307", feature = "wide"),
1807    any(feature = "d462", feature = "x-wide")
1808))]
1809crate::macros::conversions::decl_cross_width_widening!(wide D462, crate::int::types::Int<24>, D307, crate::int::types::Int<16>);
1810#[cfg(all(
1811    any(feature = "d307", feature = "wide"),
1812    any(feature = "d462", feature = "x-wide")
1813))]
1814crate::macros::conversions::decl_cross_width_narrowing!(wide D307, crate::int::types::Int<16>, D462, crate::int::types::Int<24>);
1815
1816// D462 ↔ D616
1817#[cfg(all(
1818    any(feature = "d462", feature = "x-wide"),
1819    any(feature = "d616", feature = "x-wide")
1820))]
1821crate::macros::conversions::decl_cross_width_widening!(wide D616, crate::int::types::Int<32>, D462, crate::int::types::Int<24>);
1822#[cfg(all(
1823    any(feature = "d462", feature = "x-wide"),
1824    any(feature = "d616", feature = "x-wide")
1825))]
1826crate::macros::conversions::decl_cross_width_narrowing!(wide D462, crate::int::types::Int<24>, D616, crate::int::types::Int<32>);
1827
1828// D616 ↔ D924
1829#[cfg(all(
1830    any(feature = "d616", feature = "x-wide"),
1831    any(feature = "d924", feature = "xx-wide")
1832))]
1833crate::macros::conversions::decl_cross_width_widening!(wide D924, crate::int::types::Int<48>, D616, crate::int::types::Int<32>);
1834#[cfg(all(
1835    any(feature = "d616", feature = "x-wide"),
1836    any(feature = "d924", feature = "xx-wide")
1837))]
1838crate::macros::conversions::decl_cross_width_narrowing!(wide D616, crate::int::types::Int<32>, D924, crate::int::types::Int<48>);
1839
1840// D924 ↔ D1232
1841#[cfg(all(
1842    any(feature = "d924", feature = "xx-wide"),
1843    any(feature = "d1232", feature = "xx-wide")
1844))]
1845crate::macros::conversions::decl_cross_width_widening!(wide D1232, crate::int::types::Int<64>, D924, crate::int::types::Int<48>);
1846#[cfg(all(
1847    any(feature = "d924", feature = "xx-wide"),
1848    any(feature = "d1232", feature = "xx-wide")
1849))]
1850crate::macros::conversions::decl_cross_width_narrowing!(wide D924, crate::int::types::Int<48>, D1232, crate::int::types::Int<64>);
1851
1852// .widen() / .narrow() methods on the half-width tiers — each points at the
1853// IMMEDIATE neighbour in the comprehensive ladder above. The power-of-two
1854// .widen() / .narrow() on D38/D76/D153/D307 go
1855// to the power-of-two next-up for source compatibility; users who
1856// want to traverse through the half-widths should use the methods
1857// declared here, or the From / TryFrom impls directly.
1858
1859#[cfg(any(feature = "d57", feature = "wide"))]
1860impl<const SCALE: u32> crate::D<crate::int::types::Int<3>, SCALE> {
1861    /// Demote to the immediate previous tier ([`D38`]) at the same `SCALE`.
1862    /// Returns `Err(ConvertError::Overflow)` if the value exceeds `i128` range.
1863    #[inline]
1864    pub fn narrow(self) -> Result<crate::D<crate::int::types::Int<2>, SCALE>, crate::support::error::ConvertError> {
1865        self.try_into()
1866    }
1867}
1868
1869// `widen` lives in a neighbour-gated impl: D57 can be enabled without
1870// D76 (e.g. `--features d57`), in which case D76 doesn't exist as a
1871// type and an unconditional `widen` would not compile.
1872#[cfg(all(
1873    any(feature = "d57", feature = "wide"),
1874    any(feature = "d76", feature = "wide"),
1875))]
1876impl<const SCALE: u32> crate::D<crate::int::types::Int<3>, SCALE> {
1877    /// Promote to the next storage tier ([`D76`]) at the same `SCALE`. Lossless.
1878    #[inline]
1879    #[must_use]
1880    pub fn widen(self) -> crate::D<crate::int::types::Int<4>, SCALE> {
1881        self.into()
1882    }
1883}
1884
1885// Each gap tier's `narrow` / `widen` lives in a neighbour-gated impl:
1886// a single-tier build (e.g. `--features d115`) enables neither the
1887// lower nor the upper neighbour, so referencing those types from an
1888// unconditional method would not compile. (Same pattern as the
1889// D616 → D924 split below.)
1890#[cfg(all(
1891    any(feature = "d115", feature = "wide"),
1892    any(feature = "d76", feature = "wide"),
1893))]
1894impl<const SCALE: u32> crate::D<crate::int::types::Int<6>, SCALE> {
1895    /// Demote to the immediate previous tier ([`D76`]) at the same `SCALE`.
1896    #[inline]
1897    pub fn narrow(self) -> Result<crate::D<crate::int::types::Int<4>, SCALE>, crate::support::error::ConvertError> {
1898        self.try_into()
1899    }
1900}
1901
1902#[cfg(all(
1903    any(feature = "d115", feature = "wide"),
1904    any(feature = "d153", feature = "wide"),
1905))]
1906impl<const SCALE: u32> crate::D<crate::int::types::Int<6>, SCALE> {
1907    /// Promote to the next storage tier ([`D153`]) at the same `SCALE`. Lossless.
1908    #[inline]
1909    #[must_use]
1910    pub fn widen(self) -> crate::D<crate::int::types::Int<8>, SCALE> {
1911        self.into()
1912    }
1913}
1914
1915#[cfg(all(
1916    any(feature = "d230", feature = "wide"),
1917    any(feature = "d153", feature = "wide"),
1918))]
1919impl<const SCALE: u32> crate::D<crate::int::types::Int<12>, SCALE> {
1920    /// Demote to the immediate previous tier ([`D153`]) at the same `SCALE`.
1921    #[inline]
1922    pub fn narrow(self) -> Result<crate::D<crate::int::types::Int<8>, SCALE>, crate::support::error::ConvertError> {
1923        self.try_into()
1924    }
1925}
1926
1927#[cfg(all(
1928    any(feature = "d230", feature = "wide"),
1929    any(feature = "d307", feature = "wide"),
1930))]
1931impl<const SCALE: u32> crate::D<crate::int::types::Int<12>, SCALE> {
1932    /// Promote to the next storage tier ([`D307`]) at the same `SCALE`. Lossless.
1933    #[inline]
1934    #[must_use]
1935    pub fn widen(self) -> crate::D<crate::int::types::Int<16>, SCALE> {
1936        self.into()
1937    }
1938}
1939
1940#[cfg(all(
1941    any(feature = "d462", feature = "x-wide"),
1942    any(feature = "d307", feature = "wide"),
1943))]
1944impl<const SCALE: u32> crate::D<crate::int::types::Int<24>, SCALE> {
1945    /// Demote to the immediate previous tier ([`D307`]) at the same `SCALE`.
1946    #[inline]
1947    pub fn narrow(self) -> Result<crate::D<crate::int::types::Int<16>, SCALE>, crate::support::error::ConvertError> {
1948        self.try_into()
1949    }
1950}
1951
1952#[cfg(all(
1953    any(feature = "d462", feature = "x-wide"),
1954    any(feature = "d616", feature = "x-wide"),
1955))]
1956impl<const SCALE: u32> crate::D<crate::int::types::Int<24>, SCALE> {
1957    /// Promote to the next storage tier ([`D616`]) at the same `SCALE`. Lossless.
1958    #[inline]
1959    #[must_use]
1960    pub fn widen(self) -> crate::D<crate::int::types::Int<32>, SCALE> {
1961        self.into()
1962    }
1963}
1964
1965#[cfg(all(
1966    any(feature = "d616", feature = "x-wide"),
1967    any(feature = "d462", feature = "x-wide"),
1968))]
1969impl<const SCALE: u32> crate::D<crate::int::types::Int<32>, SCALE> {
1970    /// Demote to the immediate previous tier ([`D462`]) at the same `SCALE`.
1971    #[inline]
1972    pub fn narrow(self) -> Result<crate::D<crate::int::types::Int<24>, SCALE>, crate::support::error::ConvertError> {
1973        self.try_into()
1974    }
1975}
1976
1977// `widen` lives in a second impl gated on D924's feature — D616 can
1978// be enabled without xx-wide (docs.rs builds this case), in which
1979// case D924 doesn't exist as a type and the unconditional `widen`
1980// method above breaks the doc build.
1981#[cfg(all(
1982    any(feature = "d616", feature = "x-wide"),
1983    any(feature = "d924", feature = "xx-wide"),
1984))]
1985impl<const SCALE: u32> crate::D<crate::int::types::Int<32>, SCALE> {
1986    /// Promote to the next storage tier ([`D924`]) at the same `SCALE`. Lossless.
1987    #[inline]
1988    #[must_use]
1989    pub fn widen(self) -> crate::D<crate::int::types::Int<48>, SCALE> {
1990        self.into()
1991    }
1992}
1993
1994#[cfg(all(
1995    any(feature = "d924", feature = "xx-wide"),
1996    any(feature = "d616", feature = "x-wide"),
1997))]
1998impl<const SCALE: u32> crate::D<crate::int::types::Int<48>, SCALE> {
1999    /// Demote to the immediate previous tier ([`D616`]) at the same `SCALE`.
2000    #[inline]
2001    pub fn narrow(self) -> Result<crate::D<crate::int::types::Int<32>, SCALE>, crate::support::error::ConvertError> {
2002        self.try_into()
2003    }
2004}
2005
2006#[cfg(all(
2007    any(feature = "d924", feature = "xx-wide"),
2008    any(feature = "d1232", feature = "xx-wide"),
2009))]
2010impl<const SCALE: u32> crate::D<crate::int::types::Int<48>, SCALE> {
2011    /// Promote to the next storage tier ([`D1232`]) at the same `SCALE`. Lossless.
2012    #[inline]
2013    #[must_use]
2014    pub fn widen(self) -> crate::D<crate::int::types::Int<64>, SCALE> {
2015        self.into()
2016    }
2017}
2018
2019#[cfg(all(
2020    any(feature = "d1232", feature = "xx-wide"),
2021    any(feature = "d924", feature = "xx-wide"),
2022))]
2023impl<const SCALE: u32> crate::D<crate::int::types::Int<64>, SCALE> {
2024    /// Demote to the immediate previous tier ([`D924`]) at the same `SCALE`.
2025    /// D1232 is the widest shipped tier, so there is no `.widen()` method.
2026    #[inline]
2027    pub fn narrow(self) -> Result<crate::D<crate::int::types::Int<48>, SCALE>, crate::support::error::ConvertError> {
2028        self.try_into()
2029    }
2030}
2031
2032// ─── Const-generic width sugar: `widen_n` / `narrow_n` ─────────────────
2033//
2034// Direct decimal-level mirror of the int-layer const base
2035// (`Int::resize_n` / `Int::try_narrow`, story 1.2.1): one const-generic
2036// pair on `D<Int<N>, SCALE>` that hops to ANY target width `M` in a
2037// single call, at the SAME scale (a pure width conversion — exact, no
2038// `RoundingMode`). Both delegate straight to the int const base, so they
2039// are usable in `const` context.
2040//
2041// Named with the `_n` suffix — NOT plain `widen` / `narrow` — for the
2042// same reason `Int::resize_n` carries it: the per-width tiers above
2043// already define inherent `widen(self)` / `narrow(self)` (no turbofish,
2044// single-tier hops kept for source compatibility), and a second inherent
2045// method of the same name on the aliased `D<Int<N>, SCALE>` would be a
2046// duplicate definition (E0592). The `_n` const-generic methods compose
2047// freely with those: `widen()` is `widen_n::<NEIGHBOUR>()`.
2048impl<const N: usize, const SCALE: u32> crate::D<crate::int::types::Int<N>, SCALE> {
2049    /// Widen to a wider storage `Int<M>` (`M >= N`) at the same `SCALE`.
2050    /// Sign-extends; always lossless. `const`.
2051    ///
2052    /// Mirror of [`crate::int::types::Int::widen`] lifted to the decimal
2053    /// wrapper: the logical value is unchanged, only the storage width
2054    /// grows. Use [`Self::narrow_n`] for the fallible reverse hop and the
2055    /// existing per-tier [`D38::widen`]-style methods for single-tier
2056    /// neighbour hops.
2057    #[inline]
2058    #[must_use]
2059    pub const fn widen_n<const M: usize>(self) -> crate::D<crate::int::types::Int<M>, SCALE> {
2060        debug_assert!(M >= N, "widen_n requires M >= N");
2061        crate::D(self.0.resize_n::<M>())
2062    }
2063
2064    /// Narrow to a narrower storage `Int<M>` (`1 <= M <= N`) at the same
2065    /// `SCALE`. Returns `None` when the value does not fit `Int<M>` as
2066    /// two's complement. `const`.
2067    ///
2068    /// Mirror of [`crate::int::types::Int::narrow`] lifted to the decimal
2069    /// wrapper. The narrowest decimal storage is `Int<1>` (D18), so a
2070    /// `narrow_n::<0>()` is meaningless and is rejected by the int base's
2071    /// `1 <= M` debug-assert.
2072    #[inline]
2073    pub const fn narrow_n<const M: usize>(
2074        self,
2075    ) -> Option<crate::D<crate::int::types::Int<M>, SCALE>> {
2076        match self.0.try_narrow::<M>() {
2077            Some(raw) => Some(crate::D(raw)),
2078            None => None,
2079        }
2080    }
2081}
2082
2083// ─── Cross-scale-op constructors + comparators ─────────────────────────
2084//
2085// One invocation per width emits `mul_of`, `add_of`, `sub_of`, `div_of`,
2086// `rem_of`, `max_of`, `min_of`, `clamp_of`, `cmp_of`, `eq_of`, `ne_of`,
2087// `lt_of`, `le_of`, `gt_of`, `ge_of` (plus the `_with(mode)` siblings
2088// for the constructors that involve a possibly-lossy rescale of inputs).
2089// Operands of any width ≤ Self's storage are accepted via the
2090// `WidthLE` bound; operands of any SCALE are accepted via the
2091// const-generic `S1` / `S2` parameters. See
2092// `crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops` for
2093// the body.
2094
2095crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D18, crate::int::types::Int<1>);
2096crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D38, crate::int::types::Int<2>);
2097
2098#[cfg(any(feature = "d57", feature = "wide"))]
2099crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D57, crate::int::types::Int<3>);
2100
2101#[cfg(any(feature = "d76", feature = "wide"))]
2102crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D76, crate::int::types::Int<4>);
2103
2104#[cfg(any(feature = "d115", feature = "wide"))]
2105crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D115, crate::int::types::Int<6>);
2106
2107#[cfg(any(feature = "d153", feature = "wide"))]
2108crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D153, crate::int::types::Int<8>);
2109
2110#[cfg(any(feature = "d230", feature = "wide"))]
2111crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D230, crate::int::types::Int<12>);
2112
2113#[cfg(any(feature = "d307", feature = "wide"))]
2114crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D307, crate::int::types::Int<16>);
2115
2116#[cfg(any(feature = "d462", feature = "x-wide"))]
2117crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D462, crate::int::types::Int<24>);
2118
2119#[cfg(any(feature = "d616", feature = "x-wide"))]
2120crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D616, crate::int::types::Int<32>);
2121
2122#[cfg(any(feature = "d924", feature = "xx-wide"))]
2123crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D924, crate::int::types::Int<48>);
2124
2125#[cfg(any(feature = "d1232", feature = "xx-wide"))]
2126crate::macros::cross_scale_ops::decl_decimal_cross_scale_ops!(D1232, crate::int::types::Int<64>);