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