pub type Result<T, E = MarrowError> = std::result::Result<T, E>;
pub struct MarrowError(Box<ErrorImpl>);
impl MarrowError {
pub fn new(kind: ErrorKind, message: String) -> Self {
MarrowError(Box::new(ErrorImpl {
kind,
message,
backtrace: Backtrace::capture(),
cause: None,
}))
}
pub fn with_cause(
kind: ErrorKind,
message: String,
cause: impl std::error::Error + Send + Sync + 'static,
) -> Self {
MarrowError(Box::new(ErrorImpl {
kind,
message,
backtrace: Backtrace::capture(),
cause: Some(Box::new(cause)),
}))
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ErrorKind {
ParseError,
ArrowError,
Unsupported,
}
impl std::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
macro_rules! write_variant_name {
($($variant:ident),* $(,)?) => {
match self {
$(
Self::$variant => write!(f, stringify!($variant)),
)*
}
};
}
write_variant_name!(ParseError, ArrowError, Unsupported)
}
}
impl MarrowError {
pub fn kind(&self) -> ErrorKind {
self.0.kind
}
pub fn message(&self) -> &str {
&self.0.message
}
pub fn backtrace(&self) -> &Backtrace {
&self.0.backtrace
}
}
impl std::error::Error for MarrowError {
fn description(&self) -> &str {
self.message()
}
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.0.cause {
Some(error) => Some(error.as_ref()),
None => None,
}
}
fn cause(&self) -> Option<&dyn std::error::Error> {
match &self.0.cause {
Some(error) => Some(error.as_ref()),
None => None,
}
}
}
struct ErrorImpl {
kind: ErrorKind,
message: String,
backtrace: Backtrace,
cause: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
}
impl std::fmt::Debug for MarrowError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Error: {message}\n{backtrace}",
message = self.0.message,
backtrace = BacktraceDisplay(&self.0.backtrace),
)
}
}
impl std::fmt::Display for MarrowError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Error: {}", self.0.message)
}
}
struct BacktraceDisplay<'a>(&'a Backtrace);
impl std::fmt::Display for BacktraceDisplay<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0.status() {
BacktraceStatus::Captured => write!(f, "Backtrace:\n{bt}", bt=self.0),
BacktraceStatus::Disabled => write!(f, "Backtrace not captured; set the `RUST_BACKTRACE=1` env variable to enable"),
_ => write!(f, "Backtrace not captured: most likely backtraces are not supported on the current platform"),
}
}
}
macro_rules! fail {
($kind:expr, $($msg:tt)*) => {
return Err($crate::error::MarrowError::new($kind, format!($($msg)*)))
};
}
use std::backtrace::{Backtrace, BacktraceStatus};
pub(crate) use fail;
impl From<std::num::TryFromIntError> for MarrowError {
fn from(err: std::num::TryFromIntError) -> MarrowError {
MarrowError::with_cause(
ErrorKind::Unsupported,
format!("TryFromIntError: {err}"),
err,
)
}
}
impl From<bytemuck::PodCastError> for MarrowError {
fn from(err: bytemuck::PodCastError) -> Self {
let err = match err {
bytemuck::PodCastError::TargetAlignmentGreaterAndInputNotAligned => {
"TargetAlignmentGreaterAndInputNotAligned"
}
bytemuck::PodCastError::OutputSliceWouldHaveSlop => "OutputSliceWouldHaveSlop",
bytemuck::PodCastError::SizeMismatch => "SizeMismatch",
bytemuck::PodCastError::AlignmentMismatch => "AlignmentMismatch",
};
MarrowError::new(
ErrorKind::Unsupported,
format!("bytemuck::PodCastError: {err}"),
)
}
}