pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
DuplicateComponent {
type_name: &'static str,
},
Invalid(super::ValidationOutcome),
Boot {
name: &'static str,
source: BoxError,
},
Validate {
name: &'static str,
source: BoxError,
},
Reload {
name: &'static str,
source: BoxError,
},
Finalize {
name: &'static str,
source: BoxError,
},
Dependency {
name: &'static str,
source: BoxError,
},
Run {
name: &'static str,
source: BoxError,
},
Recoverable {
name: &'static str,
source: BoxError,
},
Other(BoxError),
}
impl std::fmt::Display for Error {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
match self {
Error::Invalid(outcome) => {
let names = outcome
.failures()
.iter()
.map(|failure| failure.component())
.collect::<Vec<_>>()
.join(", ");
write!(
f,
"{} component(s) failed validation: {names}",
outcome.failed_count()
)
}
Error::DuplicateComponent { type_name } => {
write!(f, "component type '{type_name}' is already registered")
}
Error::Boot { name, source } => {
write!(f, "component '{name}' failed during boot: {source}")
}
Error::Validate { name, source } => {
write!(f, "component '{name}' failed during validate: {source}")
}
Error::Reload { name, source } => {
write!(f, "reload of '{name}' failed: {source}")
}
Error::Finalize { name, source } => {
write!(f, "finalize of '{name}' failed: {source}")
}
Error::Dependency { name, source } => {
write!(
f,
"component '{name}' is missing a dependency: {source}"
)
}
Error::Run { name, source } => {
write!(f, "runnable '{name}' failed: {source}")
}
Error::Recoverable { name, source } => {
write!(f, "runnable '{name}' failed (recoverable): {source}")
}
Error::Other(e) => std::fmt::Display::fmt(e, f),
}
}
}
impl<E> From<E> for Error
where
E: std::error::Error + Send + Sync + 'static,
{
fn from(e: E) -> Self {
Error::Other(Box::new(e))
}
}
impl Error {
pub fn into_std(self) -> StdError {
StdError(self)
}
}
#[derive(Debug)]
pub struct StdError(Error);
impl StdError {
pub fn into_inner(self) -> Error {
self.0
}
}
impl std::fmt::Display for StdError {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
impl std::error::Error for StdError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.0 {
Error::Boot { source, .. }
| Error::Validate { source, .. }
| Error::Reload { source, .. }
| Error::Finalize { source, .. }
| Error::Dependency { source, .. }
| Error::Other(source) => Some(source.as_ref()),
_ => None,
}
}
}
impl From<Error> for StdError {
fn from(error: Error) -> Self {
error.into_std()
}
}
impl Error {
pub fn msg(s: impl Into<String>) -> Self {
#[derive(Debug)]
struct MsgErr(String);
impl std::fmt::Display for MsgErr {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
impl std::error::Error for MsgErr {}
Error::Other(Box::new(MsgErr(s.into())))
}
pub(super) fn into_boot(
self,
name: &'static str,
) -> Self {
match self {
Error::Other(source) => Error::Boot { name, source },
other => other,
}
}
pub(super) fn into_validate(
self,
name: &'static str,
) -> Self {
match self {
Error::Other(source) => Error::Validate { name, source },
other => other,
}
}
pub(crate) fn into_reload(
self,
name: &'static str,
) -> Self {
match self {
Error::Other(source) => Error::Reload { name, source },
other => other,
}
}
pub(super) fn into_dependency(
self,
name: &'static str,
) -> Self {
match self {
Error::Other(source) => Error::Dependency { name, source },
other => other,
}
}
pub(super) fn into_finalize(
self,
name: &'static str,
) -> Self {
match self {
Error::Other(source) => Error::Finalize { name, source },
other => other,
}
}
pub(crate) fn into_run(
self,
name: &'static str,
) -> Self {
match self {
Error::Other(source) => Error::Run { name, source },
Error::Recoverable { name: "", source } => {
Error::Recoverable { name, source }
}
other => other,
}
}
pub fn recoverable(s: impl Into<String>) -> Self {
#[derive(Debug)]
struct MsgErr(String);
impl std::fmt::Display for MsgErr {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
impl std::error::Error for MsgErr {}
Error::Recoverable { name: "", source: Box::new(MsgErr(s.into())) }
}
}