1#![feature(error_generic_member_access)]
2#![deny(missing_docs)]
3
4#[cfg(feature = "python")]
8pub mod python;
9
10mod ext;
11
12use std::backtrace::Backtrace;
13use std::borrow::Cow;
14use std::convert::Infallible;
15use std::error::Error;
16use std::fmt::{Debug, Display, Formatter};
17use std::num::TryFromIntError;
18use std::ops::Deref;
19use std::sync::PoisonError;
20use std::{env, fmt, io};
21
22pub use ext::*;
23
24#[derive(Debug)]
26pub struct ErrString(Cow<'static, str>);
27
28#[allow(clippy::fallible_impl_from)]
29impl<T> From<T> for ErrString
30where
31 T: Into<Cow<'static, str>>,
32{
33 #[allow(clippy::panic)]
34 fn from(msg: T) -> Self {
35 if env::var("VORTEX_PANIC_ON_ERR").as_deref().unwrap_or("") == "1" {
36 panic!("{}\nBacktrace:\n{}", msg.into(), Backtrace::capture());
37 } else {
38 Self(msg.into())
39 }
40 }
41}
42
43impl AsRef<str> for ErrString {
44 fn as_ref(&self) -> &str {
45 &self.0
46 }
47}
48
49impl Deref for ErrString {
50 type Target = str;
51
52 fn deref(&self) -> &Self::Target {
53 &self.0
54 }
55}
56
57impl Display for ErrString {
58 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
59 Display::fmt(&self.0, f)
60 }
61}
62
63impl From<Infallible> for VortexError {
64 fn from(_: Infallible) -> Self {
65 unreachable!()
66 }
67}
68
69#[derive(thiserror::Error)]
71#[non_exhaustive]
72pub enum VortexError {
73 #[error("{0}\nBacktrace:\n{1}")]
75 Generic(Box<dyn Error + Send + Sync + 'static>, Backtrace),
76 #[error("index {0} out of bounds from {1} to {2}\nBacktrace:\n{3}")]
78 OutOfBounds(usize, usize, usize, Backtrace),
79 #[error("{0}\nBacktrace:\n{1}")]
81 ComputeError(ErrString, Backtrace),
82 #[error("{0}\nBacktrace:\n{1}")]
84 InvalidArgument(ErrString, Backtrace),
85 #[error("{0}\nBacktrace:\n{1}")]
87 InvalidState(ErrString, Backtrace),
88 #[error("{0}\nBacktrace:\n{1}")]
90 InvalidSerde(ErrString, Backtrace),
91 #[error("function {0} not implemented for {1}\nBacktrace:\n{2}")]
93 NotImplemented(ErrString, ErrString, Backtrace),
94 #[error("expected type: {0} but instead got {1}\nBacktrace:\n{2}")]
96 MismatchedTypes(ErrString, ErrString, Backtrace),
97 #[error("{0}\nBacktrace:\n{1}")]
99 AssertionFailed(ErrString, Backtrace),
100 #[error("{0}: {1}")]
102 Context(ErrString, #[source] Box<VortexError>),
103 #[error(transparent)]
105 ArrowError(
106 #[from]
107 #[backtrace]
108 arrow_schema::ArrowError,
109 ),
110 #[cfg(feature = "flatbuffers")]
112 #[error(transparent)]
113 FlatBuffersError(
114 #[from]
115 #[backtrace]
116 flatbuffers::InvalidFlatbuffer,
117 ),
118 #[cfg(feature = "flexbuffers")]
120 #[error(transparent)]
121 FlexBuffersReaderError(
122 #[from]
123 #[backtrace]
124 flexbuffers::ReaderError,
125 ),
126 #[cfg(feature = "flexbuffers")]
128 #[error(transparent)]
129 FlexBuffersDeError(
130 #[from]
131 #[backtrace]
132 flexbuffers::DeserializationError,
133 ),
134 #[cfg(feature = "flexbuffers")]
136 #[error(transparent)]
137 FlexBuffersSerError(
138 #[from]
139 #[backtrace]
140 flexbuffers::SerializationError,
141 ),
142 #[error(transparent)]
144 FmtError(
145 #[from]
146 #[backtrace]
147 fmt::Error,
148 ),
149 #[error(transparent)]
151 IOError(
152 #[from]
153 #[backtrace]
154 io::Error,
155 ),
156 #[error(transparent)]
158 Utf8Error(
159 #[from]
160 #[backtrace]
161 std::str::Utf8Error,
162 ),
163 #[cfg(feature = "parquet")]
165 #[error(transparent)]
166 ParquetError(
167 #[from]
168 #[backtrace]
169 parquet::errors::ParquetError,
170 ),
171 #[error(transparent)]
173 TryFromSliceError(
174 #[from]
175 #[backtrace]
176 std::array::TryFromSliceError,
177 ),
178 #[cfg(feature = "worker")]
180 #[error(transparent)]
181 WorkerError(
182 #[from]
183 #[backtrace]
184 worker::Error,
185 ),
186 #[cfg(feature = "object_store")]
188 #[error(transparent)]
189 ObjectStore(
190 #[from]
191 #[backtrace]
192 object_store::Error,
193 ),
194 #[cfg(feature = "datafusion")]
196 #[error(transparent)]
197 DataFusion(
198 #[from]
199 #[backtrace]
200 datafusion_common::DataFusionError,
201 ),
202 #[error(transparent)]
204 JiffError(
205 #[from]
206 #[backtrace]
207 jiff::Error,
208 ),
209 #[cfg(feature = "tokio")]
211 #[error(transparent)]
212 JoinError(
213 #[from]
214 #[backtrace]
215 tokio::task::JoinError,
216 ),
217 #[error(transparent)]
219 UrlError(
220 #[from]
221 #[backtrace]
222 url::ParseError,
223 ),
224 #[error(transparent)]
226 TryFromInt(
227 #[from]
228 #[backtrace]
229 TryFromIntError,
230 ),
231}
232
233impl VortexError {
234 pub fn with_context<T: Into<ErrString>>(self, msg: T) -> Self {
236 VortexError::Context(msg.into(), Box::new(self))
237 }
238}
239
240impl Debug for VortexError {
241 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
242 Display::fmt(self, f)
243 }
244}
245
246pub type VortexResult<T> = Result<T, VortexError>;
248
249pub trait VortexUnwrap {
251 type Output;
253
254 fn vortex_unwrap(self) -> Self::Output;
257}
258
259impl<T, E> VortexUnwrap for Result<T, E>
260where
261 E: Into<VortexError>,
262{
263 type Output = T;
264
265 #[inline(always)]
266 fn vortex_unwrap(self) -> Self::Output {
267 self.map_err(|err| err.into())
268 .unwrap_or_else(|err| vortex_panic!(err))
269 }
270}
271
272pub trait VortexExpect {
274 type Output;
276
277 fn vortex_expect(self, msg: &str) -> Self::Output;
280}
281
282impl<T, E> VortexExpect for Result<T, E>
283where
284 E: Into<VortexError>,
285{
286 type Output = T;
287
288 #[inline(always)]
289 fn vortex_expect(self, msg: &str) -> Self::Output {
290 self.map_err(|err| err.into())
291 .unwrap_or_else(|e| vortex_panic!(e.with_context(msg.to_string())))
292 }
293}
294
295impl<T> VortexExpect for Option<T> {
296 type Output = T;
297
298 #[inline(always)]
299 fn vortex_expect(self, msg: &str) -> Self::Output {
300 self.unwrap_or_else(|| {
301 let err = VortexError::AssertionFailed(msg.to_string().into(), Backtrace::capture());
302 vortex_panic!(err)
303 })
304 }
305}
306
307#[macro_export]
309macro_rules! vortex_err {
310 (OutOfBounds: $idx:expr, $start:expr, $stop:expr) => {{
311 use std::backtrace::Backtrace;
312 $crate::__private::must_use(
313 $crate::VortexError::OutOfBounds($idx, $start, $stop, Backtrace::capture())
314 )
315 }};
316 (NotImplemented: $func:expr, $by_whom:expr) => {{
317 use std::backtrace::Backtrace;
318 $crate::__private::must_use(
319 $crate::VortexError::NotImplemented($func.into(), format!("{}", $by_whom).into(), Backtrace::capture())
320 )
321 }};
322 (MismatchedTypes: $expected:literal, $actual:expr) => {{
323 use std::backtrace::Backtrace;
324 $crate::__private::must_use(
325 $crate::VortexError::MismatchedTypes($expected.into(), $actual.to_string().into(), Backtrace::capture())
326 )
327 }};
328 (MismatchedTypes: $expected:expr, $actual:expr) => {{
329 use std::backtrace::Backtrace;
330 $crate::__private::must_use(
331 $crate::VortexError::MismatchedTypes($expected.to_string().into(), $actual.to_string().into(), Backtrace::capture())
332 )
333 }};
334 (Context: $msg:literal, $err:expr) => {{
335 $crate::__private::must_use(
336 $crate::VortexError::Context($msg.into(), Box::new($err))
337 )
338 }};
339 ($variant:ident: $fmt:literal $(, $arg:expr)* $(,)?) => {{
340 use std::backtrace::Backtrace;
341 $crate::__private::must_use(
342 $crate::VortexError::$variant(format!($fmt, $($arg),*).into(), Backtrace::capture())
343 )
344 }};
345 ($variant:ident: $err:expr $(,)?) => {
346 $crate::__private::must_use(
347 $crate::VortexError::$variant($err)
348 )
349 };
350 ($fmt:literal $(, $arg:expr)* $(,)?) => {
351 $crate::vortex_err!(InvalidArgument: $fmt, $($arg),*)
352 };
353}
354
355#[macro_export]
357macro_rules! vortex_bail {
358 ($($tt:tt)+) => {
359 return Err($crate::vortex_err!($($tt)+))
360 };
361}
362
363#[macro_export]
366macro_rules! vortex_panic {
367 (OutOfBounds: $idx:expr, $start:expr, $stop:expr) => {{
368 $crate::vortex_panic!($crate::vortex_err!(OutOfBounds: $idx, $start, $stop))
369 }};
370 (NotImplemented: $func:expr, $for_whom:expr) => {{
371 $crate::vortex_panic!($crate::vortex_err!(NotImplemented: $func, $for_whom))
372 }};
373 (MismatchedTypes: $expected:literal, $actual:expr) => {{
374 $crate::vortex_panic!($crate::vortex_err!(MismatchedTypes: $expected, $actual))
375 }};
376 (MismatchedTypes: $expected:expr, $actual:expr) => {{
377 $crate::vortex_panic!($crate::vortex_err!(MismatchedTypes: $expected, $actual))
378 }};
379 (Context: $msg:literal, $err:expr) => {{
380 $crate::vortex_panic!($crate::vortex_err!(Context: $msg, $err))
381 }};
382 ($variant:ident: $fmt:literal $(, $arg:expr)* $(,)?) => {
383 $crate::vortex_panic!($crate::vortex_err!($variant: $fmt, $($arg),*))
384 };
385 ($err:expr, $fmt:literal $(, $arg:expr)* $(,)?) => {{
386 let err: $crate::VortexError = $err;
387 panic!("{}", err.with_context(format!($fmt, $($arg),*)))
388 }};
389 ($fmt:literal $(, $arg:expr)* $(,)?) => {
390 $crate::vortex_panic!($crate::vortex_err!($fmt, $($arg),*))
391 };
392 ($err:expr) => {{
393 let err: $crate::VortexError = $err;
394 panic!("{}", err)
395 }};
396}
397
398#[cfg(feature = "datafusion")]
399impl From<VortexError> for datafusion_common::DataFusionError {
400 fn from(value: VortexError) -> Self {
401 Self::External(Box::new(value))
402 }
403}
404
405#[cfg(feature = "datafusion")]
406impl From<VortexError> for datafusion_common::arrow::error::ArrowError {
407 fn from(value: VortexError) -> Self {
408 match value {
409 VortexError::ArrowError(e) => e,
410 _ => Self::from_external_error(Box::new(value)),
411 }
412 }
413}
414
415#[doc(hidden)]
417pub mod __private {
418 #[doc(hidden)]
419 #[inline]
420 #[cold]
421 #[must_use]
422 pub const fn must_use(error: crate::VortexError) -> crate::VortexError {
423 error
424 }
425}
426
427#[cfg(feature = "rancor")]
428impl rancor::Source for VortexError {
429 fn new<T: Error + Send + Sync + 'static>(source: T) -> Self {
430 VortexError::Generic(Box::new(source), Backtrace::capture())
431 }
432}
433
434#[cfg(feature = "rancor")]
435impl rancor::Trace for VortexError {
436 fn trace<R>(self, trace: R) -> Self
437 where
438 R: Debug + Display + Send + Sync + 'static,
439 {
440 VortexError::Context(trace.to_string().into(), Box::new(self))
441 }
442}
443
444#[cfg(feature = "worker")]
445impl From<VortexError> for worker::Error {
446 fn from(value: VortexError) -> Self {
447 Self::RustError(value.to_string())
448 }
449}
450
451impl<T> From<PoisonError<T>> for VortexError {
452 fn from(_value: PoisonError<T>) -> Self {
453 Self::InvalidState("Lock poisoned".into(), Backtrace::capture())
455 }
456}