use std::{any::Any, borrow::Cow, error, fmt};
use serde::{
ser::{Error, SerializeStruct},
Serialize, Serializer,
};
pub enum ProcedureError {
NotFound,
Deserialize(DeserializeError),
Downcast(DowncastError),
Resolver(ResolverError),
Unwind(Box<dyn Any + Send>),
}
impl ProcedureError {
pub fn variant(&self) -> &'static str {
match self {
ProcedureError::NotFound => "NotFound",
ProcedureError::Deserialize(_) => "Deserialize",
ProcedureError::Downcast(_) => "Downcast",
ProcedureError::Resolver(_) => "Resolver",
ProcedureError::Unwind(_) => "ResolverPanic",
}
}
pub fn message(&self) -> Cow<'static, str> {
match self {
ProcedureError::NotFound => "procedure not found".into(),
ProcedureError::Deserialize(err) => err.0.to_string().into(),
ProcedureError::Downcast(err) => err.to_string().into(),
ProcedureError::Resolver(err) => err
.error()
.map(|err| err.to_string().into())
.unwrap_or("resolver error".into()),
ProcedureError::Unwind(_) => "resolver panic".into(),
}
}
}
impl From<ResolverError> for ProcedureError {
fn from(err: ResolverError) -> Self {
ProcedureError::Resolver(err)
}
}
impl From<DeserializeError> for ProcedureError {
fn from(err: DeserializeError) -> Self {
ProcedureError::Deserialize(err)
}
}
impl From<DowncastError> for ProcedureError {
fn from(err: DowncastError) -> Self {
ProcedureError::Downcast(err)
}
}
impl fmt::Debug for ProcedureError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NotFound => write!(f, "NotFound"),
Self::Deserialize(err) => write!(f, "Deserialize({err:?})"),
Self::Downcast(err) => write!(f, "Downcast({err:?})"),
Self::Resolver(err) => write!(f, "Resolver({err:?})"),
Self::Unwind(err) => write!(f, "ResolverPanic({err:?})"),
}
}
}
impl fmt::Display for ProcedureError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl error::Error for ProcedureError {}
impl Serialize for ProcedureError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if let ProcedureError::Resolver(err) = self {
return err.value().serialize(serializer);
}
let mut state = serializer.serialize_struct("ProcedureError", 3)?;
state.serialize_field("~rspc", &true)?;
state.serialize_field("variant", &self.variant())?;
state.serialize_field("message", &self.message())?;
state.end()
}
}
pub struct ResolverError(Box<dyn ErrorInternalExt>);
impl ResolverError {
pub fn new<T: Serialize + Send + 'static, E: error::Error + Send + 'static>(
value: T,
source: Option<E>,
) -> Self {
Self(Box::new(ErrorInternal { value, err: source }))
}
pub fn value(&self) -> impl Serialize + '_ {
self.0.value()
}
pub fn error(&self) -> Option<&(dyn error::Error + Send + 'static)> {
self.0.error()
}
}
impl fmt::Debug for ResolverError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ResolverError({:?})", self.0.debug())
}
}
impl fmt::Display for ResolverError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl error::Error for ResolverError {}
pub struct DeserializeError(pub(crate) erased_serde::Error);
impl DeserializeError {
pub fn custom<T: fmt::Display>(err: T) -> Self {
Self(erased_serde::Error::custom(err))
}
}
impl fmt::Debug for DeserializeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Deserialize({:?})", self.0)
}
}
impl fmt::Display for DeserializeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl error::Error for DeserializeError {}
pub struct DowncastError {
pub(crate) from: Option<&'static str>,
pub(crate) to: &'static str,
}
impl fmt::Debug for DowncastError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Downcast(from: {:?}, to: {:?})", self.from, self.to)
}
}
impl fmt::Display for DowncastError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl error::Error for DowncastError {}
struct ErrorInternal<T, E> {
value: T,
err: Option<E>,
}
trait ErrorInternalExt: Send {
fn value(&self) -> &dyn erased_serde::Serialize;
fn error(&self) -> Option<&(dyn error::Error + Send + 'static)>;
fn debug(&self) -> Option<&dyn fmt::Debug>;
}
impl<T: Serialize + Send + 'static, E: error::Error + Send + 'static> ErrorInternalExt
for ErrorInternal<T, E>
{
fn value(&self) -> &dyn erased_serde::Serialize {
&self.value
}
fn error(&self) -> Option<&(dyn error::Error + Send + 'static)> {
self.err
.as_ref()
.map(|err| err as &(dyn error::Error + Send + 'static))
}
fn debug(&self) -> Option<&dyn fmt::Debug> {
self.err.as_ref().map(|err| err as &dyn fmt::Debug)
}
}