Skip to main content

fpm_rs/
error.rs

1//! Error categories returned by validation, numerical, I/O, and bundle operations.
2//!
3//! Public functions return [`Result`], whose error type is [`enum@Error`]. Match variants
4//! when a caller can recover from a specific category; otherwise propagate the error.
5
6use thiserror::Error;
7
8/// Crate-wide result type using [`enum@Error`].
9pub type Result<T> = std::result::Result<T, Error>;
10
11/// Errors produced by fpm-rs public operations.
12#[derive(Debug, Error)]
13pub enum Error {
14    /// A supplied or derived array shape is empty, inconsistent, or unsupported.
15    #[error("invalid shape: {0}")]
16    InvalidShape(String),
17    /// A named scalar or option falls outside its accepted domain.
18    #[error("invalid parameter `{name}`: {reason}")]
19    InvalidParameter {
20        /// Stable parameter name.
21        name: &'static str,
22        /// Explanation of the rejected value or relationship.
23        reason: String,
24    },
25    /// A compiled image-plane model violates a model invariant.
26    #[error("model validation failed: {0}")]
27    InvalidModel(String),
28    /// Measurements or their metadata are incompatible or invalid.
29    #[error("measurement validation failed: {0}")]
30    InvalidMeasurements(String),
31    /// A flat two-dimensional buffer length does not match its `(height, width)` shape.
32    #[error("array length {actual} does not match shape {shape:?} (expected {expected})")]
33    LengthMismatch {
34        /// Number of supplied elements.
35        actual: usize,
36        /// Number of elements required by `shape`.
37        expected: usize,
38        /// Requested `(height, width)` shape.
39        shape: (usize, usize),
40    },
41    /// A flat buffer length does not match a general-dimensional shape.
42    #[error("array length {actual} does not match shape {shape:?} (expected {expected})")]
43    ArrayLengthMismatch {
44        /// Number of supplied elements.
45        actual: usize,
46        /// Number of required elements.
47        expected: usize,
48        /// Requested axis lengths.
49        shape: Vec<usize>,
50    },
51    /// Multiplying the dimensions of an array shape overflowed addressable storage.
52    #[error("array shape {shape:?} overflows addressable storage")]
53    ShapeOverflow {
54        /// Axis lengths whose product overflowed.
55        shape: Vec<usize>,
56    },
57    /// An ndarray input is not C-contiguous standard row-major storage.
58    #[error(
59        "{context} with shape {shape:?} and strides {strides:?} is not C-contiguous standard row-major layout"
60    )]
61    NonStandardLayout {
62        /// User-facing name of the offending value.
63        context: &'static str,
64        /// Logical axis lengths.
65        shape: Vec<usize>,
66        /// Element strides reported by ndarray.
67        strides: Vec<isize>,
68    },
69    /// ndarray rejected a requested shape or storage layout.
70    #[error("ndarray shape construction failed: {0}")]
71    NdarrayShape(#[from] ndarray::ShapeError),
72    /// A requested acquisition-frame index is outside `0..frames`.
73    #[error("frame index {index} is out of range for {frames} frames")]
74    FrameOutOfRange {
75        /// Requested zero-based frame index.
76        index: usize,
77        /// Available frame count.
78        frames: usize,
79    },
80    /// A numerical operation produced an invalid or unusable value.
81    #[error("numerical error: {0}")]
82    Numerical(String),
83    /// The requested operation is not implemented for the supplied input.
84    #[error("unsupported operation: {0}")]
85    Unsupported(String),
86    /// Dataset discovery, download, verification, or loading failed.
87    #[error("dataset error: {0}")]
88    Dataset(String),
89    /// A result or benchmark bundle uses an unsupported manifest version.
90    #[error("unsupported bundle format version {actual}; supported version is {supported}")]
91    UnsupportedBundleVersion {
92        /// Version found in the manifest.
93        actual: u32,
94        /// Version supported by this build.
95        supported: u32,
96    },
97    /// A bundle manifest is malformed or violates the bundle contract.
98    #[error("invalid bundle manifest: {0}")]
99    InvalidManifest(String),
100    /// A manifest-declared bundle artifact is absent.
101    #[error("bundle artifact `{role}` is missing")]
102    MissingArtifact {
103        /// Stable artifact role from the manifest.
104        role: String,
105    },
106    /// A bundle artifact's bytes do not match its declared SHA-256 digest.
107    #[error("bundle artifact `{role}` has an invalid SHA-256 digest")]
108    ArtifactHashMismatch {
109        /// Stable artifact role from the manifest.
110        role: String,
111    },
112    /// A Parquet artifact does not have the schema required for its role.
113    #[error("bundle artifact `{role}` has an invalid Parquet schema: {reason}")]
114    InvalidParquetSchema {
115        /// Stable artifact role from the manifest.
116        role: String,
117        /// Description of the schema mismatch.
118        reason: String,
119    },
120    /// Artifacts within one bundle disagree about the run identifier.
121    #[error("bundle artifact has run ID `{actual}`, expected `{expected}`")]
122    InconsistentRunId {
123        /// Run identifier required by the bundle manifest.
124        expected: String,
125        /// Run identifier found in an artifact.
126        actual: String,
127    },
128    /// A stored NPY array has a shape inconsistent with its artifact role.
129    #[error("bundle array `{role}` has invalid shape: {reason}")]
130    InvalidArrayShape {
131        /// Stable array role from the manifest.
132        role: String,
133        /// Description of the shape mismatch.
134        reason: String,
135    },
136    /// A stored NPY array has the wrong element dtype for its role.
137    #[error("bundle array `{role}` has invalid dtype `{actual}`, expected `{expected}`")]
138    InvalidArrayDtype {
139        /// Stable array role from the manifest.
140        role: String,
141        /// Dtype encoded by the array file.
142        actual: String,
143        /// Dtype required for the artifact role.
144        expected: String,
145    },
146    /// A bundle manifest names an artifact role unknown to this version.
147    #[error("unsupported bundle artifact role `{0}")]
148    UnsupportedArtifactRole(String),
149    /// A bundle artifact path is absolute or escapes the bundle directory.
150    #[error("invalid relative bundle artifact path `{0}")]
151    InvalidRelativePath(String),
152    /// A temporary bundle workspace is missing required output before publication.
153    #[error("bundle workspace is incomplete: {0}")]
154    IncompleteBundle(String),
155    /// An operation delegated to Polars failed.
156    #[cfg(feature = "tabular")]
157    #[error("Polars error: {0}")]
158    Polars(#[from] polars::error::PolarsError),
159    /// A filesystem or stream operation failed.
160    #[error("I/O error: {0}")]
161    Io(#[from] std::io::Error),
162    /// Reading or writing CSV data failed.
163    #[error("CSV error: {0}")]
164    Csv(#[from] csv::Error),
165    /// Decoding or encoding a general image failed.
166    #[error("image error: {0}")]
167    Image(#[from] image::ImageError),
168    /// Reading a TIFF stack failed.
169    #[error("TIFF error: {0}")]
170    Tiff(#[from] tiff::TiffError),
171    /// JSON serialization or deserialization failed.
172    #[error("serialization error: {0}")]
173    Serialization(#[from] serde_json::Error),
174}