gam_terms/smooth/error.rs
1//! Typed errors emitted by smooth-term helpers.
2//!
3//! Carved out of the `smooth` module along its first real seam: this is the
4//! error vocabulary every smooth-term builder shares, with no dependency on the
5//! basis/penalty/optimizer machinery that surrounds it. `Display` reproduces the
6//! exact pre-refactor `format!(...)` text byte-for-byte, so string-matching
7//! callers (tests, log assertions) keep working unchanged. Public boundaries
8//! that interface with `term_builder.rs` / `construction` continue to return
9//! `Result<_, String>`; typed `Err(...)` values flow through
10//! `From<SmoothError> for String` at those boundaries via `.into()`.
11
12use gam_problem::BlockCountMismatch;
13
14/// Typed errors emitted by smooth-term helpers in the `smooth` module.
15#[derive(Clone, Debug)]
16pub enum SmoothError {
17 /// Spec-level configuration error: unfrozen knots/centers, invalid
18 /// numeric bounds on coefficient priors, length-scale optimizer options
19 /// that violate `min > 0 < max` / `min < max` invariants, etc.
20 InvalidConfig { reason: String },
21 /// Shape / length disagreement between design columns, penalty blocks,
22 /// coefficient ranges, directional-derivative vectors, theta length, and
23 /// other bookkeeping invariants that are checked at runtime.
24 DimensionMismatch { reason: String },
25 /// Out-of-range index into adaptive hyperparameter components, psi
26 /// derivative blocks, or non-zero block indices for single-block
27 /// custom-family impls that only support `block_idx == 0`.
28 InvalidIndex { reason: String },
29}
30
31gam_linalg::impl_reason_error_boilerplate! {
32 SmoothError {
33 InvalidConfig,
34 DimensionMismatch,
35 InvalidIndex,
36 }
37}
38
39impl From<BlockCountMismatch> for SmoothError {
40 fn from(err: BlockCountMismatch) -> SmoothError {
41 SmoothError::invalid_index(err.message())
42 }
43}
44
45impl SmoothError {
46 #[inline]
47 pub fn invalid_config(reason: impl Into<String>) -> Self {
48 SmoothError::InvalidConfig {
49 reason: reason.into(),
50 }
51 }
52 #[inline]
53 pub fn dimension_mismatch(reason: impl Into<String>) -> Self {
54 SmoothError::DimensionMismatch {
55 reason: reason.into(),
56 }
57 }
58 #[inline]
59 pub fn invalid_index(reason: impl Into<String>) -> Self {
60 SmoothError::InvalidIndex {
61 reason: reason.into(),
62 }
63 }
64}