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 = "object_store")]
111 ObjectStore(object_store::Error, Backtrace),
112 JiffError(jiff::Error, Backtrace),
114 #[cfg(feature = "tokio")]
116 JoinError(tokio::task::JoinError, Backtrace),
117 UrlError(url::ParseError, Backtrace),
119 TryFromInt(TryFromIntError, Backtrace),
121 #[cfg(feature = "serde")]
123 SerdeJsonError(serde_json::Error, Backtrace),
124 #[cfg(feature = "prost")]
126 ProstEncodeError(prost::EncodeError, Backtrace),
127 #[cfg(feature = "prost")]
129 ProstDecodeError(prost::DecodeError, Backtrace),
130 #[cfg(feature = "prost")]
132 ProstUnknownEnumValue(prost::UnknownEnumValue, Backtrace),
133}
134
135impl VortexError {
136 pub fn with_context<T: Into<ErrString>>(self, msg: T) -> Self {
138 VortexError::Context(msg.into(), Box::new(self))
139 }
140}
141
142impl Display for VortexError {
143 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
144 match self {
145 VortexError::Generic(err, backtrace) => {
146 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
147 }
148 VortexError::OutOfBounds(idx, start, stop, backtrace) => {
149 write!(
150 f,
151 "index {} out of bounds from {} to {}\nBacktrace:\n{}",
152 idx, start, stop, backtrace
153 )
154 }
155 VortexError::ComputeError(msg, backtrace) => {
156 write!(f, "{}\nBacktrace:\n{}", msg, backtrace)
157 }
158 VortexError::InvalidArgument(msg, backtrace) => {
159 write!(f, "{}\nBacktrace:\n{}", msg, backtrace)
160 }
161 VortexError::InvalidState(msg, backtrace) => {
162 write!(f, "{}\nBacktrace:\n{}", msg, backtrace)
163 }
164 VortexError::InvalidSerde(msg, backtrace) => {
165 write!(f, "{}\nBacktrace:\n{}", msg, backtrace)
166 }
167 VortexError::NotImplemented(func, by_whom, backtrace) => {
168 write!(
169 f,
170 "function {} not implemented for {}\nBacktrace:\n{}",
171 func, by_whom, backtrace
172 )
173 }
174 VortexError::MismatchedTypes(expected, actual, backtrace) => {
175 write!(
176 f,
177 "expected type: {} but instead got {}\nBacktrace:\n{}",
178 expected, actual, backtrace
179 )
180 }
181 VortexError::AssertionFailed(msg, backtrace) => {
182 write!(f, "{}\nBacktrace:\n{}", msg, backtrace)
183 }
184 VortexError::Context(msg, inner) => {
185 write!(f, "{}: {}", msg, inner)
186 }
187 VortexError::Shared(inner) => Display::fmt(inner, f),
188 VortexError::ArrowError(err, backtrace) => {
189 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
190 }
191 #[cfg(feature = "flatbuffers")]
192 VortexError::FlatBuffersError(err, backtrace) => {
193 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
194 }
195 VortexError::FmtError(err, backtrace) => {
196 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
197 }
198 VortexError::IOError(err, backtrace) => {
199 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
200 }
201 VortexError::Utf8Error(err, backtrace) => {
202 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
203 }
204 #[cfg(feature = "parquet")]
205 VortexError::ParquetError(err, backtrace) => {
206 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
207 }
208 VortexError::TryFromSliceError(err, backtrace) => {
209 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
210 }
211 #[cfg(feature = "object_store")]
212 VortexError::ObjectStore(err, backtrace) => {
213 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
214 }
215 VortexError::JiffError(err, backtrace) => {
216 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
217 }
218 #[cfg(feature = "tokio")]
219 VortexError::JoinError(err, backtrace) => {
220 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
221 }
222 VortexError::UrlError(err, backtrace) => {
223 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
224 }
225 VortexError::TryFromInt(err, backtrace) => {
226 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
227 }
228 #[cfg(feature = "serde")]
229 VortexError::SerdeJsonError(err, backtrace) => {
230 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
231 }
232 #[cfg(feature = "prost")]
233 VortexError::ProstEncodeError(err, backtrace) => {
234 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
235 }
236 #[cfg(feature = "prost")]
237 VortexError::ProstDecodeError(err, backtrace) => {
238 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
239 }
240 #[cfg(feature = "prost")]
241 VortexError::ProstUnknownEnumValue(err, backtrace) => {
242 write!(f, "{}\nBacktrace:\n{}", err, backtrace)
243 }
244 }
245 }
246}
247
248impl Error for VortexError {
249 fn source(&self) -> Option<&(dyn Error + 'static)> {
250 match self {
251 VortexError::Generic(err, _) => Some(err.as_ref()),
252 VortexError::Context(_, inner) => inner.source(),
253 VortexError::Shared(inner) => inner.source(),
254 VortexError::ArrowError(err, _) => Some(err),
255 #[cfg(feature = "flatbuffers")]
256 VortexError::FlatBuffersError(err, _) => Some(err),
257 VortexError::FmtError(err, _) => Some(err),
258 VortexError::IOError(err, _) => Some(err),
259 VortexError::Utf8Error(err, _) => Some(err),
260 #[cfg(feature = "parquet")]
261 VortexError::ParquetError(err, _) => Some(err),
262 VortexError::TryFromSliceError(err, _) => Some(err),
263 #[cfg(feature = "object_store")]
264 VortexError::ObjectStore(err, _) => Some(err),
265 VortexError::JiffError(err, _) => Some(err),
266 #[cfg(feature = "tokio")]
267 VortexError::JoinError(err, _) => Some(err),
268 VortexError::UrlError(err, _) => Some(err),
269 VortexError::TryFromInt(err, _) => Some(err),
270 #[cfg(feature = "serde")]
271 VortexError::SerdeJsonError(err, _) => Some(err),
272 #[cfg(feature = "prost")]
273 VortexError::ProstEncodeError(err, _) => Some(err),
274 #[cfg(feature = "prost")]
275 VortexError::ProstDecodeError(err, _) => Some(err),
276 #[cfg(feature = "prost")]
277 VortexError::ProstUnknownEnumValue(err, _) => Some(err),
278 _ => None,
279 }
280 }
281}
282
283impl Debug for VortexError {
284 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
285 Display::fmt(self, f)
286 }
287}
288
289pub type VortexResult<T> = Result<T, VortexError>;
291
292pub type SharedVortexResult<T> = Result<T, Arc<VortexError>>;
294
295impl From<Arc<VortexError>> for VortexError {
296 fn from(value: Arc<VortexError>) -> Self {
297 Self::from(&value)
298 }
299}
300
301impl From<&Arc<VortexError>> for VortexError {
302 fn from(e: &Arc<VortexError>) -> Self {
303 if let VortexError::Shared(e_inner) = e.as_ref() {
304 VortexError::Shared(Arc::clone(e_inner))
306 } else {
307 VortexError::Shared(Arc::clone(e))
308 }
309 }
310}
311
312pub trait VortexUnwrap {
314 type Output;
316
317 fn vortex_unwrap(self) -> Self::Output;
320}
321
322impl<T, E> VortexUnwrap for Result<T, E>
323where
324 E: Into<VortexError>,
325{
326 type Output = T;
327
328 #[inline(always)]
329 fn vortex_unwrap(self) -> Self::Output {
330 self.map_err(|err| err.into())
331 .unwrap_or_else(|err| vortex_panic!(err))
332 }
333}
334
335pub trait VortexExpect {
337 type Output;
339
340 fn vortex_expect(self, msg: &str) -> Self::Output;
343}
344
345impl<T, E> VortexExpect for Result<T, E>
346where
347 E: Into<VortexError>,
348{
349 type Output = T;
350
351 #[inline(always)]
352 fn vortex_expect(self, msg: &str) -> Self::Output {
353 self.map_err(|err| err.into())
354 .unwrap_or_else(|e| vortex_panic!(e.with_context(msg.to_string())))
355 }
356}
357
358impl<T> VortexExpect for Option<T> {
359 type Output = T;
360
361 #[inline(always)]
362 fn vortex_expect(self, msg: &str) -> Self::Output {
363 self.unwrap_or_else(|| {
364 let err = VortexError::AssertionFailed(msg.to_string().into(), Backtrace::capture());
365 vortex_panic!(err)
366 })
367 }
368}
369
370#[macro_export]
372macro_rules! vortex_err {
373 (AssertionFailed: $($tts:tt)*) => {{
374 use std::backtrace::Backtrace;
375 let err_string = format!($($tts)*);
376 $crate::__private::must_use(
377 $crate::VortexError::AssertionFailed(err_string.into(), Backtrace::capture())
378 )
379 }};
380 (IOError: $($tts:tt)*) => {{
381 use std::backtrace::Backtrace;
382 $crate::__private::must_use(
383 $crate::VortexError::IOError(err_string.into(), Backtrace::capture())
384 )
385 }};
386 (OutOfBounds: $idx:expr, $start:expr, $stop:expr) => {{
387 use std::backtrace::Backtrace;
388 $crate::__private::must_use(
389 $crate::VortexError::OutOfBounds($idx, $start, $stop, Backtrace::capture())
390 )
391 }};
392 (NotImplemented: $func:expr, $by_whom:expr) => {{
393 use std::backtrace::Backtrace;
394 $crate::__private::must_use(
395 $crate::VortexError::NotImplemented($func.into(), format!("{}", $by_whom).into(), Backtrace::capture())
396 )
397 }};
398 (MismatchedTypes: $expected:literal, $actual:expr) => {{
399 use std::backtrace::Backtrace;
400 $crate::__private::must_use(
401 $crate::VortexError::MismatchedTypes($expected.into(), $actual.to_string().into(), Backtrace::capture())
402 )
403 }};
404 (MismatchedTypes: $expected:expr, $actual:expr) => {{
405 use std::backtrace::Backtrace;
406 $crate::__private::must_use(
407 $crate::VortexError::MismatchedTypes($expected.to_string().into(), $actual.to_string().into(), Backtrace::capture())
408 )
409 }};
410 (Context: $msg:literal, $err:expr) => {{
411 $crate::__private::must_use(
412 $crate::VortexError::Context($msg.into(), Box::new($err))
413 )
414 }};
415 ($variant:ident: $fmt:literal $(, $arg:expr)* $(,)?) => {{
416 use std::backtrace::Backtrace;
417 $crate::__private::must_use(
418 $crate::VortexError::$variant(format!($fmt, $($arg),*).into(), Backtrace::capture())
419 )
420 }};
421 ($variant:ident: $err:expr $(,)?) => {
422 $crate::__private::must_use(
423 $crate::VortexError::$variant($err)
424 )
425 };
426 ($fmt:literal $(, $arg:expr)* $(,)?) => {
427 $crate::vortex_err!(InvalidArgument: $fmt, $($arg),*)
428 };
429}
430
431#[macro_export]
433macro_rules! vortex_bail {
434 ($($tt:tt)+) => {
435 return Err($crate::vortex_err!($($tt)+))
436 };
437}
438
439#[macro_export]
442macro_rules! vortex_panic {
443 (OutOfBounds: $idx:expr, $start:expr, $stop:expr) => {{
444 $crate::vortex_panic!($crate::vortex_err!(OutOfBounds: $idx, $start, $stop))
445 }};
446 (NotImplemented: $func:expr, $for_whom:expr) => {{
447 $crate::vortex_panic!($crate::vortex_err!(NotImplemented: $func, $for_whom))
448 }};
449 (MismatchedTypes: $expected:literal, $actual:expr) => {{
450 $crate::vortex_panic!($crate::vortex_err!(MismatchedTypes: $expected, $actual))
451 }};
452 (MismatchedTypes: $expected:expr, $actual:expr) => {{
453 $crate::vortex_panic!($crate::vortex_err!(MismatchedTypes: $expected, $actual))
454 }};
455 (Context: $msg:literal, $err:expr) => {{
456 $crate::vortex_panic!($crate::vortex_err!(Context: $msg, $err))
457 }};
458 ($variant:ident: $fmt:literal $(, $arg:expr)* $(,)?) => {
459 $crate::vortex_panic!($crate::vortex_err!($variant: $fmt, $($arg),*))
460 };
461 ($err:expr, $fmt:literal $(, $arg:expr)* $(,)?) => {{
462 let err: $crate::VortexError = $err;
463 panic!("{}", err.with_context(format!($fmt, $($arg),*)))
464 }};
465 ($fmt:literal $(, $arg:expr)* $(,)?) => {
466 $crate::vortex_panic!($crate::vortex_err!($fmt, $($arg),*))
467 };
468 ($err:expr) => {{
469 let err: $crate::VortexError = $err;
470 panic!("{}", err)
471 }};
472}
473
474impl From<arrow_schema::ArrowError> for VortexError {
475 fn from(value: arrow_schema::ArrowError) -> Self {
476 VortexError::ArrowError(value, Backtrace::capture())
477 }
478}
479
480#[cfg(feature = "flatbuffers")]
481impl From<flatbuffers::InvalidFlatbuffer> for VortexError {
482 fn from(value: flatbuffers::InvalidFlatbuffer) -> Self {
483 VortexError::FlatBuffersError(value, Backtrace::capture())
484 }
485}
486
487impl From<fmt::Error> for VortexError {
488 fn from(value: fmt::Error) -> Self {
489 VortexError::FmtError(value, Backtrace::capture())
490 }
491}
492
493impl From<io::Error> for VortexError {
494 fn from(value: io::Error) -> Self {
495 VortexError::IOError(value, Backtrace::capture())
496 }
497}
498
499impl From<std::str::Utf8Error> for VortexError {
500 fn from(value: std::str::Utf8Error) -> Self {
501 VortexError::Utf8Error(value, Backtrace::capture())
502 }
503}
504
505#[cfg(feature = "parquet")]
506impl From<parquet::errors::ParquetError> for VortexError {
507 fn from(value: parquet::errors::ParquetError) -> Self {
508 VortexError::ParquetError(value, Backtrace::capture())
509 }
510}
511
512impl From<std::array::TryFromSliceError> for VortexError {
513 fn from(value: std::array::TryFromSliceError) -> Self {
514 VortexError::TryFromSliceError(value, Backtrace::capture())
515 }
516}
517
518#[cfg(feature = "object_store")]
519impl From<object_store::Error> for VortexError {
520 fn from(value: object_store::Error) -> Self {
521 VortexError::ObjectStore(value, Backtrace::capture())
522 }
523}
524
525impl From<jiff::Error> for VortexError {
526 fn from(value: jiff::Error) -> Self {
527 VortexError::JiffError(value, Backtrace::capture())
528 }
529}
530
531#[cfg(feature = "tokio")]
532impl From<tokio::task::JoinError> for VortexError {
533 fn from(value: tokio::task::JoinError) -> Self {
534 VortexError::JoinError(value, Backtrace::capture())
535 }
536}
537
538impl From<url::ParseError> for VortexError {
539 fn from(value: url::ParseError) -> Self {
540 VortexError::UrlError(value, Backtrace::capture())
541 }
542}
543
544impl From<TryFromIntError> for VortexError {
545 fn from(value: TryFromIntError) -> Self {
546 VortexError::TryFromInt(value, Backtrace::capture())
547 }
548}
549
550#[cfg(feature = "serde")]
551impl From<serde_json::Error> for VortexError {
552 fn from(value: serde_json::Error) -> Self {
553 VortexError::SerdeJsonError(value, Backtrace::capture())
554 }
555}
556
557#[cfg(feature = "prost")]
558impl From<prost::EncodeError> for VortexError {
559 fn from(value: prost::EncodeError) -> Self {
560 VortexError::ProstEncodeError(value, Backtrace::capture())
561 }
562}
563
564#[cfg(feature = "prost")]
565impl From<prost::DecodeError> for VortexError {
566 fn from(value: prost::DecodeError) -> Self {
567 VortexError::ProstDecodeError(value, Backtrace::capture())
568 }
569}
570
571#[cfg(feature = "prost")]
572impl From<prost::UnknownEnumValue> for VortexError {
573 fn from(value: prost::UnknownEnumValue) -> Self {
574 VortexError::ProstUnknownEnumValue(value, Backtrace::capture())
575 }
576}
577
578#[doc(hidden)]
580pub mod __private {
581 #[doc(hidden)]
582 #[inline]
583 #[cold]
584 #[must_use]
585 pub const fn must_use(error: crate::VortexError) -> crate::VortexError {
586 error
587 }
588}
589
590impl<T> From<PoisonError<T>> for VortexError {
591 fn from(_value: PoisonError<T>) -> Self {
592 Self::InvalidState("Lock poisoned".into(), Backtrace::capture())
594 }
595}