1use std::fmt;
4use std::io;
5
6use crate::block::BlockError;
7
8#[derive(Debug)]
10pub enum MolRsError {
11 Block(BlockError),
13
14 Io(io::Error),
16
17 Parse {
19 line: Option<usize>,
21 message: String,
23 },
24
25 Validation {
27 message: String,
29 },
30
31 #[cfg(feature = "zarr")]
33 Zarr {
34 message: String,
36 },
37
38 NotFound {
40 entity: &'static str,
42 message: String,
44 },
45
46 Other(String),
48}
49
50impl fmt::Display for MolRsError {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 match self {
53 MolRsError::Block(e) => write!(f, "Block error: {}", e),
54 MolRsError::Io(e) => write!(f, "IO error: {}", e),
55 MolRsError::Parse {
56 line: Some(line),
57 message,
58 } => {
59 write!(f, "Parse error at line {}: {}", line, message)
60 }
61 MolRsError::Parse {
62 line: None,
63 message,
64 } => {
65 write!(f, "Parse error: {}", message)
66 }
67 MolRsError::Validation { message } => {
68 write!(f, "Validation error: {}", message)
69 }
70 MolRsError::NotFound { entity, message } => {
71 write!(f, "{} not found: {}", entity, message)
72 }
73 #[cfg(feature = "zarr")]
74 MolRsError::Zarr { message } => {
75 write!(f, "Zarr error: {}", message)
76 }
77 MolRsError::Other(msg) => write!(f, "{}", msg),
78 }
79 }
80}
81
82impl std::error::Error for MolRsError {
83 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
84 match self {
85 MolRsError::Block(e) => Some(e),
86 MolRsError::Io(e) => Some(e),
87 _ => None,
88 }
89 }
90}
91
92impl From<BlockError> for MolRsError {
94 fn from(err: BlockError) -> Self {
95 MolRsError::Block(err)
96 }
97}
98
99impl From<io::Error> for MolRsError {
100 fn from(err: io::Error) -> Self {
101 MolRsError::Io(err)
102 }
103}
104
105impl From<String> for MolRsError {
106 fn from(msg: String) -> Self {
107 MolRsError::Other(msg)
108 }
109}
110
111impl From<&str> for MolRsError {
112 fn from(msg: &str) -> Self {
113 MolRsError::Other(msg.to_string())
114 }
115}
116
117impl MolRsError {
119 pub fn parse_error(line: usize, message: impl Into<String>) -> Self {
121 MolRsError::Parse {
122 line: Some(line),
123 message: message.into(),
124 }
125 }
126
127 pub fn parse(message: impl Into<String>) -> Self {
129 MolRsError::Parse {
130 line: None,
131 message: message.into(),
132 }
133 }
134
135 pub fn validation(message: impl Into<String>) -> Self {
137 MolRsError::Validation {
138 message: message.into(),
139 }
140 }
141
142 pub fn not_found(entity: &'static str, message: impl Into<String>) -> Self {
144 MolRsError::NotFound {
145 entity,
146 message: message.into(),
147 }
148 }
149
150 #[cfg(feature = "zarr")]
152 pub fn zarr(message: impl Into<String>) -> Self {
153 MolRsError::Zarr {
154 message: message.into(),
155 }
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 use crate::block::BlockError;
163
164 #[test]
165 fn test_error_display() {
166 let err = MolRsError::parse_error(42, "unexpected token");
167 assert_eq!(
168 format!("{}", err),
169 "Parse error at line 42: unexpected token"
170 );
171
172 let err = MolRsError::parse("invalid format");
173 assert_eq!(format!("{}", err), "Parse error: invalid format");
174
175 let err = MolRsError::validation("inconsistent dimensions");
176 assert_eq!(
177 format!("{}", err),
178 "Validation error: inconsistent dimensions"
179 );
180 }
181
182 #[test]
183 fn test_from_block_error() {
184 let block_err = BlockError::RankZero {
185 key: "test".to_string(),
186 };
187 let err: MolRsError = block_err.into();
188 assert!(matches!(err, MolRsError::Block(_)));
189 }
190
191 #[test]
192 fn test_from_string() {
193 let err: MolRsError = "test error".into();
194 assert!(matches!(err, MolRsError::Other(_)));
195 assert_eq!(format!("{}", err), "test error");
196 }
197}