1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8#[repr(u8)]
9#[non_exhaustive]
10pub enum GrpcStatus {
11 Ok = 0,
12 Cancelled = 1,
13 Unknown = 2,
14 InvalidArgument = 3,
15 DeadlineExceeded = 4,
16 NotFound = 5,
17 AlreadyExists = 6,
18 PermissionDenied = 7,
19 ResourceExhausted = 8,
20 FailedPrecondition = 9,
21 Aborted = 10,
22 OutOfRange = 11,
23 Unimplemented = 12,
24 Internal = 13,
25 Unavailable = 14,
26 DataLoss = 15,
27 Unauthenticated = 16,
28}
29
30impl GrpcStatus {
31 pub fn from_u8(v: u8) -> Self {
33 match v {
34 0 => Self::Ok,
35 1 => Self::Cancelled,
36 2 => Self::Unknown,
37 3 => Self::InvalidArgument,
38 4 => Self::DeadlineExceeded,
39 5 => Self::NotFound,
40 6 => Self::AlreadyExists,
41 7 => Self::PermissionDenied,
42 8 => Self::ResourceExhausted,
43 9 => Self::FailedPrecondition,
44 10 => Self::Aborted,
45 11 => Self::OutOfRange,
46 12 => Self::Unimplemented,
47 13 => Self::Internal,
48 14 => Self::Unavailable,
49 15 => Self::DataLoss,
50 16 => Self::Unauthenticated,
51 _ => Self::Unknown,
52 }
53 }
54}
55
56impl std::fmt::Display for GrpcStatus {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 match self {
59 Self::Ok => write!(f, "OK"),
60 Self::Cancelled => write!(f, "CANCELLED"),
61 Self::Unknown => write!(f, "UNKNOWN"),
62 Self::InvalidArgument => write!(f, "INVALID_ARGUMENT"),
63 Self::DeadlineExceeded => write!(f, "DEADLINE_EXCEEDED"),
64 Self::NotFound => write!(f, "NOT_FOUND"),
65 Self::AlreadyExists => write!(f, "ALREADY_EXISTS"),
66 Self::PermissionDenied => write!(f, "PERMISSION_DENIED"),
67 Self::ResourceExhausted => write!(f, "RESOURCE_EXHAUSTED"),
68 Self::FailedPrecondition => write!(f, "FAILED_PRECONDITION"),
69 Self::Aborted => write!(f, "ABORTED"),
70 Self::OutOfRange => write!(f, "OUT_OF_RANGE"),
71 Self::Unimplemented => write!(f, "UNIMPLEMENTED"),
72 Self::Internal => write!(f, "INTERNAL"),
73 Self::Unavailable => write!(f, "UNAVAILABLE"),
74 Self::DataLoss => write!(f, "DATA_LOSS"),
75 Self::Unauthenticated => write!(f, "UNAUTHENTICATED"),
76 }
77 }
78}
79
80#[derive(Debug)]
84#[non_exhaustive]
85pub enum GrpcError {
86 H2(ringline_h2::H2Error),
88 InvalidMessage(String),
90 MaxSizeExceeded(String),
95 NotReady,
97}
98
99impl std::fmt::Display for GrpcError {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 match self {
102 Self::H2(e) => write!(f, "h2: {e}"),
103 Self::InvalidMessage(s) => write!(f, "invalid grpc message: {s}"),
104 Self::MaxSizeExceeded(s) => write!(f, "max size exceeded: {s}"),
105 Self::NotReady => write!(f, "connection not ready"),
106 }
107 }
108}
109
110impl std::error::Error for GrpcError {}
111
112impl From<ringline_h2::H2Error> for GrpcError {
113 fn from(e: ringline_h2::H2Error) -> Self {
114 Self::H2(e)
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn status_round_trip() {
124 for code in 0..=16u8 {
125 let status = GrpcStatus::from_u8(code);
126 assert_eq!(status as u8, code);
127 }
128 }
129
130 #[test]
131 fn unknown_status_code() {
132 assert_eq!(GrpcStatus::from_u8(99), GrpcStatus::Unknown);
133 assert_eq!(GrpcStatus::from_u8(255), GrpcStatus::Unknown);
134 }
135
136 #[test]
137 fn status_display() {
138 assert_eq!(GrpcStatus::Ok.to_string(), "OK");
139 assert_eq!(GrpcStatus::Internal.to_string(), "INTERNAL");
140 assert_eq!(GrpcStatus::Unauthenticated.to_string(), "UNAUTHENTICATED");
141 }
142
143 #[test]
144 fn error_display() {
145 let err = GrpcError::NotReady;
146 assert_eq!(err.to_string(), "connection not ready");
147
148 let err = GrpcError::InvalidMessage("bad prefix".into());
149 assert_eq!(err.to_string(), "invalid grpc message: bad prefix");
150 }
151}