Skip to main content

datarust_profile/
error.rs

1//! Error types returned by datarust-profile.
2
3use std::error::Error as StdError;
4use std::fmt;
5
6/// Errors returned by profiling operations.
7#[derive(Debug)]
8pub enum ProfileError {
9    /// The supplied data is malformed or otherwise invalid for the operation.
10    InvalidInput(String),
11    /// An empty dataset (zero rows or zero columns) was provided.
12    EmptyInput(String),
13    /// A failure propagated from the underlying `datarust` crate.
14    Datarust(datarust::error::DatarustError),
15    /// An IO failure while reading from or writing to disk.
16    Io(std::io::Error),
17    /// A (de)serialization failure (e.g. malformed JSON). Only present under the
18    /// `serde` feature.
19    #[cfg(feature = "serde")]
20    Serde(serde_json::Error),
21}
22
23impl fmt::Display for ProfileError {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        match self {
26            ProfileError::InvalidInput(s) => write!(f, "invalid input: {}", s),
27            ProfileError::EmptyInput(s) => write!(f, "empty input: {}", s),
28            ProfileError::Datarust(e) => write!(f, "datarust error: {}", e),
29            ProfileError::Io(e) => write!(f, "io error: {}", e),
30            #[cfg(feature = "serde")]
31            ProfileError::Serde(e) => write!(f, "serialization error: {}", e),
32        }
33    }
34}
35
36impl StdError for ProfileError {
37    fn source(&self) -> Option<&(dyn StdError + 'static)> {
38        match self {
39            ProfileError::Datarust(e) => Some(e),
40            ProfileError::Io(e) => Some(e),
41            #[cfg(feature = "serde")]
42            ProfileError::Serde(e) => Some(e),
43            _ => None,
44        }
45    }
46}
47
48impl From<datarust::error::DatarustError> for ProfileError {
49    fn from(e: datarust::error::DatarustError) -> Self {
50        ProfileError::Datarust(e)
51    }
52}
53
54impl From<std::io::Error> for ProfileError {
55    fn from(e: std::io::Error) -> Self {
56        ProfileError::Io(e)
57    }
58}
59
60#[cfg(feature = "serde")]
61impl From<serde_json::Error> for ProfileError {
62    fn from(e: serde_json::Error) -> Self {
63        ProfileError::Serde(e)
64    }
65}
66
67/// The canonical `Result` type alias used throughout the crate.
68pub type Result<T> = std::result::Result<T, ProfileError>;
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn display_invalid_input() {
76        let e = ProfileError::InvalidInput("bad".to_string());
77        assert_eq!(e.to_string(), "invalid input: bad");
78    }
79
80    #[test]
81    fn display_empty_input() {
82        let e = ProfileError::EmptyInput("0 rows".to_string());
83        assert_eq!(e.to_string(), "empty input: 0 rows");
84    }
85
86    #[test]
87    fn display_io() {
88        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
89        let e = ProfileError::Io(io_err);
90        assert_eq!(e.to_string(), "io error: file missing");
91    }
92
93    #[test]
94    fn source_invalid_input() {
95        let e = ProfileError::InvalidInput("x".to_string());
96        assert!(e.source().is_none());
97    }
98
99    #[test]
100    fn source_empty_input() {
101        let e = ProfileError::EmptyInput("x".to_string());
102        assert!(e.source().is_none());
103    }
104
105    #[test]
106    fn source_io() {
107        let io_err = std::io::Error::new(std::io::ErrorKind::Other, "oops");
108        let e = ProfileError::Io(io_err);
109        assert!(e.source().is_some());
110    }
111
112    #[test]
113    fn from_datarust_error() {
114        let dr_err = datarust::error::DatarustError::ShapeMismatch {
115            expected: "(2, 2)".to_string(),
116            actual: "(3, 3)".to_string(),
117        };
118        let e: ProfileError = dr_err.into();
119        assert!(e.to_string().contains("datarust error"));
120        assert!(e.source().is_some());
121    }
122
123    #[test]
124    fn from_io_error() {
125        let io_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "denied");
126        let e: ProfileError = io_err.into();
127        assert!(e.to_string().contains("io error"));
128    }
129
130    #[test]
131    fn debug_is_impl() {
132        let e = ProfileError::InvalidInput("test".to_string());
133        let debug = format!("{:?}", e);
134        assert!(debug.contains("InvalidInput"));
135    }
136}