use std::fmt::{self, Debug, Display};
use std::sync::Arc;
use thiserror::Error;
use {fidl_fuchsia_component_sandbox as fsandbox, zx_status as zx};
#[derive(Debug, Error, Clone)]
pub enum RouterError {
#[error("{0}")]
NotFound(Arc<dyn Explain>),
#[error("invalid arguments")]
InvalidArgs,
#[error("not supported")]
NotSupported,
#[error("internal")]
Internal,
#[error("unknown")]
Unknown,
}
impl From<fsandbox::RouterError> for RouterError {
fn from(err: fsandbox::RouterError) -> Self {
match err {
fsandbox::RouterError::NotFound => Self::NotFound(Arc::new(ExternalNotFoundError {})),
fsandbox::RouterError::InvalidArgs => Self::InvalidArgs,
fsandbox::RouterError::NotSupported => Self::NotSupported,
fsandbox::RouterError::Internal => Self::Internal,
fsandbox::RouterErrorUnknown!() => Self::Unknown,
}
}
}
impl From<RouterError> for fsandbox::RouterError {
fn from(err: RouterError) -> Self {
match err {
RouterError::NotFound(_) => Self::NotFound,
RouterError::InvalidArgs => Self::InvalidArgs,
RouterError::NotSupported => Self::NotSupported,
RouterError::Internal => Self::Internal,
RouterError::Unknown => Self::unknown(),
}
}
}
#[derive(Debug, Error, Clone)]
struct ExternalNotFoundError {}
impl Explain for ExternalNotFoundError {
fn as_zx_status(&self) -> zx::Status {
zx::Status::NOT_FOUND
}
}
impl fmt::Display for ExternalNotFoundError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "external not found error")
}
}
pub trait Explain: std::error::Error + Debug + Display + Send + Sync + sealed::AnyCast {
fn as_zx_status(&self) -> zx::Status;
}
impl Explain for RouterError {
fn as_zx_status(&self) -> zx::Status {
match self {
Self::NotFound(err) => err.as_zx_status(),
Self::InvalidArgs => zx::Status::INVALID_ARGS,
Self::NotSupported => zx::Status::NOT_SUPPORTED,
Self::Internal => zx::Status::INTERNAL,
Self::Unknown => zx::Status::INTERNAL,
}
}
}
pub trait DowncastErrorForTest {
fn downcast_for_test<E: Explain>(&self) -> &E;
}
impl DowncastErrorForTest for dyn Explain {
fn downcast_for_test<E: Explain>(&self) -> &E {
match self.as_any().downcast_ref::<E>() {
Some(value) => value,
None => {
let expected = std::any::type_name::<E>();
panic!("Cannot downcast `{self:?}` to the {expected:?} error type!");
}
}
}
}
mod sealed {
use std::any::Any;
pub trait AnyCast: Any {
fn as_any(&self) -> &dyn Any;
}
impl<T: Any> AnyCast for T {
fn as_any(&self) -> &dyn Any {
self
}
}
}