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::env;
16use std::error::Error;
17use std::fmt;
18use std::fmt::Debug;
19use std::fmt::Display;
20use std::fmt::Formatter;
21use std::io;
22use std::num::TryFromIntError;
23use std::ops::Deref;
24use std::sync::Arc;
25use std::sync::PoisonError;
26
27#[derive(Debug)]
29pub struct ErrString(Cow<'static, str>);
30
31#[expect(
32 clippy::fallible_impl_from,
33 reason = "intentionally panic in debug mode when VORTEX_PANIC_ON_ERR is set"
34)]
35impl<T> From<T> for ErrString
36where
37 T: Into<Cow<'static, str>>,
38{
39 #[expect(
40 clippy::panic,
41 reason = "intentionally panic in debug mode when VORTEX_PANIC_ON_ERR is set"
42 )]
43 fn from(msg: T) -> Self {
44 if env::var("VORTEX_PANIC_ON_ERR").as_deref().unwrap_or("") == "1" {
45 panic!("{}\nBacktrace:\n{}", msg.into(), Backtrace::capture());
46 } else {
47 Self(msg.into())
48 }
49 }
50}
51
52impl AsRef<str> for ErrString {
53 fn as_ref(&self) -> &str {
54 &self.0
55 }
56}
57
58impl Deref for ErrString {
59 type Target = str;
60
61 fn deref(&self) -> &Self::Target {
62 &self.0
63 }
64}
65
66impl Display for ErrString {
67 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
68 Display::fmt(&self.0, f)
69 }
70}
71
72impl From<Infallible> for VortexError {
73 fn from(_: Infallible) -> Self {
74 unreachable!()
75 }
76}
77
78const _: () = {
79 assert!(size_of::<VortexError>() < 128);
80};
81#[non_exhaustive]
83pub enum VortexError {
84 Generic(Box<dyn Error + Send + Sync + 'static>, Box<Backtrace>),
86 OutOfBounds(usize, usize, usize, Box<Backtrace>),
88 ComputeError(ErrString, Box<Backtrace>),
90 InvalidArgument(ErrString, Box<Backtrace>),
92 InvalidState(ErrString, Box<Backtrace>),
94 InvalidSerde(ErrString, Box<Backtrace>),
96 NotImplemented(ErrString, ErrString, Box<Backtrace>),
98 MismatchedTypes(ErrString, ErrString, Box<Backtrace>),
100 AssertionFailed(ErrString, Box<Backtrace>),
102 Context(ErrString, Box<VortexError>),
104 Shared(Arc<VortexError>),
106 ArrowError(arrow_schema::ArrowError, Box<Backtrace>),
108 #[cfg(feature = "flatbuffers")]
110 FlatBuffersError(flatbuffers::InvalidFlatbuffer, Box<Backtrace>),
111 FmtError(fmt::Error, Box<Backtrace>),
113 IOError(io::Error, Box<Backtrace>),
115 TryFromSliceError(std::array::TryFromSliceError, Box<Backtrace>),
117 #[cfg(feature = "object_store")]
119 ObjectStore(object_store::Error, Box<Backtrace>),
120 JiffError(jiff::Error, Box<Backtrace>),
122 #[cfg(feature = "tokio")]
124 JoinError(tokio::task::JoinError, Box<Backtrace>),
125 UrlError(url::ParseError, Box<Backtrace>),
127 TryFromInt(TryFromIntError, Box<Backtrace>),
129 #[cfg(feature = "serde")]
131 SerdeJsonError(serde_json::Error, Box<Backtrace>),
132 #[cfg(feature = "prost")]
134 ProstEncodeError(prost::EncodeError, Box<Backtrace>),
135 #[cfg(feature = "prost")]
137 ProstDecodeError(prost::DecodeError, Box<Backtrace>),
138 #[cfg(feature = "prost")]
140 ProstUnknownEnumValue(prost::UnknownEnumValue, Box<Backtrace>),
141}
142
143impl VortexError {
144 pub fn with_context<T: Into<ErrString>>(self, msg: T) -> Self {
146 VortexError::Context(msg.into(), Box::new(self))
147 }
148
149 pub fn generic(err: Box<dyn Error + Send + Sync + 'static>) -> Self {
151 Self::Generic(err, Box::new(Backtrace::capture()))
152 }
153}
154
155impl Display for VortexError {
156 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
157 match self {
158 VortexError::Generic(err, backtrace) => {
159 write!(f, "{err}\nBacktrace:\n{backtrace}")
160 }
161 VortexError::OutOfBounds(idx, start, stop, backtrace) => {
162 write!(
163 f,
164 "index {idx} out of bounds from {start} to {stop}\nBacktrace:\n{backtrace}",
165 )
166 }
167 VortexError::ComputeError(msg, backtrace) => {
168 write!(f, "{msg}\nBacktrace:\n{backtrace}")
169 }
170 VortexError::InvalidArgument(msg, backtrace) => {
171 write!(f, "{msg}\nBacktrace:\n{backtrace}")
172 }
173 VortexError::InvalidState(msg, backtrace) => {
174 write!(f, "{msg}\nBacktrace:\n{backtrace}")
175 }
176 VortexError::InvalidSerde(msg, backtrace) => {
177 write!(f, "{msg}\nBacktrace:\n{backtrace}")
178 }
179 VortexError::NotImplemented(func, by_whom, backtrace) => {
180 write!(
181 f,
182 "function {func} not implemented for {by_whom}\nBacktrace:\n{backtrace}",
183 )
184 }
185 VortexError::MismatchedTypes(expected, actual, backtrace) => {
186 write!(
187 f,
188 "expected type: {expected} but instead got {actual}\nBacktrace:\n{backtrace}",
189 )
190 }
191 VortexError::AssertionFailed(msg, backtrace) => {
192 write!(f, "{msg}\nBacktrace:\n{backtrace}")
193 }
194 VortexError::Context(msg, inner) => {
195 write!(f, "{msg}:\n {inner}")
196 }
197 VortexError::Shared(inner) => Display::fmt(inner, f),
198 VortexError::ArrowError(err, backtrace) => {
199 write!(f, "{err}\nBacktrace:\n{backtrace}")
200 }
201 #[cfg(feature = "flatbuffers")]
202 VortexError::FlatBuffersError(err, backtrace) => {
203 write!(f, "{err}\nBacktrace:\n{backtrace}")
204 }
205 VortexError::FmtError(err, backtrace) => {
206 write!(f, "{err}\nBacktrace:\n{backtrace}")
207 }
208 VortexError::IOError(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::IOError(err, _) => Some(err),
261 #[cfg(feature = "object_store")]
262 VortexError::ObjectStore(err, _) => Some(err),
263 VortexError::JiffError(err, _) => Some(err),
264 #[cfg(feature = "tokio")]
265 VortexError::JoinError(err, _) => Some(err),
266 VortexError::UrlError(err, _) => Some(err),
267 #[cfg(feature = "serde")]
268 VortexError::SerdeJsonError(err, _) => Some(err),
269 #[cfg(feature = "prost")]
270 VortexError::ProstEncodeError(err, _) => Some(err),
271 #[cfg(feature = "prost")]
272 VortexError::ProstDecodeError(err, _) => Some(err),
273 #[cfg(feature = "prost")]
274 VortexError::ProstUnknownEnumValue(err, _) => Some(err),
275 _ => None,
276 }
277 }
278}
279
280impl Debug for VortexError {
281 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
282 Display::fmt(self, f)
283 }
284}
285
286pub type VortexResult<T> = Result<T, VortexError>;
288
289pub type SharedVortexResult<T> = Result<T, Arc<VortexError>>;
291
292impl From<Arc<VortexError>> for VortexError {
293 fn from(value: Arc<VortexError>) -> Self {
294 Self::from(&value)
295 }
296}
297
298impl From<&Arc<VortexError>> for VortexError {
299 fn from(e: &Arc<VortexError>) -> Self {
300 if let VortexError::Shared(e_inner) = e.as_ref() {
301 VortexError::Shared(Arc::clone(e_inner))
303 } else {
304 VortexError::Shared(Arc::clone(e))
305 }
306 }
307}
308
309pub trait VortexUnwrap {
311 type Output;
313
314 fn vortex_unwrap(self) -> Self::Output;
317}
318
319impl<T, E> VortexUnwrap for Result<T, E>
320where
321 E: Into<VortexError>,
322{
323 type Output = T;
324
325 #[inline(always)]
326 fn vortex_unwrap(self) -> Self::Output {
327 self.map_err(|err| err.into())
328 .unwrap_or_else(|err| vortex_panic!(err))
329 }
330}
331
332pub trait VortexExpect {
334 type Output;
336
337 fn vortex_expect(self, msg: &'static 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: &'static 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: &'static 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_ensure {
449 ($cond:expr) => {
450 vortex_ensure!($cond, AssertionFailed: "{}", stringify!($cond));
451 };
452 ($cond:expr, $($tt:tt)*) => {
453 if !$cond {
454 $crate::vortex_bail!($($tt)*);
455 }
456 };
457}
458
459#[macro_export]
462macro_rules! vortex_panic {
463 (OutOfBounds: $idx:expr, $start:expr, $stop:expr) => {{
464 $crate::vortex_panic!($crate::vortex_err!(OutOfBounds: $idx, $start, $stop))
465 }};
466 (NotImplemented: $func:expr, $for_whom:expr) => {{
467 $crate::vortex_panic!($crate::vortex_err!(NotImplemented: $func, $for_whom))
468 }};
469 (MismatchedTypes: $expected:literal, $actual:expr) => {{
470 $crate::vortex_panic!($crate::vortex_err!(MismatchedTypes: $expected, $actual))
471 }};
472 (MismatchedTypes: $expected:expr, $actual:expr) => {{
473 $crate::vortex_panic!($crate::vortex_err!(MismatchedTypes: $expected, $actual))
474 }};
475 (Context: $msg:literal, $err:expr) => {{
476 $crate::vortex_panic!($crate::vortex_err!(Context: $msg, $err))
477 }};
478 ($variant:ident: $fmt:literal $(, $arg:expr)* $(,)?) => {
479 $crate::vortex_panic!($crate::vortex_err!($variant: $fmt, $($arg),*))
480 };
481 ($err:expr, $fmt:literal $(, $arg:expr)* $(,)?) => {{
482 let err: $crate::VortexError = $err;
483 panic!("{}", err.with_context(format!($fmt, $($arg),*)))
484 }};
485 ($fmt:literal $(, $arg:expr)* $(,)?) => {
486 $crate::vortex_panic!($crate::vortex_err!($fmt, $($arg),*))
487 };
488 ($err:expr) => {{
489 let err: $crate::VortexError = $err;
490 panic!("{}", err)
491 }};
492}
493
494impl From<arrow_schema::ArrowError> for VortexError {
495 fn from(value: arrow_schema::ArrowError) -> Self {
496 VortexError::ArrowError(value, Box::new(Backtrace::capture()))
497 }
498}
499
500#[cfg(feature = "flatbuffers")]
501impl From<flatbuffers::InvalidFlatbuffer> for VortexError {
502 fn from(value: flatbuffers::InvalidFlatbuffer) -> Self {
503 VortexError::FlatBuffersError(value, Box::new(Backtrace::capture()))
504 }
505}
506
507impl From<io::Error> for VortexError {
508 fn from(value: io::Error) -> Self {
509 VortexError::IOError(value, Box::new(Backtrace::capture()))
510 }
511}
512
513impl From<std::array::TryFromSliceError> for VortexError {
514 fn from(value: std::array::TryFromSliceError) -> Self {
515 VortexError::TryFromSliceError(value, Box::new(Backtrace::capture()))
516 }
517}
518
519#[cfg(feature = "object_store")]
520impl From<object_store::Error> for VortexError {
521 fn from(value: object_store::Error) -> Self {
522 VortexError::ObjectStore(value, Box::new(Backtrace::capture()))
523 }
524}
525
526impl From<jiff::Error> for VortexError {
527 fn from(value: jiff::Error) -> Self {
528 VortexError::JiffError(value, Box::new(Backtrace::capture()))
529 }
530}
531
532#[cfg(feature = "tokio")]
533impl From<tokio::task::JoinError> for VortexError {
534 fn from(value: tokio::task::JoinError) -> Self {
535 if value.is_panic() {
536 std::panic::resume_unwind(value.into_panic())
537 } else {
538 VortexError::JoinError(value, Box::new(Backtrace::capture()))
539 }
540 }
541}
542
543impl From<url::ParseError> for VortexError {
544 fn from(value: url::ParseError) -> Self {
545 VortexError::UrlError(value, Box::new(Backtrace::capture()))
546 }
547}
548
549impl From<TryFromIntError> for VortexError {
550 fn from(value: TryFromIntError) -> Self {
551 VortexError::TryFromInt(value, Box::new(Backtrace::capture()))
552 }
553}
554
555#[cfg(feature = "serde")]
556impl From<serde_json::Error> for VortexError {
557 fn from(value: serde_json::Error) -> Self {
558 VortexError::SerdeJsonError(value, Box::new(Backtrace::capture()))
559 }
560}
561
562#[cfg(feature = "prost")]
563impl From<prost::EncodeError> for VortexError {
564 fn from(value: prost::EncodeError) -> Self {
565 VortexError::ProstEncodeError(value, Box::new(Backtrace::capture()))
566 }
567}
568
569#[cfg(feature = "prost")]
570impl From<prost::DecodeError> for VortexError {
571 fn from(value: prost::DecodeError) -> Self {
572 VortexError::ProstDecodeError(value, Box::new(Backtrace::capture()))
573 }
574}
575
576#[cfg(feature = "prost")]
577impl From<prost::UnknownEnumValue> for VortexError {
578 fn from(value: prost::UnknownEnumValue) -> Self {
579 VortexError::ProstUnknownEnumValue(value, Box::new(Backtrace::capture()))
580 }
581}
582
583#[doc(hidden)]
585pub mod __private {
586 #[doc(hidden)]
587 #[inline]
588 #[cold]
589 #[must_use]
590 pub const fn must_use(error: crate::VortexError) -> crate::VortexError {
591 error
592 }
593}
594
595impl<T> From<PoisonError<T>> for VortexError {
596 fn from(_value: PoisonError<T>) -> Self {
597 Self::InvalidState("Lock poisoned".into(), Box::new(Backtrace::capture()))
599 }
600}