#![deny(missing_docs)]
#[cfg(feature = "python")]
pub mod python;
use std::backtrace::Backtrace;
use std::borrow::Cow;
use std::convert::Infallible;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::num::TryFromIntError;
use std::ops::Deref;
use std::sync::{Arc, PoisonError};
use std::{env, fmt, io};
#[derive(Debug)]
pub struct ErrString(Cow<'static, str>);
#[allow(clippy::fallible_impl_from)]
impl<T> From<T> for ErrString
where
T: Into<Cow<'static, str>>,
{
#[allow(clippy::panic)]
fn from(msg: T) -> Self {
if env::var("VORTEX_PANIC_ON_ERR").as_deref().unwrap_or("") == "1" {
panic!("{}\nBacktrace:\n{}", msg.into(), Backtrace::capture());
} else {
Self(msg.into())
}
}
}
impl AsRef<str> for ErrString {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Deref for ErrString {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Display for ErrString {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl From<Infallible> for VortexError {
fn from(_: Infallible) -> Self {
unreachable!()
}
}
const _: () = {
assert!(size_of::<VortexError>() < 128);
};
#[non_exhaustive]
pub enum VortexError {
Generic(Box<dyn Error + Send + Sync + 'static>, Box<Backtrace>),
OutOfBounds(usize, usize, usize, Box<Backtrace>),
ComputeError(ErrString, Box<Backtrace>),
InvalidArgument(ErrString, Box<Backtrace>),
InvalidState(ErrString, Box<Backtrace>),
InvalidSerde(ErrString, Box<Backtrace>),
NotImplemented(ErrString, ErrString, Box<Backtrace>),
MismatchedTypes(ErrString, ErrString, Box<Backtrace>),
AssertionFailed(ErrString, Box<Backtrace>),
Context(ErrString, Box<VortexError>),
Shared(Arc<VortexError>),
ArrowError(arrow_schema::ArrowError, Box<Backtrace>),
#[cfg(feature = "flatbuffers")]
FlatBuffersError(flatbuffers::InvalidFlatbuffer, Box<Backtrace>),
FmtError(fmt::Error, Box<Backtrace>),
IOError(io::Error, Box<Backtrace>),
TryFromSliceError(std::array::TryFromSliceError, Box<Backtrace>),
#[cfg(feature = "object_store")]
ObjectStore(object_store::Error, Box<Backtrace>),
JiffError(jiff::Error, Box<Backtrace>),
#[cfg(feature = "tokio")]
JoinError(tokio::task::JoinError, Box<Backtrace>),
UrlError(url::ParseError, Box<Backtrace>),
TryFromInt(TryFromIntError, Box<Backtrace>),
#[cfg(feature = "serde")]
SerdeJsonError(serde_json::Error, Box<Backtrace>),
#[cfg(feature = "prost")]
ProstEncodeError(prost::EncodeError, Box<Backtrace>),
#[cfg(feature = "prost")]
ProstDecodeError(prost::DecodeError, Box<Backtrace>),
#[cfg(feature = "prost")]
ProstUnknownEnumValue(prost::UnknownEnumValue, Box<Backtrace>),
}
impl VortexError {
pub fn with_context<T: Into<ErrString>>(self, msg: T) -> Self {
VortexError::Context(msg.into(), Box::new(self))
}
pub fn generic(err: Box<dyn Error + Send + Sync + 'static>) -> Self {
Self::Generic(err, Box::new(Backtrace::capture()))
}
}
impl Display for VortexError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
VortexError::Generic(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
VortexError::OutOfBounds(idx, start, stop, backtrace) => {
write!(
f,
"index {idx} out of bounds from {start} to {stop}\nBacktrace:\n{backtrace}",
)
}
VortexError::ComputeError(msg, backtrace) => {
write!(f, "{msg}\nBacktrace:\n{backtrace}")
}
VortexError::InvalidArgument(msg, backtrace) => {
write!(f, "{msg}\nBacktrace:\n{backtrace}")
}
VortexError::InvalidState(msg, backtrace) => {
write!(f, "{msg}\nBacktrace:\n{backtrace}")
}
VortexError::InvalidSerde(msg, backtrace) => {
write!(f, "{msg}\nBacktrace:\n{backtrace}")
}
VortexError::NotImplemented(func, by_whom, backtrace) => {
write!(
f,
"function {func} not implemented for {by_whom}\nBacktrace:\n{backtrace}",
)
}
VortexError::MismatchedTypes(expected, actual, backtrace) => {
write!(
f,
"expected type: {expected} but instead got {actual}\nBacktrace:\n{backtrace}",
)
}
VortexError::AssertionFailed(msg, backtrace) => {
write!(f, "{msg}\nBacktrace:\n{backtrace}")
}
VortexError::Context(msg, inner) => {
write!(f, "{msg}: {inner}")
}
VortexError::Shared(inner) => Display::fmt(inner, f),
VortexError::ArrowError(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
#[cfg(feature = "flatbuffers")]
VortexError::FlatBuffersError(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
VortexError::FmtError(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
VortexError::IOError(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
VortexError::TryFromSliceError(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
#[cfg(feature = "object_store")]
VortexError::ObjectStore(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
VortexError::JiffError(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
#[cfg(feature = "tokio")]
VortexError::JoinError(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
VortexError::UrlError(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
VortexError::TryFromInt(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
#[cfg(feature = "serde")]
VortexError::SerdeJsonError(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
#[cfg(feature = "prost")]
VortexError::ProstEncodeError(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
#[cfg(feature = "prost")]
VortexError::ProstDecodeError(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
#[cfg(feature = "prost")]
VortexError::ProstUnknownEnumValue(err, backtrace) => {
write!(f, "{err}\nBacktrace:\n{backtrace}")
}
}
}
}
impl Error for VortexError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
VortexError::Generic(err, _) => Some(err.as_ref()),
VortexError::Context(_, inner) => inner.source(),
VortexError::Shared(inner) => inner.source(),
VortexError::ArrowError(err, _) => Some(err),
#[cfg(feature = "flatbuffers")]
VortexError::FlatBuffersError(err, _) => Some(err),
VortexError::IOError(err, _) => Some(err),
#[cfg(feature = "object_store")]
VortexError::ObjectStore(err, _) => Some(err),
VortexError::JiffError(err, _) => Some(err),
#[cfg(feature = "tokio")]
VortexError::JoinError(err, _) => Some(err),
VortexError::UrlError(err, _) => Some(err),
#[cfg(feature = "serde")]
VortexError::SerdeJsonError(err, _) => Some(err),
#[cfg(feature = "prost")]
VortexError::ProstEncodeError(err, _) => Some(err),
#[cfg(feature = "prost")]
VortexError::ProstDecodeError(err, _) => Some(err),
#[cfg(feature = "prost")]
VortexError::ProstUnknownEnumValue(err, _) => Some(err),
_ => None,
}
}
}
impl Debug for VortexError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(self, f)
}
}
pub type VortexResult<T> = Result<T, VortexError>;
pub type SharedVortexResult<T> = Result<T, Arc<VortexError>>;
impl From<Arc<VortexError>> for VortexError {
fn from(value: Arc<VortexError>) -> Self {
Self::from(&value)
}
}
impl From<&Arc<VortexError>> for VortexError {
fn from(e: &Arc<VortexError>) -> Self {
if let VortexError::Shared(e_inner) = e.as_ref() {
VortexError::Shared(Arc::clone(e_inner))
} else {
VortexError::Shared(Arc::clone(e))
}
}
}
pub trait VortexUnwrap {
type Output;
fn vortex_unwrap(self) -> Self::Output;
}
impl<T, E> VortexUnwrap for Result<T, E>
where
E: Into<VortexError>,
{
type Output = T;
#[inline(always)]
fn vortex_unwrap(self) -> Self::Output {
self.map_err(|err| err.into())
.unwrap_or_else(|err| vortex_panic!(err))
}
}
pub trait VortexExpect {
type Output;
fn vortex_expect(self, msg: &str) -> Self::Output;
}
impl<T, E> VortexExpect for Result<T, E>
where
E: Into<VortexError>,
{
type Output = T;
#[inline(always)]
fn vortex_expect(self, msg: &str) -> Self::Output {
self.map_err(|err| err.into())
.unwrap_or_else(|e| vortex_panic!(e.with_context(msg.to_string())))
}
}
impl<T> VortexExpect for Option<T> {
type Output = T;
#[inline(always)]
fn vortex_expect(self, msg: &str) -> Self::Output {
self.unwrap_or_else(|| {
let err = VortexError::AssertionFailed(
msg.to_string().into(),
Box::new(Backtrace::capture()),
);
vortex_panic!(err)
})
}
}
#[macro_export]
macro_rules! vortex_err {
(AssertionFailed: $($tts:tt)*) => {{
use std::backtrace::Backtrace;
let err_string = format!($($tts)*);
$crate::__private::must_use(
$crate::VortexError::AssertionFailed(err_string.into(), Box::new(Backtrace::capture()))
)
}};
(IOError: $($tts:tt)*) => {{
use std::backtrace::Backtrace;
$crate::__private::must_use(
$crate::VortexError::IOError(err_string.into(), Box::new(Backtrace::capture()))
)
}};
(OutOfBounds: $idx:expr, $start:expr, $stop:expr) => {{
use std::backtrace::Backtrace;
$crate::__private::must_use(
$crate::VortexError::OutOfBounds($idx, $start, $stop, Box::new(Backtrace::capture()))
)
}};
(NotImplemented: $func:expr, $by_whom:expr) => {{
use std::backtrace::Backtrace;
$crate::__private::must_use(
$crate::VortexError::NotImplemented($func.into(), format!("{}", $by_whom).into(), Box::new(Backtrace::capture()))
)
}};
(MismatchedTypes: $expected:literal, $actual:expr) => {{
use std::backtrace::Backtrace;
$crate::__private::must_use(
$crate::VortexError::MismatchedTypes($expected.into(), $actual.to_string().into(), Box::new(Backtrace::capture()))
)
}};
(MismatchedTypes: $expected:expr, $actual:expr) => {{
use std::backtrace::Backtrace;
$crate::__private::must_use(
$crate::VortexError::MismatchedTypes($expected.to_string().into(), $actual.to_string().into(), Box::new(Backtrace::capture()))
)
}};
(Context: $msg:literal, $err:expr) => {{
$crate::__private::must_use(
$crate::VortexError::Context($msg.into(), Box::new($err))
)
}};
($variant:ident: $fmt:literal $(, $arg:expr)* $(,)?) => {{
use std::backtrace::Backtrace;
$crate::__private::must_use(
$crate::VortexError::$variant(format!($fmt, $($arg),*).into(), Box::new(Backtrace::capture()))
)
}};
($variant:ident: $err:expr $(,)?) => {
$crate::__private::must_use(
$crate::VortexError::$variant($err)
)
};
($fmt:literal $(, $arg:expr)* $(,)?) => {
$crate::vortex_err!(InvalidArgument: $fmt, $($arg),*)
};
}
#[macro_export]
macro_rules! vortex_bail {
($($tt:tt)+) => {
return Err($crate::vortex_err!($($tt)+))
};
}
#[macro_export]
macro_rules! vortex_ensure {
($cond:expr) => {
vortex_ensure!($cond, AssertionFailed: "{}", stringify!($cond));
};
($cond:expr, $($tt:tt)*) => {
if !$cond {
$crate::vortex_bail!($($tt)*);
}
};
}
#[macro_export]
macro_rules! vortex_panic {
(OutOfBounds: $idx:expr, $start:expr, $stop:expr) => {{
$crate::vortex_panic!($crate::vortex_err!(OutOfBounds: $idx, $start, $stop))
}};
(NotImplemented: $func:expr, $for_whom:expr) => {{
$crate::vortex_panic!($crate::vortex_err!(NotImplemented: $func, $for_whom))
}};
(MismatchedTypes: $expected:literal, $actual:expr) => {{
$crate::vortex_panic!($crate::vortex_err!(MismatchedTypes: $expected, $actual))
}};
(MismatchedTypes: $expected:expr, $actual:expr) => {{
$crate::vortex_panic!($crate::vortex_err!(MismatchedTypes: $expected, $actual))
}};
(Context: $msg:literal, $err:expr) => {{
$crate::vortex_panic!($crate::vortex_err!(Context: $msg, $err))
}};
($variant:ident: $fmt:literal $(, $arg:expr)* $(,)?) => {
$crate::vortex_panic!($crate::vortex_err!($variant: $fmt, $($arg),*))
};
($err:expr, $fmt:literal $(, $arg:expr)* $(,)?) => {{
let err: $crate::VortexError = $err;
panic!("{}", err.with_context(format!($fmt, $($arg),*)))
}};
($fmt:literal $(, $arg:expr)* $(,)?) => {
$crate::vortex_panic!($crate::vortex_err!($fmt, $($arg),*))
};
($err:expr) => {{
let err: $crate::VortexError = $err;
panic!("{}", err)
}};
}
impl From<arrow_schema::ArrowError> for VortexError {
fn from(value: arrow_schema::ArrowError) -> Self {
VortexError::ArrowError(value, Box::new(Backtrace::capture()))
}
}
#[cfg(feature = "flatbuffers")]
impl From<flatbuffers::InvalidFlatbuffer> for VortexError {
fn from(value: flatbuffers::InvalidFlatbuffer) -> Self {
VortexError::FlatBuffersError(value, Box::new(Backtrace::capture()))
}
}
impl From<io::Error> for VortexError {
fn from(value: io::Error) -> Self {
VortexError::IOError(value, Box::new(Backtrace::capture()))
}
}
impl From<std::array::TryFromSliceError> for VortexError {
fn from(value: std::array::TryFromSliceError) -> Self {
VortexError::TryFromSliceError(value, Box::new(Backtrace::capture()))
}
}
#[cfg(feature = "object_store")]
impl From<object_store::Error> for VortexError {
fn from(value: object_store::Error) -> Self {
VortexError::ObjectStore(value, Box::new(Backtrace::capture()))
}
}
impl From<jiff::Error> for VortexError {
fn from(value: jiff::Error) -> Self {
VortexError::JiffError(value, Box::new(Backtrace::capture()))
}
}
#[cfg(feature = "tokio")]
impl From<tokio::task::JoinError> for VortexError {
fn from(value: tokio::task::JoinError) -> Self {
if value.is_panic() {
std::panic::resume_unwind(value.into_panic())
} else {
VortexError::JoinError(value, Box::new(Backtrace::capture()))
}
}
}
impl From<url::ParseError> for VortexError {
fn from(value: url::ParseError) -> Self {
VortexError::UrlError(value, Box::new(Backtrace::capture()))
}
}
impl From<TryFromIntError> for VortexError {
fn from(value: TryFromIntError) -> Self {
VortexError::TryFromInt(value, Box::new(Backtrace::capture()))
}
}
#[cfg(feature = "serde")]
impl From<serde_json::Error> for VortexError {
fn from(value: serde_json::Error) -> Self {
VortexError::SerdeJsonError(value, Box::new(Backtrace::capture()))
}
}
#[cfg(feature = "prost")]
impl From<prost::EncodeError> for VortexError {
fn from(value: prost::EncodeError) -> Self {
VortexError::ProstEncodeError(value, Box::new(Backtrace::capture()))
}
}
#[cfg(feature = "prost")]
impl From<prost::DecodeError> for VortexError {
fn from(value: prost::DecodeError) -> Self {
VortexError::ProstDecodeError(value, Box::new(Backtrace::capture()))
}
}
#[cfg(feature = "prost")]
impl From<prost::UnknownEnumValue> for VortexError {
fn from(value: prost::UnknownEnumValue) -> Self {
VortexError::ProstUnknownEnumValue(value, Box::new(Backtrace::capture()))
}
}
#[doc(hidden)]
pub mod __private {
#[doc(hidden)]
#[inline]
#[cold]
#[must_use]
pub const fn must_use(error: crate::VortexError) -> crate::VortexError {
error
}
}
impl<T> From<PoisonError<T>> for VortexError {
fn from(_value: PoisonError<T>) -> Self {
Self::InvalidState("Lock poisoned".into(), Box::new(Backtrace::capture()))
}
}