1use std::fmt::{Debug, Display};
12
13use rustolio_utils::{http::StatusCode, prelude::*};
14
15#[derive(Debug, Encode, Decode)]
16pub enum NoCustomError {}
17
18impl std::fmt::Display for NoCustomError {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 write!(f, "self:?")
21 }
22}
23impl std::error::Error for NoCustomError {}
24
25#[derive(Debug, Encode, Decode)]
26pub enum ServerFnError<E = NoCustomError> {
27 RpcError(E),
29
30 NetworkError(String),
32
33 #[encode(skip)]
36 HttpError(StatusCode, String),
37
38 SerializationError(String),
40
41 DeserializationError(String),
43}
44
45impl<E> ServerFnError<E> {
46 pub fn http_error(
47 status_code: impl TryInto<StatusCode, Error: Debug>,
48 msg: impl Display,
49 ) -> Self {
50 ServerFnError::HttpError(
51 status_code.try_into().expect("Could not parse StatusCode"),
52 msg.to_string(),
53 )
54 }
55}
56
57impl<E> ServerFnError<E> {
59 pub fn from(value: ServerFnError<NoCustomError>) -> Self {
60 match value {
61 ServerFnError::RpcError(_) => {
62 unreachable!("NoCustomError cannot be constructed")
63 }
64 ServerFnError::NetworkError(msg) => ServerFnError::NetworkError(msg),
65 ServerFnError::HttpError(status, msg) => ServerFnError::HttpError(status, msg),
66 ServerFnError::SerializationError(msg) => ServerFnError::SerializationError(msg),
67 ServerFnError::DeserializationError(msg) => ServerFnError::DeserializationError(msg),
68 }
69 }
70}
71
72impl ServerFnError<NoCustomError> {
73 pub fn into<E>(self) -> ServerFnError<E> {
74 ServerFnError::from(self)
75 }
76}
77
78impl<E> From<E> for ServerFnError<E> {
79 fn from(value: E) -> Self {
80 ServerFnError::RpcError(value)
81 }
82}
83
84pub trait IntoServerResult<T, E> {
85 fn server_result(self) -> std::result::Result<T, ServerFnError<E>>;
86}
87
88impl<T, E, C> IntoServerResult<T, C> for std::result::Result<T, E>
89where
90 E: Into<C>,
91{
92 fn server_result(self) -> std::result::Result<T, ServerFnError<C>> {
93 match self {
94 Ok(v) => Ok(v),
95 Err(e) => Err(ServerFnError::RpcError(e.into())),
96 }
97 }
98}
99
100impl<E> std::fmt::Display for ServerFnError<E> {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 write!(f, "self:?")
103 }
104}
105impl<E> std::error::Error for ServerFnError<E> where E: std::error::Error {}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[allow(unused)]
112 struct MyCustomError;
113
114 impl Into<ServerFnError<String>> for MyCustomError {
115 fn into(self) -> ServerFnError<String> {
116 ServerFnError::HttpError(StatusCode::BAD_REQUEST, "MyCustomError".to_string())
117 }
118 }
119
120 fn _test_server_fn_error_from_conversion() -> std::result::Result<(), ServerFnError<String>> {
122 Err("Custom error".to_string())?;
124 Err(ServerFnError::NetworkError("Network issue".to_string()))?;
125
126 if let Err(e) = Err::<(), _>(MyCustomError) {
128 return Err(e.into());
129 }
130
131 if let Err(e) = Err::<(), _>(String::from("Custom error")) {
133 return Err(e.into());
134 }
135
136 if let Err(e) =
138 Err::<(), ServerFnError>(ServerFnError::NetworkError("Network issue".to_string()))
139 {
140 return Err(e.into());
141 }
142
143 Ok(())
144 }
145
146 fn _rpc_endpoint() -> std::result::Result<String, ServerFnError<String>> {
147 let _ = Ok::<_, String>(String::from("Ok"))?;
148 let _ = Err(String::from("Err"))?;
149 let _ = Err("Err").server_result()?;
150 unreachable!()
151 }
152}