1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// SPDX-FileCopyrightText: 2026 John Moxley
// SPDX-License-Identifier: MIT OR Apache-2.0
//! Mul policy — the per-`(N, SCALE)` algorithm matcher for decimal
//! multiplication.
//!
//! `D<Int<N>, SCALE>::mul_with` delegates directly to the one shared
//! [`dispatch`] generic function, which follows the canonical policy shape
//! (see `docs/ARCHITECTURE.md` → "Policy file structure"):
//!
//! 1. an [`Algorithm`] enum — the real multiply algorithms, no `Default`
//! variant;
//! 2. a [`Select`] verdict — a settled algorithm or "the value decides"
//! (mul has no value split, so `ByValue` is never returned);
//! 3. a `const fn` [`select`] keyed on `(N, SCALE)`, total over the key;
//! 4. dispatch via an inline `const { select::<N, SCALE>() }` block, then
//! an **exhaustive** `match algo` — no `_`, no panic.
//!
//! Because `select` is `const` and keyed only on the const generics, the
//! `const { … }` block folds per monomorphisation and every unchosen arm
//! is dead-arm-eliminated in release: each concrete `D<Int<N>, SCALE>`
//! compiles to a direct call to one kernel, no runtime branch.
//!
//! # Work width — expanded in limbs, no `Int<2N>` type
//!
//! Decimal multiplication forms `a * b`, which spans up to `2N` limbs,
//! before dividing by `10^SCALE`. Rather than thread a work *type* `Int<2N>`
//! (unnameable from `N` on stable), the [`WidenDivide`](Algorithm::WidenDivide)
//! kernel does that arithmetic directly in a `ComputeLimbs` limb buffer and
//! divides via the shared MG / Newton magnitude-slice cores. So `dispatch`
//! carries no work-width parameter and the policy stays a pure `(N, SCALE)`
//! matcher; it adds only `where Limbs<N>: ComputeLimbs` for the scratch buffer.
//!
//! # Why there is only one selected algorithm
//!
//! Decimal multiply has two internal paths (a fast path when the product
//! fits `Int<N>`, and a widening path), but both are implementation details
//! of the single `mul_widen_divide` algorithm. `Schoolbook` is an unrouted
//! benchmarkable reference seam (no MG / Newton, plain int `div_rem`).
use crate;
use crateInt;
use crateRoundingMode;
// ── 1. the real multiply algorithms — NAMED, no `Default` ─────────────
/// The multiply algorithms this policy chooses between. Variants are the
/// CamelCase of each kernel fn's name minus the `mul_` prefix
/// (`mul_widen_divide` → `WidenDivide`, `mul_schoolbook` → `Schoolbook`).
// ── 2. the verdict ────────────────────────────────────────────────────
/// A settled algorithm, or "the value decides". The mul picker always
/// returns `ByAlgorithm`; `ByValue` is part of the canonical shape for
/// uniformity and `select` never returns it.
// ── 3. the matcher: const, keyed on `(N, SCALE)`, total over the key ──
/// Pick the multiply algorithm for storage limb count `N` and decimal
/// `SCALE`. Total over the key; `WidenDivide` wins at every `(N, SCALE)`.
const
// ── 4. the shared dispatch: resolve the verdict, then dispatch ────────
/// Decimal multiply dispatch for storage `Int<N>` and decimal `SCALE`.
///
/// The `const { select }` block folds away at every concrete `N`, leaving a
/// direct call to the chosen kernel. `dispatch` delegates *down* to the
/// generic-over-`N` kernel; the `2N`-wide product lives in the kernel's
/// `ComputeLimbs` scratch buffer, so no work-width type is named here.
pub