1use serde::{Deserialize, Serialize};
2use thiserror::Error;
3
4pub type RpcResult<T> = Result<T, RuntimeError>;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
7#[repr(i32)]
8pub enum RuntimeErrorCode {
9 UnknownMessageKind = 1001,
10 UnsupportedProtocolVersion = 1002,
11 InvalidEnvelope = 1003,
12 InvalidRequestId = 1004,
13 InvalidInstanceId = 1005,
14 InstanceNotFound = 1006,
15 MethodNotFound = 1007,
16 NotificationNotFound = 1008,
17 PayloadDecodeFailed = 1009,
18 PayloadEncodeFailed = 1010,
19 ServiceActivationNotSupported = 1011,
20 ServiceGuidNotFound = 1012,
21 InstanceReleaseNotAllowed = 1013,
22 RequestTimeout = 1014,
23 UnsupportedCapability = 1015,
24 BusinessErrorDeclared = 1016,
25 DuplicateRequestId = 1017,
26 RequestCancelUnsupported = 1018,
27 AccessDenied = 1019,
28 InternalRuntimeError = 1020,
29}
30
31impl RuntimeErrorCode {
32 pub const fn as_i32(self) -> i32 {
33 self as i32
34 }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
38#[repr(u8)]
39pub enum ErrorKind {
40 Transport = 1,
41 Protocol = 2,
42 Runtime = 3,
43 Business = 4,
44 Timeout = 5,
45 Cancelled = 6,
46}
47
48impl ErrorKind {
49 pub const fn as_u8(self) -> u8 {
50 self as u8
51 }
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Error, Serialize, Deserialize)]
55#[error("{kind:?} error {code:?}: {message}")]
56pub struct RuntimeError {
57 pub code: RuntimeErrorCode,
58 pub kind: ErrorKind,
59 pub message: String,
60}
61
62impl RuntimeError {
63 pub fn new(code: RuntimeErrorCode, kind: ErrorKind, message: impl Into<String>) -> Self {
64 Self {
65 code,
66 kind,
67 message: message.into(),
68 }
69 }
70
71 pub fn protocol(code: RuntimeErrorCode, message: impl Into<String>) -> Self {
72 Self::new(code, ErrorKind::Protocol, message)
73 }
74
75 pub fn transport(code: RuntimeErrorCode, message: impl Into<String>) -> Self {
76 Self::new(code, ErrorKind::Transport, message)
77 }
78
79 pub fn runtime(code: RuntimeErrorCode, message: impl Into<String>) -> Self {
80 Self::new(code, ErrorKind::Runtime, message)
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn runtime_error_code_values_are_stable() {
90 assert_eq!(RuntimeErrorCode::UnknownMessageKind.as_i32(), 1001);
91 assert_eq!(RuntimeErrorCode::UnsupportedProtocolVersion.as_i32(), 1002);
92 assert_eq!(RuntimeErrorCode::InvalidEnvelope.as_i32(), 1003);
93 assert_eq!(RuntimeErrorCode::InvalidRequestId.as_i32(), 1004);
94 assert_eq!(RuntimeErrorCode::InvalidInstanceId.as_i32(), 1005);
95 assert_eq!(RuntimeErrorCode::InstanceNotFound.as_i32(), 1006);
96 assert_eq!(RuntimeErrorCode::MethodNotFound.as_i32(), 1007);
97 assert_eq!(RuntimeErrorCode::NotificationNotFound.as_i32(), 1008);
98 assert_eq!(RuntimeErrorCode::PayloadDecodeFailed.as_i32(), 1009);
99 assert_eq!(RuntimeErrorCode::PayloadEncodeFailed.as_i32(), 1010);
100 assert_eq!(
101 RuntimeErrorCode::ServiceActivationNotSupported.as_i32(),
102 1011
103 );
104 assert_eq!(RuntimeErrorCode::ServiceGuidNotFound.as_i32(), 1012);
105 assert_eq!(RuntimeErrorCode::InstanceReleaseNotAllowed.as_i32(), 1013);
106 assert_eq!(RuntimeErrorCode::RequestTimeout.as_i32(), 1014);
107 assert_eq!(RuntimeErrorCode::UnsupportedCapability.as_i32(), 1015);
108 assert_eq!(RuntimeErrorCode::BusinessErrorDeclared.as_i32(), 1016);
109 assert_eq!(RuntimeErrorCode::DuplicateRequestId.as_i32(), 1017);
110 assert_eq!(RuntimeErrorCode::RequestCancelUnsupported.as_i32(), 1018);
111 assert_eq!(RuntimeErrorCode::AccessDenied.as_i32(), 1019);
112 assert_eq!(RuntimeErrorCode::InternalRuntimeError.as_i32(), 1020);
113 }
114
115 #[test]
116 fn error_kind_values_are_stable() {
117 assert_eq!(ErrorKind::Transport.as_u8(), 1);
118 assert_eq!(ErrorKind::Protocol.as_u8(), 2);
119 assert_eq!(ErrorKind::Runtime.as_u8(), 3);
120 assert_eq!(ErrorKind::Business.as_u8(), 4);
121 assert_eq!(ErrorKind::Timeout.as_u8(), 5);
122 assert_eq!(ErrorKind::Cancelled.as_u8(), 6);
123 }
124}