Skip to main content

oximedia_ml/
error.rs

1//! Error types for `oximedia-ml`.
2//!
3//! Every fallible operation in the crate returns [`MlResult<T>`], which
4//! is an alias for `Result<T, MlError>`. The variants are designed so
5//! call sites never need to reach into backend-specific error types:
6//! backend failures are flattened into [`MlError::OnnxRuntime`] or
7//! [`MlError::ModelLoad`], and user-supplied data problems surface as
8//! [`MlError::InvalidInput`] / [`MlError::Preprocess`] /
9//! [`MlError::Postprocess`].
10//!
11//! ## Pattern
12//!
13//! ```no_run
14//! use oximedia_ml::{MlError, MlResult};
15//!
16//! fn check_top_k(k: usize) -> MlResult<()> {
17//!     if k == 0 {
18//!         return Err(MlError::invalid_input("top_k must be >= 1"));
19//!     }
20//!     Ok(())
21//! }
22//! ```
23//!
24//! The [`MlError::pipeline`], [`MlError::invalid_input`],
25//! [`MlError::preprocess`], and [`MlError::postprocess`] constructors
26//! accept anything `Into<String>` so integrators can propagate rich
27//! messages without allocating at call sites that already have owned
28//! strings.
29
30use std::path::PathBuf;
31use thiserror::Error;
32
33/// Result alias for ML operations.
34///
35/// All fallible APIs in this crate return `MlResult<T>`; pattern-match
36/// on [`MlError`] to handle the different failure categories.
37pub type MlResult<T> = Result<T, MlError>;
38
39/// Errors surfaced by oximedia-ml.
40///
41/// Construct user-facing failures with [`MlError::invalid_input`],
42/// [`MlError::preprocess`], [`MlError::postprocess`], or
43/// [`MlError::pipeline`]; the remaining variants are usually produced by
44/// the crate itself and matched on at call sites.
45#[derive(Debug, Error)]
46pub enum MlError {
47    /// The requested device is either unknown, unavailable, or built without its feature flag.
48    #[error("device '{0}' is not available in this build")]
49    DeviceUnavailable(String),
50
51    /// A feature required to perform the operation is disabled.
52    #[error("required feature '{0}' is not enabled (re-build oximedia-ml with --features {0})")]
53    FeatureDisabled(&'static str),
54
55    /// The model file could not be loaded from disk.
56    #[error("failed to load model at {path}: {reason}")]
57    ModelLoad {
58        /// Model path that failed to load.
59        path: PathBuf,
60        /// Human-readable reason provided by the backend.
61        reason: String,
62    },
63
64    /// Input tensor(s) did not match the model's contract.
65    #[error("invalid input: {0}")]
66    InvalidInput(String),
67
68    /// Pre-processing failed (e.g. image dimensions don't fit).
69    #[error("preprocess error: {0}")]
70    Preprocess(String),
71
72    /// Post-processing failed (e.g. reading an output tensor).
73    #[error("postprocess error: {0}")]
74    Postprocess(String),
75
76    /// A pipeline sub-component failed to execute.
77    #[error("pipeline error ({stage}): {message}")]
78    Pipeline {
79        /// Pipeline stage that raised the error.
80        stage: &'static str,
81        /// Descriptive error message.
82        message: String,
83    },
84
85    /// The cache capacity was zero, which is invalid.
86    #[error("model cache capacity must be at least 1")]
87    CacheCapacityZero,
88
89    /// Underlying ONNX runtime error (feature-gated).
90    #[error("onnx runtime error: {0}")]
91    OnnxRuntime(String),
92}
93
94impl MlError {
95    /// Convenience constructor for pipeline errors.
96    #[must_use]
97    pub fn pipeline(stage: &'static str, message: impl Into<String>) -> Self {
98        Self::Pipeline {
99            stage,
100            message: message.into(),
101        }
102    }
103
104    /// Convenience constructor for invalid input errors.
105    #[must_use]
106    pub fn invalid_input(message: impl Into<String>) -> Self {
107        Self::InvalidInput(message.into())
108    }
109
110    /// Convenience constructor for preprocess errors.
111    #[must_use]
112    pub fn preprocess(message: impl Into<String>) -> Self {
113        Self::Preprocess(message.into())
114    }
115
116    /// Convenience constructor for postprocess errors.
117    #[must_use]
118    pub fn postprocess(message: impl Into<String>) -> Self {
119        Self::Postprocess(message.into())
120    }
121}