#![allow(missing_docs, dead_code)] use crate::compat::{boxed::Box, error::Error as ErrorTrait};
#[cfg(feature = "std")]
use crate::error::inner::Location;
use serde::{Deserialize, Serialize};
use self::code::ErrorCode;
mod code;
mod inner;
pub mod errcode {
pub use super::code::*;
}
#[cfg(feature = "alloc")]
type ErrorData = Box<inner::ErrorData>;
#[cfg(not(feature = "alloc"))]
type ErrorData = Inner;
pub type Result<T, E = Error> = core::result::Result<T, E>;
#[derive(Serialize, Deserialize)]
pub struct Error(ErrorData);
impl Error {
#[cold]
#[track_caller]
#[cfg(feature = "std")]
pub fn new<E>(origin: code::Origin, kind: code::Kind, cause: E) -> Self
where
E: Into<Box<dyn std::error::Error + Send + Sync>>,
{
Self(inner::ErrorData::new(ErrorCode::new(origin, kind), cause).into())
}
#[cold]
#[track_caller]
#[cfg(not(feature = "std"))]
pub fn new<E>(origin: code::Origin, kind: code::Kind, cause: E) -> Self
where
E: core::fmt::Display,
{
Self(inner::ErrorData::new(ErrorCode::new(origin, kind), cause).into())
}
#[cold]
#[cfg(feature = "std")]
#[track_caller]
pub fn new_unknown<E>(origin: code::Origin, cause: E) -> Self
where
E: Into<Box<dyn crate::compat::error::Error + Send + Sync>>,
{
Self::new(origin, code::Kind::Unknown, cause)
}
#[cold]
#[track_caller]
pub fn new_without_cause(origin: code::Origin, kind: code::Kind) -> Self {
Self(inner::ErrorData::new_without_cause(origin, kind).into())
}
pub fn code(&self) -> ErrorCode {
self.0.code
}
#[cfg(feature = "std")]
pub(super) fn source_location(&self) -> Location {
self.0.source_loc.clone()
}
#[must_use]
pub fn context(mut self, key: &str, val: impl core::fmt::Display) -> Self {
self.0.add_context(key, &val);
self
}
}
impl core::fmt::Debug for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
#[cfg(feature = "std")]
match self.source() {
None => write!(
f,
"{}, source location: {}",
self.code(),
self.source_location()
)?,
Some(e) => write!(
f,
"{} ({}, source location: {})",
e,
self.code(),
self.source_location()
)?,
}
#[cfg(not(feature = "std"))]
write!(f, "{}", self.code())?;
Ok(())
}
}
impl ErrorTrait for Error {
#[cfg(feature = "std")]
fn source(&self) -> Option<&(dyn ErrorTrait + 'static)> {
if let Some(e) = self.0.cause() {
let force_coercion: &(dyn ErrorTrait + 'static) = e;
Some(force_coercion)
} else {
None
}
}
}
impl From<core::fmt::Error> for Error {
#[cfg(feature = "std")]
#[track_caller]
fn from(e: core::fmt::Error) -> Self {
Error::new(code::Origin::Application, code::Kind::Invalid, e)
}
#[cfg(not(feature = "std"))]
#[track_caller]
fn from(_: core::fmt::Error) -> Self {
Error::new_without_cause(code::Origin::Application, code::Kind::Invalid)
}
}
impl From<strum::ParseError> for Error {
#[cfg(feature = "std")]
#[track_caller]
fn from(e: strum::ParseError) -> Self {
Error::new(code::Origin::Application, code::Kind::Invalid, e)
}
#[cfg(not(feature = "std"))]
#[track_caller]
fn from(_: strum::ParseError) -> Self {
Error::new_without_cause(code::Origin::Application, code::Kind::Invalid)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::errcode::{Kind, Origin};
#[test]
fn test_error_display() {
let e = Error::new(Origin::Node, Kind::NotFound, "address not found");
assert!(e.to_string().contains("address not found (origin: Node, kind: NotFound, source location: implementations/rust/ockam/ockam_core/src/error/mod.rs"))
}
#[test]
fn test_error_without_cause_display() {
let e = Error::new_without_cause(Origin::Node, Kind::NotFound);
assert!(e.to_string().contains("origin: Node, kind: NotFound, source location: implementations/rust/ockam/ockam_core/src/error/mod.rs"))
}
}