Skip to main content

orpc_procedure/
error.rs

1use std::any::Any;
2use std::fmt;
3
4/// Error during input deserialization.
5#[derive(Debug)]
6pub struct DeserializeError(pub Box<dyn std::error::Error + Send + Sync>);
7
8impl fmt::Display for DeserializeError {
9    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
10        write!(f, "{}", self.0)
11    }
12}
13
14impl std::error::Error for DeserializeError {
15    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
16        Some(&*self.0)
17    }
18}
19
20impl From<serde_json::Error> for DeserializeError {
21    fn from(err: serde_json::Error) -> Self {
22        DeserializeError(Box::new(err))
23    }
24}
25
26impl From<erased_serde::Error> for DeserializeError {
27    fn from(err: erased_serde::Error) -> Self {
28        DeserializeError(Box::new(err))
29    }
30}
31
32/// Error during output serialization.
33#[derive(Debug)]
34pub struct SerializeError(pub Box<dyn std::error::Error + Send + Sync>);
35
36impl fmt::Display for SerializeError {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        write!(f, "{}", self.0)
39    }
40}
41
42impl std::error::Error for SerializeError {
43    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
44        Some(&*self.0)
45    }
46}
47
48impl From<serde_json::Error> for SerializeError {
49    fn from(err: serde_json::Error) -> Self {
50        SerializeError(Box::new(err))
51    }
52}
53
54/// Universal error type for the type-erased execution layer.
55///
56/// All errors that can occur during procedure execution are represented here.
57/// Higher-level error types (e.g., ORPCError) convert into `ProcedureError`
58/// via the `Resolver` variant.
59#[derive(Debug)]
60pub enum ProcedureError {
61    /// Input deserialization failed (malformed JSON, type mismatch, etc.)
62    Deserialize(DeserializeError),
63    /// Output serialization failed
64    Serialize(SerializeError),
65    /// Handler panicked (caught by `catch_unwind`)
66    Unwind(Box<dyn Any + Send>),
67    /// Application-level error from user handler or middleware
68    Resolver(Box<dyn std::error::Error + Send + Sync>),
69}
70
71impl fmt::Display for ProcedureError {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        match self {
74            ProcedureError::Deserialize(e) => write!(f, "deserialization error: {e}"),
75            ProcedureError::Serialize(e) => write!(f, "serialization error: {e}"),
76            ProcedureError::Unwind(_) => write!(f, "handler panicked"),
77            ProcedureError::Resolver(e) => write!(f, "{e}"),
78        }
79    }
80}
81
82impl std::error::Error for ProcedureError {
83    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
84        match self {
85            ProcedureError::Deserialize(e) => Some(e),
86            ProcedureError::Serialize(e) => Some(e),
87            ProcedureError::Unwind(_) => None,
88            ProcedureError::Resolver(e) => Some(&**e),
89        }
90    }
91}
92
93impl From<DeserializeError> for ProcedureError {
94    fn from(err: DeserializeError) -> Self {
95        ProcedureError::Deserialize(err)
96    }
97}
98
99impl From<SerializeError> for ProcedureError {
100    fn from(err: SerializeError) -> Self {
101        ProcedureError::Serialize(err)
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use std::error::Error;
108
109    use super::*;
110
111    #[test]
112    fn deserialize_error_display() {
113        let err = DeserializeError(Box::new(std::io::Error::new(
114            std::io::ErrorKind::InvalidData,
115            "bad input",
116        )));
117        assert_eq!(err.to_string(), "bad input");
118    }
119
120    #[test]
121    fn serialize_error_display() {
122        let err = SerializeError(Box::new(std::io::Error::other("write failed")));
123        assert_eq!(err.to_string(), "write failed");
124    }
125
126    #[test]
127    fn procedure_error_deserialize_variant() {
128        let err = ProcedureError::Deserialize(DeserializeError(Box::new(std::io::Error::new(
129            std::io::ErrorKind::InvalidData,
130            "bad json",
131        ))));
132        assert!(err.to_string().contains("deserialization error"));
133        assert!(err.to_string().contains("bad json"));
134        assert!(err.source().is_some());
135    }
136
137    #[test]
138    fn procedure_error_serialize_variant() {
139        let err = ProcedureError::Serialize(SerializeError(Box::new(std::io::Error::other(
140            "encode failed",
141        ))));
142        assert!(err.to_string().contains("serialization error"));
143        assert!(err.source().is_some());
144    }
145
146    #[test]
147    fn procedure_error_unwind_variant() {
148        let err = ProcedureError::Unwind(Box::new("panic message"));
149        assert_eq!(err.to_string(), "handler panicked");
150        assert!(err.source().is_none());
151    }
152
153    #[test]
154    fn procedure_error_resolver_variant() {
155        let err = ProcedureError::Resolver(Box::new(std::io::Error::new(
156            std::io::ErrorKind::NotFound,
157            "user not found",
158        )));
159        assert_eq!(err.to_string(), "user not found");
160        assert!(err.source().is_some());
161    }
162
163    #[test]
164    fn from_deserialize_error() {
165        let de_err = DeserializeError(Box::new(std::io::Error::other("test")));
166        let proc_err: ProcedureError = de_err.into();
167        assert!(matches!(proc_err, ProcedureError::Deserialize(_)));
168    }
169
170    #[test]
171    fn from_serialize_error() {
172        let se_err = SerializeError(Box::new(std::io::Error::other("test")));
173        let proc_err: ProcedureError = se_err.into();
174        assert!(matches!(proc_err, ProcedureError::Serialize(_)));
175    }
176
177    #[test]
178    fn deserialize_error_from_serde_json() {
179        let json_err = serde_json::from_str::<String>("not json").unwrap_err();
180        let de_err: DeserializeError = json_err.into();
181        assert!(!de_err.to_string().is_empty());
182    }
183
184    #[test]
185    fn procedure_error_is_send() {
186        fn assert_send<T: Send>() {}
187        assert_send::<ProcedureError>();
188    }
189}