1use core::num::TryFromIntError;
8use std::error::Error;
9use std::string::FromUtf8Error;
10use std::{cell, io, result, str};
11
12#[cfg(feature = "arrow")]
13use arrow_schema::ArrowError;
14
15#[derive(Debug)]
19#[non_exhaustive]
20pub enum ParquetError {
21 General(String),
24 NYI(String),
27 EOF(String),
31 #[cfg(feature = "arrow")]
32 ArrowError(String),
35 IndexOutOfBound(usize, usize),
38 External(Box<dyn Error + Send + Sync>),
40 NeedMoreData(usize),
43 NeedMoreDataRange(std::ops::Range<u64>),
46}
47
48impl std::fmt::Display for ParquetError {
49 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
50 match &self {
51 ParquetError::General(message) => {
52 write!(fmt, "Parquet error: {message}")
53 }
54 ParquetError::NYI(message) => write!(fmt, "NYI: {message}"),
55 ParquetError::EOF(message) => write!(fmt, "EOF: {message}"),
56 #[cfg(feature = "arrow")]
57 ParquetError::ArrowError(message) => write!(fmt, "Arrow: {message}"),
58 ParquetError::IndexOutOfBound(index, bound) => {
59 write!(fmt, "Index {index} out of bound: {bound}")
60 }
61 ParquetError::External(e) => write!(fmt, "External: {e}"),
62 ParquetError::NeedMoreData(needed) => write!(fmt, "NeedMoreData: {needed}"),
63 ParquetError::NeedMoreDataRange(range) => {
64 write!(fmt, "NeedMoreDataRange: {}..{}", range.start, range.end)
65 }
66 }
67 }
68}
69
70impl Error for ParquetError {
71 fn source(&self) -> Option<&(dyn Error + 'static)> {
72 match self {
73 ParquetError::External(e) => Some(e.as_ref()),
74 _ => None,
75 }
76 }
77}
78
79impl From<TryFromIntError> for ParquetError {
80 fn from(e: TryFromIntError) -> ParquetError {
81 ParquetError::General(format!("Integer overflow: {e}"))
82 }
83}
84
85impl From<io::Error> for ParquetError {
86 fn from(e: io::Error) -> ParquetError {
87 ParquetError::External(Box::new(e))
88 }
89}
90
91#[cfg(any(feature = "snap", test))]
92impl From<snap::Error> for ParquetError {
93 fn from(e: snap::Error) -> ParquetError {
94 ParquetError::External(Box::new(e))
95 }
96}
97
98impl From<cell::BorrowMutError> for ParquetError {
99 fn from(e: cell::BorrowMutError) -> ParquetError {
100 ParquetError::External(Box::new(e))
101 }
102}
103
104impl From<str::Utf8Error> for ParquetError {
105 fn from(e: str::Utf8Error) -> ParquetError {
106 ParquetError::External(Box::new(e))
107 }
108}
109
110impl From<FromUtf8Error> for ParquetError {
111 fn from(e: FromUtf8Error) -> ParquetError {
112 ParquetError::External(Box::new(e))
113 }
114}
115
116#[cfg(feature = "arrow")]
117impl From<ArrowError> for ParquetError {
118 fn from(e: ArrowError) -> ParquetError {
119 ParquetError::External(Box::new(e))
120 }
121}
122
123#[cfg(feature = "object_store")]
124impl From<object_store::Error> for ParquetError {
125 fn from(e: object_store::Error) -> ParquetError {
126 ParquetError::External(Box::new(e))
127 }
128}
129
130#[cfg(feature = "encryption")]
131impl From<ring::error::Unspecified> for ParquetError {
132 fn from(e: ring::error::Unspecified) -> ParquetError {
133 ParquetError::External(Box::new(e))
134 }
135}
136
137pub type Result<T, E = ParquetError> = result::Result<T, E>;
139
140impl From<ParquetError> for io::Error {
144 fn from(e: ParquetError) -> Self {
145 io::Error::other(e)
146 }
147}
148
149macro_rules! general_err {
153 ($fmt:literal) => (ParquetError::General(format!($fmt)));
154 ($fmt:expr) => (ParquetError::General($fmt.to_owned()));
155 ($fmt:expr, $($args:expr),*) => (ParquetError::General(format!($fmt, $($args),*)));
156 ($e:expr, $fmt:expr) => (ParquetError::General($fmt.to_owned(), $e));
157 ($e:ident, $fmt:expr, $($args:tt),*) => (
158 ParquetError::General(&format!($fmt, $($args),*), $e));
159}
160
161macro_rules! nyi_err {
162 ($fmt:literal) => (ParquetError::NYI(format!($fmt)));
163 ($fmt:expr) => (ParquetError::NYI($fmt.to_owned()));
164 ($fmt:expr, $($args:expr),*) => (ParquetError::NYI(format!($fmt, $($args),*)));
165}
166
167macro_rules! eof_err {
168 ($fmt:literal) => (ParquetError::EOF(format!($fmt)));
169 ($fmt:expr) => (ParquetError::EOF($fmt.to_owned()));
170 ($fmt:expr, $($args:expr),*) => (ParquetError::EOF(format!($fmt, $($args),*)));
171}
172
173#[cfg(feature = "arrow")]
174macro_rules! arrow_err {
175 ($fmt:literal) => (ParquetError::ArrowError(format!($fmt)));
176 ($fmt:expr) => (ParquetError::ArrowError($fmt.to_owned()));
177 ($fmt:expr, $($args:expr),*) => (ParquetError::ArrowError(format!($fmt, $($args),*)));
178 ($e:expr, $fmt:expr) => (ParquetError::ArrowError($fmt.to_owned(), $e));
179 ($e:ident, $fmt:expr, $($args:tt),*) => (
180 ParquetError::ArrowError(&format!($fmt, $($args),*), $e));
181}
182
183#[cfg(feature = "arrow")]
187impl From<ParquetError> for ArrowError {
188 fn from(p: ParquetError) -> Self {
189 Self::ParquetError(format!("{p}"))
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
200 fn error_macros_format_inline_args() {
201 let expected = 1;
202 let actual = 2;
203 assert_eq!(
204 general_err!("expected {expected}, got {actual}").to_string(),
205 "Parquet error: expected 1, got 2"
206 );
207 assert_eq!(
208 nyi_err!("not yet: {expected}").to_string(),
209 "NYI: not yet: 1"
210 );
211 assert_eq!(eof_err!("eof at {actual}").to_string(), "EOF: eof at 2");
212 }
213}