use serde::{Deserialize, Serialize};
use std::{
fmt,
fmt::{Display, Write},
str::FromStr,
};
use thiserror::Error;
use throw_error::Error;
use url::Url;
pub const SERVER_FN_ERROR_HEADER: &str = "serverfnerror";
impl From<ServerFnError> for Error {
fn from(e: ServerFnError) -> Self {
Error::from(ServerFnErrorErr::from(e))
}
}
#[derive(
Debug,
Deserialize,
Serialize,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
Clone,
Copy,
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
pub struct NoCustomError;
impl fmt::Display for NoCustomError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Unit Type Displayed")
}
}
impl FromStr for NoCustomError {
type Err = ();
fn from_str(_s: &str) -> Result<Self, Self::Err> {
Ok(NoCustomError)
}
}
#[derive(Debug)]
pub struct WrapError<T>(pub T);
#[macro_export]
macro_rules! server_fn_error {
() => {{
use $crate::{ViaError, WrapError};
(&&&&&WrapError(())).to_server_error()
}};
($err:expr) => {{
use $crate::error::{ViaError, WrapError};
match $err {
error => (&&&&&WrapError(error)).to_server_error(),
}
}};
}
pub trait ViaError<E> {
fn to_server_error(&self) -> ServerFnError<E>;
}
impl<E: ServerFnErrorKind + std::error::Error + Clone> ViaError<E>
for &&&&WrapError<ServerFnError<E>>
{
fn to_server_error(&self) -> ServerFnError<E> {
self.0.clone()
}
}
pub(crate) trait ServerFnErrorKind {}
impl ServerFnErrorKind for ServerFnError {}
impl ViaError<NoCustomError> for &&&WrapError<()> {
fn to_server_error(&self) -> ServerFnError {
ServerFnError::WrappedServerError(NoCustomError)
}
}
impl<E: std::error::Error + Clone> ViaError<E> for &&WrapError<E> {
fn to_server_error(&self) -> ServerFnError<E> {
ServerFnError::WrappedServerError(self.0.clone())
}
}
impl<E: Display + Clone> ViaError<E> for &WrapError<E> {
fn to_server_error(&self) -> ServerFnError<E> {
ServerFnError::ServerError(self.0.to_string())
}
}
impl<E> ViaError<E> for WrapError<E> {
#[track_caller]
fn to_server_error(&self) -> ServerFnError<E> {
panic!(
"At {}, you call `to_server_error()` or use `server_fn_error!` \
with a value that does not implement `Clone` and either `Error` \
or `Display`.",
std::panic::Location::caller()
);
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
pub enum ServerFnError<E = NoCustomError> {
WrappedServerError(E),
Registration(String),
Request(String),
Response(String),
ServerError(String),
Deserialization(String),
Serialization(String),
Args(String),
MissingArg(String),
}
impl ServerFnError<NoCustomError> {
pub fn new(msg: impl ToString) -> Self {
Self::ServerError(msg.to_string())
}
}
impl<CustErr> From<CustErr> for ServerFnError<CustErr> {
fn from(value: CustErr) -> Self {
ServerFnError::WrappedServerError(value)
}
}
impl<E: std::error::Error> From<E> for ServerFnError {
fn from(value: E) -> Self {
ServerFnError::ServerError(value.to_string())
}
}
impl<CustErr> Display for ServerFnError<CustErr>
where
CustErr: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
ServerFnError::Registration(s) => format!(
"error while trying to register the server function: {s}"
),
ServerFnError::Request(s) => format!(
"error reaching server to call server function: {s}"
),
ServerFnError::ServerError(s) =>
format!("error running server function: {s}"),
ServerFnError::Deserialization(s) =>
format!("error deserializing server function results: {s}"),
ServerFnError::Serialization(s) =>
format!("error serializing server function arguments: {s}"),
ServerFnError::Args(s) => format!(
"error deserializing server function arguments: {s}"
),
ServerFnError::MissingArg(s) => format!("missing argument {s}"),
ServerFnError::Response(s) =>
format!("error generating HTTP response: {s}"),
ServerFnError::WrappedServerError(e) => format!("{e}"),
}
)
}
}
pub trait ServerFnErrorSerde: Sized {
fn ser(&self) -> Result<String, std::fmt::Error>;
fn de(data: &str) -> Self;
}
impl<CustErr> ServerFnErrorSerde for ServerFnError<CustErr>
where
CustErr: FromStr + Display,
{
fn ser(&self) -> Result<String, std::fmt::Error> {
let mut buf = String::new();
match self {
ServerFnError::WrappedServerError(e) => {
write!(&mut buf, "WrappedServerFn|{e}")
}
ServerFnError::Registration(e) => {
write!(&mut buf, "Registration|{e}")
}
ServerFnError::Request(e) => write!(&mut buf, "Request|{e}"),
ServerFnError::Response(e) => write!(&mut buf, "Response|{e}"),
ServerFnError::ServerError(e) => {
write!(&mut buf, "ServerError|{e}")
}
ServerFnError::Deserialization(e) => {
write!(&mut buf, "Deserialization|{e}")
}
ServerFnError::Serialization(e) => {
write!(&mut buf, "Serialization|{e}")
}
ServerFnError::Args(e) => write!(&mut buf, "Args|{e}"),
ServerFnError::MissingArg(e) => {
write!(&mut buf, "MissingArg|{e}")
}
}?;
Ok(buf)
}
fn de(data: &str) -> Self {
data.split_once('|')
.and_then(|(ty, data)| match ty {
"WrappedServerFn" => match CustErr::from_str(data) {
Ok(d) => Some(ServerFnError::WrappedServerError(d)),
Err(_) => None,
},
"Registration" => {
Some(ServerFnError::Registration(data.to_string()))
}
"Request" => Some(ServerFnError::Request(data.to_string())),
"Response" => Some(ServerFnError::Response(data.to_string())),
"ServerError" => {
Some(ServerFnError::ServerError(data.to_string()))
}
"Deserialization" => {
Some(ServerFnError::Deserialization(data.to_string()))
}
"Serialization" => {
Some(ServerFnError::Serialization(data.to_string()))
}
"Args" => Some(ServerFnError::Args(data.to_string())),
"MissingArg" => {
Some(ServerFnError::MissingArg(data.to_string()))
}
_ => None,
})
.unwrap_or_else(|| {
ServerFnError::Deserialization(format!(
"Could not deserialize error {data:?}"
))
})
}
}
impl<E> std::error::Error for ServerFnError<E>
where
E: std::error::Error + 'static,
ServerFnError<E>: std::fmt::Display,
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
ServerFnError::WrappedServerError(e) => Some(e),
_ => None,
}
}
}
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum ServerFnErrorErr<E = NoCustomError> {
#[error("internal error: {0}")]
WrappedServerError(E),
#[error("error while trying to register the server function: {0}")]
Registration(String),
#[error("error reaching server to call server function: {0}")]
Request(String),
#[error("error running server function: {0}")]
ServerError(String),
#[error("error deserializing server function results: {0}")]
Deserialization(String),
#[error("error serializing server function arguments: {0}")]
Serialization(String),
#[error("error deserializing server function arguments: {0}")]
Args(String),
#[error("missing argument {0}")]
MissingArg(String),
#[error("error creating response {0}")]
Response(String),
}
impl<CustErr> From<ServerFnError<CustErr>> for ServerFnErrorErr<CustErr> {
fn from(value: ServerFnError<CustErr>) -> Self {
match value {
ServerFnError::Registration(value) => {
ServerFnErrorErr::Registration(value)
}
ServerFnError::Request(value) => ServerFnErrorErr::Request(value),
ServerFnError::ServerError(value) => {
ServerFnErrorErr::ServerError(value)
}
ServerFnError::Deserialization(value) => {
ServerFnErrorErr::Deserialization(value)
}
ServerFnError::Serialization(value) => {
ServerFnErrorErr::Serialization(value)
}
ServerFnError::Args(value) => ServerFnErrorErr::Args(value),
ServerFnError::MissingArg(value) => {
ServerFnErrorErr::MissingArg(value)
}
ServerFnError::WrappedServerError(value) => {
ServerFnErrorErr::WrappedServerError(value)
}
ServerFnError::Response(value) => ServerFnErrorErr::Response(value),
}
}
}
#[derive(Debug)]
pub struct ServerFnUrlError<CustErr> {
path: String,
error: ServerFnError<CustErr>,
}
impl<CustErr> ServerFnUrlError<CustErr> {
pub fn new(path: impl Display, error: ServerFnError<CustErr>) -> Self {
Self {
path: path.to_string(),
error,
}
}
pub fn error(&self) -> &ServerFnError<CustErr> {
&self.error
}
pub fn path(&self) -> &str {
&self.path
}
pub fn to_url(&self, base: &str) -> Result<Url, url::ParseError>
where
CustErr: FromStr + Display,
{
let mut url = Url::parse(base)?;
url.query_pairs_mut()
.append_pair("__path", &self.path)
.append_pair(
"__err",
&ServerFnErrorSerde::ser(&self.error).unwrap_or_default(),
);
Ok(url)
}
pub fn strip_error_info(path: &mut String) {
if let Ok(mut url) = Url::parse(&*path) {
let pairs_previously = url
.query_pairs()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect::<Vec<_>>();
let mut pairs = url.query_pairs_mut();
pairs.clear();
for (key, value) in pairs_previously
.into_iter()
.filter(|(key, _)| key != "__path" && key != "__err")
{
pairs.append_pair(&key, &value);
}
drop(pairs);
*path = url.to_string();
}
}
}
impl<CustErr> From<ServerFnUrlError<CustErr>> for ServerFnError<CustErr> {
fn from(error: ServerFnUrlError<CustErr>) -> Self {
error.error
}
}
impl<CustErr> From<ServerFnUrlError<CustErr>> for ServerFnErrorErr<CustErr> {
fn from(error: ServerFnUrlError<CustErr>) -> Self {
error.error.into()
}
}