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