use std::any::Any;
use std::{fmt, io};
use crate::{coordinator, worker};
pub struct Error {
inner: ErrorInner,
}
enum ErrorInner {
Setup(StringError),
SetupTrace(io::Error),
InitCoordinator(io::Error),
Coordinator(coordinator::Error),
StartWorker(io::Error),
Worker(worker::Error),
WorkerPanic(StringError),
StartSyncActor(io::Error),
SyncActorPanic(StringError),
}
impl Error {
const DESC: &'static str = "error running Heph runtime";
#[allow(clippy::needless_pass_by_value)]
pub fn setup<E>(err: E) -> Error
where
E: ToString,
{
Error {
inner: ErrorInner::Setup(StringError(err.to_string())),
}
}
pub(super) const fn setup_trace(err: io::Error) -> Error {
Error {
inner: ErrorInner::SetupTrace(err),
}
}
pub(super) const fn init_coordinator(err: io::Error) -> Error {
Error {
inner: ErrorInner::InitCoordinator(err),
}
}
pub(super) const fn coordinator(err: coordinator::Error) -> Error {
Error {
inner: ErrorInner::Coordinator(err),
}
}
pub(super) const fn start_worker(err: io::Error) -> Error {
Error {
inner: ErrorInner::StartWorker(err),
}
}
pub(super) const fn worker(err: worker::Error) -> Error {
Error {
inner: ErrorInner::Worker(err),
}
}
pub(super) fn worker_panic(err: Box<dyn Any + Send + 'static>) -> Error {
let msg = convert_panic(err);
Error {
inner: ErrorInner::WorkerPanic(msg),
}
}
pub(super) const fn start_sync_actor(err: io::Error) -> Error {
Error {
inner: ErrorInner::StartSyncActor(err),
}
}
pub(super) fn sync_actor_panic(err: Box<dyn Any + Send + 'static>) -> Error {
let msg = convert_panic(err);
Error {
inner: ErrorInner::SyncActorPanic(msg),
}
}
}
fn convert_panic(err: Box<dyn Any + Send + 'static>) -> StringError {
let msg = match err.downcast::<&'static str>() {
Ok(s) => (*s).to_owned(),
Err(err) => match err.downcast::<String>() {
Ok(s) => *s,
Err(..) => {
"unknown panic message (use `String` or `&'static str` in the future)".to_owned()
}
},
};
StringError(msg)
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ErrorInner::*;
match self.inner {
Setup(ref err) => {
write!(f, "{}: error in user-defined setup: {}", Self::DESC, err)
}
SetupTrace(ref err) => write!(
f,
"{}: error setting up trace infrastructure: {}",
Self::DESC,
err
),
InitCoordinator(ref err) => {
write!(f, "{}: error creating coordinator: {}", Self::DESC, err)
}
Coordinator(ref err) => {
write!(f, "{}: error in coordinator thread: {}", Self::DESC, err)
}
StartWorker(ref err) => {
write!(f, "{}: error starting worker thread: {}", Self::DESC, err)
}
Worker(ref err) => write!(f, "{}: error in worker thread: {}", Self::DESC, err),
WorkerPanic(ref msg) => write!(f, "{}: panic in worker thread: {}", Self::DESC, msg),
StartSyncActor(ref err) => write!(
f,
"{}: error starting synchronous actor: {}",
Self::DESC,
err
),
SyncActorPanic(ref msg) => write!(
f,
"{}: panic in synchronous actor thread: {}",
Self::DESC,
msg
),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use ErrorInner::*;
match self.inner {
SetupTrace(ref err)
| InitCoordinator(ref err)
| StartWorker(ref err)
| StartSyncActor(ref err) => Some(err),
Coordinator(ref err) => Some(err),
Worker(ref err) => Some(err),
Setup(ref err) | WorkerPanic(ref err) | SyncActorPanic(ref err) => Some(err),
}
}
}
pub(crate) struct StringError(String);
impl From<String> for StringError {
fn from(err: String) -> StringError {
StringError(err)
}
}
impl fmt::Debug for StringError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl fmt::Display for StringError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl std::error::Error for StringError {}