extern crate alloc;
use alloc::{boxed::Box, format, string::String};
use core::{
error::Error as CoreError,
fmt::{self, Debug, Display, Formatter},
result::Result as CoreResult,
};
#[cfg(feature = "std")]
use std::backtrace::{Backtrace, BacktraceStatus};
use crate::ast::NodeRef;
pub type Result<T> = CoreResult<T, Error>;
#[derive(Debug)]
#[non_exhaustive]
pub enum CallbackError<E: CoreError + 'static> {
Internal(Error),
Callback(E),
}
impl<E: CoreError + 'static> Display for CallbackError<E> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
CallbackError::Internal(err) => write!(f, "{}", err),
CallbackError::Callback(err) => {
write!(f, "{}", err)
}
}
}
}
impl<E: CoreError + 'static> CoreError for CallbackError<E> {
fn source(&self) -> Option<&(dyn CoreError + 'static)> {
match self {
CallbackError::Internal(err) => Some(err),
CallbackError::Callback(err) => Some(err),
}
}
}
#[non_exhaustive]
pub enum Error {
InvalidNodeRef {
noderef: NodeRef,
description: String,
#[cfg(feature = "std")]
backtrace: Backtrace,
},
InvalidNodeOperation {
message: String,
description: String,
#[cfg(feature = "std")]
backtrace: Backtrace,
},
Io {
message: String,
description: String,
source: Option<Box<dyn CoreError + 'static>>,
#[cfg(feature = "std")]
backtrace: Backtrace,
},
}
impl Error {
pub fn invalid_node_ref(node_ref: NodeRef) -> Self {
Error::InvalidNodeRef {
noderef: node_ref,
description: format!("invalid node reference: {}", node_ref),
#[cfg(feature = "std")]
backtrace: Backtrace::capture(),
}
}
pub fn invalid_node_operation(message: String) -> Self {
Error::InvalidNodeOperation {
message: message.clone(),
description: format!("invalid operation: {}", message),
#[cfg(feature = "std")]
backtrace: Backtrace::capture(),
}
}
pub fn io<S>(m: S, source: Option<Box<dyn CoreError + 'static>>) -> Self
where
S: Into<String>,
{
let message = m.into();
Error::Io {
message: message.clone(),
description: format!("io error: {}", message),
source,
#[cfg(feature = "std")]
backtrace: Backtrace::capture(),
}
}
#[cfg(feature = "std")]
pub fn backtrace(&self) -> Option<&Backtrace> {
match self {
Error::InvalidNodeRef { backtrace, .. } => Some(backtrace),
Error::InvalidNodeOperation { backtrace, .. } => Some(backtrace),
Error::Io { backtrace, .. } => Some(backtrace),
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Error::InvalidNodeRef { description, .. } => write!(f, "{}", description),
Error::InvalidNodeOperation { description, .. } => write!(f, "{}", description),
Error::Io { description, .. } => write!(f, "{}", description),
}
}
}
impl Debug for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Error::InvalidNodeRef {
description,
#[cfg(feature = "std")]
backtrace,
..
} => {
write!(f, "{}", description)?;
#[cfg(feature = "std")]
{
write!(f, "{}", format_backtrace(backtrace))?;
}
}
Error::InvalidNodeOperation {
description,
#[cfg(feature = "std")]
backtrace,
..
} => {
write!(f, "{}", description)?;
#[cfg(feature = "std")]
{
write!(f, "{}", format_backtrace(backtrace))?;
}
}
Error::Io {
description,
#[cfg(feature = "std")]
backtrace,
..
} => {
write!(f, "{}", description)?;
#[cfg(feature = "std")]
{
write!(f, "{}", format_backtrace(backtrace))?;
}
}
}
if let Some(source) = self.source() {
writeln!(f, "Caused by: {:?}", source)?;
}
Ok(())
}
}
impl CoreError for Error {
fn source(&self) -> Option<&(dyn CoreError + 'static)> {
{
match self {
Error::Io { source, .. } => source.as_deref(),
_ => None,
}
}
}
}
#[cfg(feature = "std")]
fn format_backtrace(backtrace: &Backtrace) -> String {
match backtrace.status() {
BacktraceStatus::Captured => format!("\nstack backtrace:\n{}", backtrace),
_ => String::new(),
}
}