1#![deny(missing_docs)]
2
3#[cfg(feature = "python")]
7pub mod python;
8
9mod ext;
10
11use std::backtrace::Backtrace;
12use std::borrow::Cow;
13use std::convert::Infallible;
14use std::error::Error;
15use std::fmt::{Debug, Display, Formatter};
16use std::num::TryFromIntError;
17use std::ops::Deref;
18use std::sync::{Arc, PoisonError};
19use std::{env, fmt, io};
20
21pub use ext::*;
22
23#[derive(Debug)]
25pub struct ErrString(Cow<'static, str>);
26
27#[allow(clippy::fallible_impl_from)]
28impl<T> From<T> for ErrString
29where
30 T: Into<Cow<'static, str>>,
31{
32 #[allow(clippy::panic)]
33 fn from(msg: T) -> Self {
34 if env::var("VORTEX_PANIC_ON_ERR").as_deref().unwrap_or("") == "1" {
35 panic!("{}\nBacktrace:\n{}", msg.into(), Backtrace::capture());
36 } else {
37 Self(msg.into())
38 }
39 }
40}
41
42impl AsRef<str> for ErrString {
43 fn as_ref(&self) -> &str {
44 &self.0
45 }
46}
47
48impl Deref for ErrString {
49 type Target = str;
50
51 fn deref(&self) -> &Self::Target {
52 &self.0
53 }
54}
55
56impl Display for ErrString {
57 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
58 Display::fmt(&self.0, f)
59 }
60}
61
62impl From<Infallible> for VortexError {
63 fn from(_: Infallible) -> Self {
64 unreachable!()
65 }
66}
67
68#[non_exhaustive]
70pub enum VortexError {
71 Generic(Box<dyn Error + Send + Sync + 'static>, Backtrace),
73 OutOfBounds(usize, usize, usize, Backtrace),
75 ComputeError(ErrString, Backtrace),
77 InvalidArgument(ErrString, Backtrace),
79 InvalidState(ErrString, Backtrace),
81 InvalidSerde(ErrString, Backtrace),
83 NotImplemented(ErrString, ErrString, Backtrace),
85 MismatchedTypes(ErrString, ErrString, Backtrace),
87 AssertionFailed(ErrString, Backtrace),
89 Context(ErrString, Box<VortexError>),
91 Shared(Arc<VortexError>),
93 ArrowError(arrow_schema::ArrowError, Backtrace),
95 #[cfg(feature = "flatbuffers")]
97 FlatBuffersError(flatbuffers::InvalidFlatbuffer, Backtrace),
98 FmtError(fmt::Error, Backtrace),
100 IOError(io::Error, Backtrace),
102 Utf8Error(std::str::Utf8Error, Backtrace),
104 #[cfg(feature = "parquet")]
106 ParquetError(parquet::errors::ParquetError, Backtrace),
107 TryFromSliceError(std::array::TryFromSliceError, Backtrace),
109 #[cfg(feature = "worker")]
111 WorkerError(worker::Error, Backtrace),
112 #[cfg(feature = "object_store")]
114 ObjectStore(object_store::Error, Backtrace),
115 JiffError(jiff::Error, Backtrace),
117 #[cfg(feature = "tokio")]
119 JoinError(tokio::task::JoinError, Backtrace),
120 UrlError(url::ParseError, Backtrace),
122 TryFromInt(TryFromIntError, Backtrace),
124 #[cfg(feature = "serde")]
126 SerdeJsonError(serde_json::Error, Backtrace),
127 #[cfg(feature = "prost")]
129 ProstEncodeError(prost::EncodeError, Backtrace),
130 #[cfg(feature = "prost")]
132 ProstDecodeError(prost::DecodeError, Backtrace),
133 #[cfg(feature = "prost")]
135 ProstUnknownEnumValue(prost::UnknownEnumValue, Backtrace),
136}
137
138impl VortexError {
139 pub fn with_context<T: Into<ErrString>>(self, msg: T) -> Self {
141 VortexError::Context(msg.into(), Box::new(self))
142 }
143}
144
145impl Display for VortexError {
146 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
147 match self {
148 VortexError::Generic(err, backtrace) => {
149 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
150 }
151 VortexError::OutOfBounds(idx, start, stop, backtrace) => {
152 write!(
153 f,
154 "index {} out of bounds from {} to {}\nBacktrace:\n{}",
155 idx, start, stop, backtrace
156 )
157 }
158 VortexError::ComputeError(msg, backtrace) => {
159 write!(f, "{}\nBacktrace:\n{}", msg, backtrace)
160 }
161 VortexError::InvalidArgument(msg, backtrace) => {
162 write!(f, "{}\nBacktrace:\n{}", msg, backtrace)
163 }
164 VortexError::InvalidState(msg, backtrace) => {
165 write!(f, "{}\nBacktrace:\n{}", msg, backtrace)
166 }
167 VortexError::InvalidSerde(msg, backtrace) => {
168 write!(f, "{}\nBacktrace:\n{}", msg, backtrace)
169 }
170 VortexError::NotImplemented(func, by_whom, backtrace) => {
171 write!(
172 f,
173 "function {} not implemented for {}\nBacktrace:\n{}",
174 func, by_whom, backtrace
175 )
176 }
177 VortexError::MismatchedTypes(expected, actual, backtrace) => {
178 write!(
179 f,
180 "expected type: {} but instead got {}\nBacktrace:\n{}",
181 expected, actual, backtrace
182 )
183 }
184 VortexError::AssertionFailed(msg, backtrace) => {
185 write!(f, "{}\nBacktrace:\n{}", msg, backtrace)
186 }
187 VortexError::Context(msg, inner) => {
188 write!(f, "{}: {}", msg, inner)
189 }
190 VortexError::Shared(inner) => Display::fmt(inner, f),
191 VortexError::ArrowError(err, backtrace) => {
192 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
193 }
194 #[cfg(feature = "flatbuffers")]
195 VortexError::FlatBuffersError(err, backtrace) => {
196 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
197 }
198 VortexError::FmtError(err, backtrace) => {
199 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
200 }
201 VortexError::IOError(err, backtrace) => {
202 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
203 }
204 VortexError::Utf8Error(err, backtrace) => {
205 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
206 }
207 #[cfg(feature = "parquet")]
208 VortexError::ParquetError(err, backtrace) => {
209 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
210 }
211 VortexError::TryFromSliceError(err, backtrace) => {
212 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
213 }
214 #[cfg(feature = "worker")]
215 VortexError::WorkerError(err, backtrace) => {
216 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
217 }
218 #[cfg(feature = "object_store")]
219 VortexError::ObjectStore(err, backtrace) => {
220 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
221 }
222 VortexError::JiffError(err, backtrace) => {
223 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
224 }
225 #[cfg(feature = "tokio")]
226 VortexError::JoinError(err, backtrace) => {
227 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
228 }
229 VortexError::UrlError(err, backtrace) => {
230 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
231 }
232 VortexError::TryFromInt(err, backtrace) => {
233 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
234 }
235 #[cfg(feature = "serde")]
236 VortexError::SerdeJsonError(err, backtrace) => {
237 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
238 }
239 #[cfg(feature = "prost")]
240 VortexError::ProstEncodeError(err, backtrace) => {
241 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
242 }
243 #[cfg(feature = "prost")]
244 VortexError::ProstDecodeError(err, backtrace) => {
245 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
246 }
247 #[cfg(feature = "prost")]
248 VortexError::ProstUnknownEnumValue(err, backtrace) => {
249 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
250 }
251 }
252 }
253}
254
255impl Error for VortexError {
256 fn source(&self) -> Option<&(dyn Error + 'static)> {
257 match self {
258 VortexError::Generic(err, _) => Some(err.as_ref()),
259 VortexError::Context(_, inner) => inner.source(),
260 VortexError::Shared(inner) => inner.source(),
261 VortexError::ArrowError(err, _) => Some(err),
262 #[cfg(feature = "flatbuffers")]
263 VortexError::FlatBuffersError(err, _) => Some(err),
264 VortexError::FmtError(err, _) => Some(err),
265 VortexError::IOError(err, _) => Some(err),
266 VortexError::Utf8Error(err, _) => Some(err),
267 #[cfg(feature = "parquet")]
268 VortexError::ParquetError(err, _) => Some(err),
269 VortexError::TryFromSliceError(err, _) => Some(err),
270 #[cfg(feature = "worker")]
271 VortexError::WorkerError(err, _) => Some(err),
272 #[cfg(feature = "object_store")]
273 VortexError::ObjectStore(err, _) => Some(err),
274 VortexError::JiffError(err, _) => Some(err),
275 #[cfg(feature = "tokio")]
276 VortexError::JoinError(err, _) => Some(err),
277 VortexError::UrlError(err, _) => Some(err),
278 VortexError::TryFromInt(err, _) => Some(err),
279 #[cfg(feature = "serde")]
280 VortexError::SerdeJsonError(err, _) => Some(err),
281 #[cfg(feature = "prost")]
282 VortexError::ProstEncodeError(err, _) => Some(err),
283 #[cfg(feature = "prost")]
284 VortexError::ProstDecodeError(err, _) => Some(err),
285 #[cfg(feature = "prost")]
286 VortexError::ProstUnknownEnumValue(err, _) => Some(err),
287 _ => None,
288 }
289 }
290}
291
292impl Debug for VortexError {
293 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
294 Display::fmt(self, f)
295 }
296}
297
298pub type VortexResult<T> = Result<T, VortexError>;
300
301pub type SharedVortexResult<T> = Result<T, Arc<VortexError>>;
303
304impl From<Arc<VortexError>> for VortexError {
305 fn from(value: Arc<VortexError>) -> Self {
306 Self::from(&value)
307 }
308}
309
310impl From<&Arc<VortexError>> for VortexError {
311 fn from(e: &Arc<VortexError>) -> Self {
312 if let VortexError::Shared(e_inner) = e.as_ref() {
313 VortexError::Shared(Arc::clone(e_inner))
315 } else {
316 VortexError::Shared(Arc::clone(e))
317 }
318 }
319}
320
321pub trait VortexUnwrap {
323 type Output;
325
326 fn vortex_unwrap(self) -> Self::Output;
329}
330
331impl<T, E> VortexUnwrap for Result<T, E>
332where
333 E: Into<VortexError>,
334{
335 type Output = T;
336
337 #[inline(always)]
338 fn vortex_unwrap(self) -> Self::Output {
339 self.map_err(|err| err.into())
340 .unwrap_or_else(|err| vortex_panic!(err))
341 }
342}
343
344pub trait VortexExpect {
346 type Output;
348
349 fn vortex_expect(self, msg: &str) -> Self::Output;
352}
353
354impl<T, E> VortexExpect for Result<T, E>
355where
356 E: Into<VortexError>,
357{
358 type Output = T;
359
360 #[inline(always)]
361 fn vortex_expect(self, msg: &str) -> Self::Output {
362 self.map_err(|err| err.into())
363 .unwrap_or_else(|e| vortex_panic!(e.with_context(msg.to_string())))
364 }
365}
366
367impl<T> VortexExpect for Option<T> {
368 type Output = T;
369
370 #[inline(always)]
371 fn vortex_expect(self, msg: &str) -> Self::Output {
372 self.unwrap_or_else(|| {
373 let err = VortexError::AssertionFailed(msg.to_string().into(), Backtrace::capture());
374 vortex_panic!(err)
375 })
376 }
377}
378
379#[macro_export]
381macro_rules! vortex_err {
382 (AssertionFailed: $($tts:tt)*) => {{
383 use std::backtrace::Backtrace;
384 let err_string = format!($($tts)*);
385 $crate::__private::must_use(
386 $crate::VortexError::AssertionFailed(err_string.into(), Backtrace::capture())
387 )
388 }};
389 (IOError: $($tts:tt)*) => {{
390 use std::backtrace::Backtrace;
391 $crate::__private::must_use(
392 $crate::VortexError::IOError(err_string.into(), Backtrace::capture())
393 )
394 }};
395 (OutOfBounds: $idx:expr, $start:expr, $stop:expr) => {{
396 use std::backtrace::Backtrace;
397 $crate::__private::must_use(
398 $crate::VortexError::OutOfBounds($idx, $start, $stop, Backtrace::capture())
399 )
400 }};
401 (NotImplemented: $func:expr, $by_whom:expr) => {{
402 use std::backtrace::Backtrace;
403 $crate::__private::must_use(
404 $crate::VortexError::NotImplemented($func.into(), format!("{}", $by_whom).into(), Backtrace::capture())
405 )
406 }};
407 (MismatchedTypes: $expected:literal, $actual:expr) => {{
408 use std::backtrace::Backtrace;
409 $crate::__private::must_use(
410 $crate::VortexError::MismatchedTypes($expected.into(), $actual.to_string().into(), Backtrace::capture())
411 )
412 }};
413 (MismatchedTypes: $expected:expr, $actual:expr) => {{
414 use std::backtrace::Backtrace;
415 $crate::__private::must_use(
416 $crate::VortexError::MismatchedTypes($expected.to_string().into(), $actual.to_string().into(), Backtrace::capture())
417 )
418 }};
419 (Context: $msg:literal, $err:expr) => {{
420 $crate::__private::must_use(
421 $crate::VortexError::Context($msg.into(), Box::new($err))
422 )
423 }};
424 ($variant:ident: $fmt:literal $(, $arg:expr)* $(,)?) => {{
425 use std::backtrace::Backtrace;
426 $crate::__private::must_use(
427 $crate::VortexError::$variant(format!($fmt, $($arg),*).into(), Backtrace::capture())
428 )
429 }};
430 ($variant:ident: $err:expr $(,)?) => {
431 $crate::__private::must_use(
432 $crate::VortexError::$variant($err)
433 )
434 };
435 ($fmt:literal $(, $arg:expr)* $(,)?) => {
436 $crate::vortex_err!(InvalidArgument: $fmt, $($arg),*)
437 };
438}
439
440#[macro_export]
442macro_rules! vortex_bail {
443 ($($tt:tt)+) => {
444 return Err($crate::vortex_err!($($tt)+))
445 };
446}
447
448#[macro_export]
451macro_rules! vortex_panic {
452 (OutOfBounds: $idx:expr, $start:expr, $stop:expr) => {{
453 $crate::vortex_panic!($crate::vortex_err!(OutOfBounds: $idx, $start, $stop))
454 }};
455 (NotImplemented: $func:expr, $for_whom:expr) => {{
456 $crate::vortex_panic!($crate::vortex_err!(NotImplemented: $func, $for_whom))
457 }};
458 (MismatchedTypes: $expected:literal, $actual:expr) => {{
459 $crate::vortex_panic!($crate::vortex_err!(MismatchedTypes: $expected, $actual))
460 }};
461 (MismatchedTypes: $expected:expr, $actual:expr) => {{
462 $crate::vortex_panic!($crate::vortex_err!(MismatchedTypes: $expected, $actual))
463 }};
464 (Context: $msg:literal, $err:expr) => {{
465 $crate::vortex_panic!($crate::vortex_err!(Context: $msg, $err))
466 }};
467 ($variant:ident: $fmt:literal $(, $arg:expr)* $(,)?) => {
468 $crate::vortex_panic!($crate::vortex_err!($variant: $fmt, $($arg),*))
469 };
470 ($err:expr, $fmt:literal $(, $arg:expr)* $(,)?) => {{
471 let err: $crate::VortexError = $err;
472 panic!("{}", err.with_context(format!($fmt, $($arg),*)))
473 }};
474 ($fmt:literal $(, $arg:expr)* $(,)?) => {
475 $crate::vortex_panic!($crate::vortex_err!($fmt, $($arg),*))
476 };
477 ($err:expr) => {{
478 let err: $crate::VortexError = $err;
479 panic!("{}", err)
480 }};
481}
482
483impl From<arrow_schema::ArrowError> for VortexError {
484 fn from(value: arrow_schema::ArrowError) -> Self {
485 VortexError::ArrowError(value, Backtrace::capture())
486 }
487}
488
489#[cfg(feature = "flatbuffers")]
490impl From<flatbuffers::InvalidFlatbuffer> for VortexError {
491 fn from(value: flatbuffers::InvalidFlatbuffer) -> Self {
492 VortexError::FlatBuffersError(value, Backtrace::capture())
493 }
494}
495
496impl From<fmt::Error> for VortexError {
497 fn from(value: fmt::Error) -> Self {
498 VortexError::FmtError(value, Backtrace::capture())
499 }
500}
501
502impl From<io::Error> for VortexError {
503 fn from(value: io::Error) -> Self {
504 VortexError::IOError(value, Backtrace::capture())
505 }
506}
507
508impl From<std::str::Utf8Error> for VortexError {
509 fn from(value: std::str::Utf8Error) -> Self {
510 VortexError::Utf8Error(value, Backtrace::capture())
511 }
512}
513
514#[cfg(feature = "parquet")]
515impl From<parquet::errors::ParquetError> for VortexError {
516 fn from(value: parquet::errors::ParquetError) -> Self {
517 VortexError::ParquetError(value, Backtrace::capture())
518 }
519}
520
521impl From<std::array::TryFromSliceError> for VortexError {
522 fn from(value: std::array::TryFromSliceError) -> Self {
523 VortexError::TryFromSliceError(value, Backtrace::capture())
524 }
525}
526
527#[cfg(feature = "worker")]
528impl From<worker::Error> for VortexError {
529 fn from(value: worker::Error) -> Self {
530 VortexError::WorkerError(value, Backtrace::capture())
531 }
532}
533
534#[cfg(feature = "object_store")]
535impl From<object_store::Error> for VortexError {
536 fn from(value: object_store::Error) -> Self {
537 VortexError::ObjectStore(value, Backtrace::capture())
538 }
539}
540
541impl From<jiff::Error> for VortexError {
542 fn from(value: jiff::Error) -> Self {
543 VortexError::JiffError(value, Backtrace::capture())
544 }
545}
546
547#[cfg(feature = "tokio")]
548impl From<tokio::task::JoinError> for VortexError {
549 fn from(value: tokio::task::JoinError) -> Self {
550 VortexError::JoinError(value, Backtrace::capture())
551 }
552}
553
554impl From<url::ParseError> for VortexError {
555 fn from(value: url::ParseError) -> Self {
556 VortexError::UrlError(value, Backtrace::capture())
557 }
558}
559
560impl From<TryFromIntError> for VortexError {
561 fn from(value: TryFromIntError) -> Self {
562 VortexError::TryFromInt(value, Backtrace::capture())
563 }
564}
565
566#[cfg(feature = "serde")]
567impl From<serde_json::Error> for VortexError {
568 fn from(value: serde_json::Error) -> Self {
569 VortexError::SerdeJsonError(value, Backtrace::capture())
570 }
571}
572
573#[cfg(feature = "prost")]
574impl From<prost::EncodeError> for VortexError {
575 fn from(value: prost::EncodeError) -> Self {
576 VortexError::ProstEncodeError(value, Backtrace::capture())
577 }
578}
579
580#[cfg(feature = "prost")]
581impl From<prost::DecodeError> for VortexError {
582 fn from(value: prost::DecodeError) -> Self {
583 VortexError::ProstDecodeError(value, Backtrace::capture())
584 }
585}
586
587#[cfg(feature = "prost")]
588impl From<prost::UnknownEnumValue> for VortexError {
589 fn from(value: prost::UnknownEnumValue) -> Self {
590 VortexError::ProstUnknownEnumValue(value, Backtrace::capture())
591 }
592}
593
594#[doc(hidden)]
596pub mod __private {
597 #[doc(hidden)]
598 #[inline]
599 #[cold]
600 #[must_use]
601 pub const fn must_use(error: crate::VortexError) -> crate::VortexError {
602 error
603 }
604}
605
606#[cfg(feature = "worker")]
607impl From<VortexError> for worker::Error {
608 fn from(value: VortexError) -> Self {
609 Self::RustError(value.to_string())
610 }
611}
612
613impl<T> From<PoisonError<T>> for VortexError {
614 fn from(_value: PoisonError<T>) -> Self {
615 Self::InvalidState("Lock poisoned".into(), Backtrace::capture())
617 }
618}