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
// SPDX-FileCopyrightText: 2026 John Moxley
// SPDX-License-Identifier: MIT OR Apache-2.0
//! Per-family policy traits — which algorithm each `Dxx<S>` calls.
//!
//! The typed method shell on each `Dxx<S>` (e.g. `D57::<SCALE>::exp_strict`)
//! delegates to the policy `dispatch` fn (`exp::dispatch`). Every family
//! follows the canonical `(N, SCALE)` matcher (`sqrt` is the exemplar): a
//! per-function `Algorithm` enum + a `const fn select<N, SCALE>()` + an
//! exhaustive `match algo`, dispatched via an inline
//! `const { select::<N, SCALE>() }` block. See [`sqrt`] and
//! `docs/ARCHITECTURE.md` → "Policy file structure".
//!
//! The keys (`N` and `SCALE`) are `const` at every monomorphisation, so
//! `select` const-folds to its single live arm — every concrete `Dxx<S>`
//! compiles to a direct call to one kernel. Zero runtime dispatch cost.
//!
//! Stable Rust does not allow trait-impl specialisation on const-generic
//! types, so a width's per-`(N, SCALE)` realisations live as arms inside
//! the canonical `match algo` (with a const-folding inner `match SCALE`
//! where one algorithm has several per-band kernels at a width) rather
//! than as separate `impl SqrtPolicy for D57<20>` blocks. The few inverse
//! / hyperbolic trig methods whose fall-through is an inherent
//! `*_strict_with` shell (not a raw-storage kernel) realise their single
//! algorithm through that shell.
// Unconditional — D18/D38 impls live here too. Wide-tier impls
// inside each family are individually feature-gated.
pub
pub
pub
pub
pub
pub
pub
pub
pub
pub
pub
pub
pub
pub
pub
pub
pub
pub
// Shared policy-layer support: the SCALE-derived work-rung selector
// (`ln` Tang + forward trig). Private to the policy layer.
pub
// ── Narrow-tier checked narrow ──────────────────────────────────────
//
// The exp/ln/log/pow policies route the narrow tier (N == 1, i.e. D18,
// and the identity N == 2, i.e. D38) by computing the result at Int<2>
// (D38 width) and narrowing back to storage. For N == 1 that narrow is
// LOSSY and must PANIC when the D38 result exceeds the i64 storage range
// (e.g. exp(5) at D18<17>), restoring the documented strict-overflow
// contract. (For N == 2 it is identity; for the wide arms N >= 3 the
// result is already computed at Int<N> and routed through their own
// resize.)
//
// `Int<2>::narrow::<N>()` cannot be used here: these arms are generic
// over N and instantiate for wide N too (dead at runtime), and the
// inherent `narrow::<M>` requires `M <= N` at compile time. Instead we
// resize to the storage width and verify the value survives a round-trip
// back to Int<2>; any discrepancy means the value did not fit and we
// panic via the shared diagnostics helper (stable substring
// `"{method}: result out of range"`).
pub
/// `Option` primitive under [`narrow_checked`]: `None` when the `Int<2>`
/// value does not survive the round-trip to `Int<N>` (i.e. it does not
/// fit the narrower storage). The `checked_*` dispatch paths propagate
/// the `None`; the default paths panic via [`narrow_checked`].
pub