#[cfg(not(feature = "std"))]
use alloc::{borrow::Cow, boxed::Box, string::String};
#[cfg(feature = "std")]
use std::borrow::Cow;
use crate::context::{ContextChain, ContextLayer, IntoContextValue};
#[derive(Debug)]
pub struct ErrFrame {
pub(crate) message: Cow<'static, str>,
#[cfg(feature = "std")]
pub(crate) source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
#[cfg(not(feature = "std"))]
pub(crate) source: Option<String>,
pub(crate) context: ContextChain,
#[cfg(all(feature = "std", feature = "backtrace"))]
pub(crate) backtrace: Option<std::backtrace::Backtrace>,
}
impl ErrFrame {
pub fn new<M: Into<Cow<'static, str>>>(message: M) -> Self {
Self {
message: message.into(),
source: None,
context: ContextChain::new(),
#[cfg(all(feature = "std", feature = "backtrace"))]
backtrace: None,
}
}
#[cfg(feature = "std")]
pub fn with_source<E>(mut self, err: E) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
self.source = Some(Box::new(err));
self
}
#[cfg(not(feature = "std"))]
pub fn with_source<E: core::fmt::Display>(mut self, err: E) -> Self {
use alloc::format;
self.source = Some(format!("{}", err));
self
}
pub fn context<K, V>(mut self, key: K, value: V) -> Self
where
K: Into<Cow<'static, str>>,
V: IntoContextValue,
{
self.context.push(ContextLayer::with_key(key, value));
self
}
pub fn context_text<T: Into<Cow<'static, str>>>(mut self, text: T) -> Self {
self.context.push(ContextLayer::text(text));
self
}
#[cfg(all(feature = "std", feature = "backtrace"))]
pub fn capture_backtrace(mut self) -> Self {
self.backtrace = Some(std::backtrace::Backtrace::capture());
self
}
#[cfg(not(all(feature = "std", feature = "backtrace")))]
pub fn capture_backtrace(self) -> Self {
self
}
pub fn message(&self) -> &str {
&self.message
}
pub fn context_layers(&self) -> impl Iterator<Item = &ContextLayer> {
self.context.iter()
}
#[cfg(all(feature = "std", feature = "backtrace"))]
pub fn backtrace(&self) -> Option<&std::backtrace::Backtrace> {
self.backtrace.as_ref()
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for ErrFrame {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)?;
if !self.context.is_empty() {
write!(f, " (")?;
let mut first = true;
for layer in self.context.iter() {
if !first {
write!(f, ", ")?;
}
first = false;
if let Some(key) = layer.key() {
write!(f, "{}={}", key, layer.value().as_str())?;
} else {
write!(f, "{}", layer.value().as_str())?;
}
}
write!(f, ")")?;
}
Ok(())
}
}
#[cfg(not(feature = "std"))]
impl core::fmt::Display for ErrFrame {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.message)?;
if !self.context.is_empty() {
write!(f, " (")?;
let mut first = true;
for layer in self.context.iter() {
if !first {
write!(f, ", ")?;
}
first = false;
if let Some(key) = layer.key() {
write!(f, "{}={}", key, layer.value().as_str())?;
} else {
write!(f, "{}", layer.value().as_str())?;
}
}
write!(f, ")")?;
}
Ok(())
}
}
#[cfg(feature = "std")]
impl std::error::Error for ErrFrame {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source.as_ref().map(|e| e.as_ref() as _)
}
}