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