/src/thrift/lib/rs/src/errors.rs
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | use std::convert::TryFrom; |
19 | | use std::convert::{From, Into}; |
20 | | use std::fmt::{Debug, Display, Formatter}; |
21 | | use std::{error, fmt, io, string}; |
22 | | |
23 | | use crate::protocol::{ |
24 | | TFieldIdentifier, TInputProtocol, TOutputProtocol, TStructIdentifier, TType, |
25 | | }; |
26 | | |
27 | | // FIXME: should all my error structs impl error::Error as well? |
28 | | // FIXME: should all fields in TransportError, ProtocolError and ApplicationError be optional? |
29 | | |
30 | | /// Error type returned by all runtime library functions. |
31 | | /// |
32 | | /// `thrift::Error` is used throughout this crate as well as in auto-generated |
33 | | /// Rust code. It consists of four variants defined by convention across Thrift |
34 | | /// implementations: |
35 | | /// |
36 | | /// 1. `Transport`: errors encountered while operating on I/O channels |
37 | | /// 2. `Protocol`: errors encountered during runtime-library processing |
38 | | /// 3. `Application`: errors encountered within auto-generated code |
39 | | /// 4. `User`: IDL-defined exception structs |
40 | | /// |
41 | | /// The `Application` variant also functions as a catch-all: all handler errors |
42 | | /// are automatically turned into application errors. |
43 | | /// |
44 | | /// All error variants except `Error::User` take an eponymous struct with two |
45 | | /// required fields: |
46 | | /// |
47 | | /// 1. `kind`: variant-specific enum identifying the error sub-type |
48 | | /// 2. `message`: human-readable error info string |
49 | | /// |
50 | | /// `kind` is defined by convention while `message` is freeform. If none of the |
51 | | /// enumerated kinds are suitable use `Unknown`. |
52 | | /// |
53 | | /// To simplify error creation convenience constructors are defined for all |
54 | | /// variants, and conversions from their structs (`thrift::TransportError`, |
55 | | /// `thrift::ProtocolError` and `thrift::ApplicationError` into `thrift::Error`. |
56 | | /// |
57 | | /// # Examples |
58 | | /// |
59 | | /// Create a `TransportError`. |
60 | | /// |
61 | | /// ``` |
62 | | /// use thrift::{TransportError, TransportErrorKind}; |
63 | | /// |
64 | | /// // explicit |
65 | | /// let err0: thrift::Result<()> = Err( |
66 | | /// thrift::Error::Transport( |
67 | | /// TransportError { |
68 | | /// kind: TransportErrorKind::TimedOut, |
69 | | /// message: format!("connection to server timed out") |
70 | | /// } |
71 | | /// ) |
72 | | /// ); |
73 | | /// |
74 | | /// // use conversion |
75 | | /// let err1: thrift::Result<()> = Err( |
76 | | /// thrift::Error::from( |
77 | | /// TransportError { |
78 | | /// kind: TransportErrorKind::TimedOut, |
79 | | /// message: format!("connection to server timed out") |
80 | | /// } |
81 | | /// ) |
82 | | /// ); |
83 | | /// |
84 | | /// // use struct constructor |
85 | | /// let err2: thrift::Result<()> = Err( |
86 | | /// thrift::Error::Transport( |
87 | | /// TransportError::new( |
88 | | /// TransportErrorKind::TimedOut, |
89 | | /// "connection to server timed out" |
90 | | /// ) |
91 | | /// ) |
92 | | /// ); |
93 | | /// |
94 | | /// |
95 | | /// // use error variant constructor |
96 | | /// let err3: thrift::Result<()> = Err( |
97 | | /// thrift::new_transport_error( |
98 | | /// TransportErrorKind::TimedOut, |
99 | | /// "connection to server timed out" |
100 | | /// ) |
101 | | /// ); |
102 | | /// ``` |
103 | | /// |
104 | | /// Create an error from a string. |
105 | | /// |
106 | | /// ``` |
107 | | /// use thrift::{ApplicationError, ApplicationErrorKind}; |
108 | | /// |
109 | | /// // we just use `From::from` to convert a `String` into a `thrift::Error` |
110 | | /// let err0: thrift::Result<()> = Err( |
111 | | /// thrift::Error::from("This is an error") |
112 | | /// ); |
113 | | /// |
114 | | /// // err0 is equivalent to... |
115 | | /// let err1: thrift::Result<()> = Err( |
116 | | /// thrift::Error::Application( |
117 | | /// ApplicationError { |
118 | | /// kind: ApplicationErrorKind::Unknown, |
119 | | /// message: format!("This is an error") |
120 | | /// } |
121 | | /// ) |
122 | | /// ); |
123 | | /// ``` |
124 | | /// |
125 | | /// Return an IDL-defined exception. |
126 | | /// |
127 | | /// ```text |
128 | | /// // Thrift IDL exception definition. |
129 | | /// exception Xception { |
130 | | /// 1: i32 errorCode, |
131 | | /// 2: string message |
132 | | /// } |
133 | | /// ``` |
134 | | /// |
135 | | /// ``` |
136 | | /// use std::error::Error; |
137 | | /// use std::fmt; |
138 | | /// use std::fmt::{Display, Formatter}; |
139 | | /// |
140 | | /// // auto-generated by the Thrift compiler |
141 | | /// #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] |
142 | | /// pub struct Xception { |
143 | | /// pub error_code: Option<i32>, |
144 | | /// pub message: Option<String>, |
145 | | /// } |
146 | | /// |
147 | | /// // auto-generated by the Thrift compiler |
148 | | /// impl Error for Xception { } |
149 | | /// |
150 | | /// // auto-generated by the Thrift compiler |
151 | | /// impl From<Xception> for thrift::Error { |
152 | | /// fn from(e: Xception) -> Self { |
153 | | /// thrift::Error::User(Box::new(e)) |
154 | | /// } |
155 | | /// } |
156 | | /// |
157 | | /// // auto-generated by the Thrift compiler |
158 | | /// impl Display for Xception { |
159 | | /// fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
160 | | /// write!(f, "remote service threw Xception") |
161 | | /// } |
162 | | /// } |
163 | | /// |
164 | | /// // in user code... |
165 | | /// let err: thrift::Result<()> = Err( |
166 | | /// thrift::Error::from(Xception { error_code: Some(1), message: None }) |
167 | | /// ); |
168 | | /// ``` |
169 | | pub enum Error { |
170 | | /// Errors encountered while operating on I/O channels. |
171 | | /// |
172 | | /// These include *connection closed* and *bind failure*. |
173 | | Transport(TransportError), |
174 | | /// Errors encountered during runtime-library processing. |
175 | | /// |
176 | | /// These include *message too large* and *unsupported protocol version*. |
177 | | Protocol(ProtocolError), |
178 | | /// Errors encountered within auto-generated code, or when incoming |
179 | | /// or outgoing messages violate the Thrift spec. |
180 | | /// |
181 | | /// These include *out-of-order messages* and *missing required struct |
182 | | /// fields*. |
183 | | /// |
184 | | /// This variant also functions as a catch-all: errors from handler |
185 | | /// functions are automatically returned as an `ApplicationError`. |
186 | | Application(ApplicationError), |
187 | | /// IDL-defined exception structs. |
188 | | User(Box<dyn error::Error + Sync + Send>), |
189 | | } |
190 | | |
191 | | impl Error { |
192 | | /// Create an `ApplicationError` from its wire representation. |
193 | | /// |
194 | | /// Application code **should never** call this method directly. |
195 | 0 | pub fn read_application_error_from_in_protocol( |
196 | 0 | i: &mut dyn TInputProtocol, |
197 | 0 | ) -> crate::Result<ApplicationError> { |
198 | 0 | let mut message = "general remote error".to_owned(); |
199 | 0 | let mut kind = ApplicationErrorKind::Unknown; |
200 | | |
201 | 0 | i.read_struct_begin()?; |
202 | | |
203 | | loop { |
204 | 0 | let field_ident = i.read_field_begin()?; |
205 | | |
206 | 0 | if field_ident.field_type == TType::Stop { |
207 | 0 | break; |
208 | 0 | } |
209 | | |
210 | 0 | let id = field_ident |
211 | 0 | .id |
212 | 0 | .expect("sender should always specify id for non-STOP field"); |
213 | | |
214 | 0 | match id { |
215 | | 1 => { |
216 | 0 | let remote_message = i.read_string()?; |
217 | 0 | i.read_field_end()?; |
218 | 0 | message = remote_message; |
219 | | } |
220 | | 2 => { |
221 | 0 | let remote_type_as_int = i.read_i32()?; |
222 | 0 | let remote_kind: ApplicationErrorKind = TryFrom::try_from(remote_type_as_int) |
223 | 0 | .unwrap_or(ApplicationErrorKind::Unknown); |
224 | 0 | i.read_field_end()?; |
225 | 0 | kind = remote_kind; |
226 | | } |
227 | | _ => { |
228 | 0 | i.skip(field_ident.field_type)?; |
229 | | } |
230 | | } |
231 | | } |
232 | | |
233 | 0 | i.read_struct_end()?; |
234 | | |
235 | 0 | Ok(ApplicationError { kind, message }) |
236 | 0 | } |
237 | | |
238 | | /// Convert an `ApplicationError` into its wire representation and write |
239 | | /// it to the remote. |
240 | | /// |
241 | | /// Application code **should never** call this method directly. |
242 | 0 | pub fn write_application_error_to_out_protocol( |
243 | 0 | e: &ApplicationError, |
244 | 0 | o: &mut dyn TOutputProtocol, |
245 | 0 | ) -> crate::Result<()> { |
246 | 0 | o.write_struct_begin(&TStructIdentifier { |
247 | 0 | name: "TApplicationException".to_owned(), |
248 | 0 | })?; |
249 | | |
250 | 0 | let message_field = TFieldIdentifier::new("message", TType::String, 1); |
251 | 0 | let type_field = TFieldIdentifier::new("type", TType::I32, 2); |
252 | | |
253 | 0 | o.write_field_begin(&message_field)?; |
254 | 0 | o.write_string(&e.message)?; |
255 | 0 | o.write_field_end()?; |
256 | | |
257 | 0 | o.write_field_begin(&type_field)?; |
258 | 0 | o.write_i32(e.kind as i32)?; |
259 | 0 | o.write_field_end()?; |
260 | | |
261 | 0 | o.write_field_stop()?; |
262 | 0 | o.write_struct_end()?; |
263 | | |
264 | 0 | o.flush() |
265 | 0 | } |
266 | | } |
267 | | |
268 | | impl error::Error for Error {} |
269 | | |
270 | | impl Debug for Error { |
271 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
272 | 0 | match *self { |
273 | 0 | Error::Transport(ref e) => Debug::fmt(e, f), |
274 | 0 | Error::Protocol(ref e) => Debug::fmt(e, f), |
275 | 0 | Error::Application(ref e) => Debug::fmt(e, f), |
276 | 0 | Error::User(ref e) => Debug::fmt(e, f), |
277 | | } |
278 | 0 | } |
279 | | } |
280 | | |
281 | | impl Display for Error { |
282 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
283 | 0 | match *self { |
284 | 0 | Error::Transport(ref e) => Display::fmt(e, f), |
285 | 0 | Error::Protocol(ref e) => Display::fmt(e, f), |
286 | 0 | Error::Application(ref e) => Display::fmt(e, f), |
287 | 0 | Error::User(ref e) => Display::fmt(e, f), |
288 | | } |
289 | 0 | } |
290 | | } |
291 | | |
292 | | impl From<String> for Error { |
293 | 0 | fn from(s: String) -> Self { |
294 | 0 | Error::Application(ApplicationError { |
295 | 0 | kind: ApplicationErrorKind::Unknown, |
296 | 0 | message: s, |
297 | 0 | }) |
298 | 0 | } |
299 | | } |
300 | | |
301 | | impl<'a> From<&'a str> for Error { |
302 | 0 | fn from(s: &'a str) -> Self { |
303 | 0 | Error::Application(ApplicationError { |
304 | 0 | kind: ApplicationErrorKind::Unknown, |
305 | 0 | message: String::from(s), |
306 | 0 | }) |
307 | 0 | } |
308 | | } |
309 | | |
310 | | impl From<TransportError> for Error { |
311 | 0 | fn from(e: TransportError) -> Self { |
312 | 0 | Error::Transport(e) |
313 | 0 | } |
314 | | } |
315 | | |
316 | | impl From<ProtocolError> for Error { |
317 | 0 | fn from(e: ProtocolError) -> Self { |
318 | 0 | Error::Protocol(e) |
319 | 0 | } |
320 | | } |
321 | | |
322 | | impl From<ApplicationError> for Error { |
323 | 0 | fn from(e: ApplicationError) -> Self { |
324 | 0 | Error::Application(e) |
325 | 0 | } |
326 | | } |
327 | | |
328 | | /// Create a new `Error` instance of type `Transport` that wraps a |
329 | | /// `TransportError`. |
330 | 0 | pub fn new_transport_error<S: Into<String>>(kind: TransportErrorKind, message: S) -> Error { |
331 | 0 | Error::Transport(TransportError::new(kind, message)) |
332 | 0 | } |
333 | | |
334 | | /// Information about I/O errors. |
335 | | #[derive(Debug, Eq, PartialEq)] |
336 | | pub struct TransportError { |
337 | | /// I/O error variant. |
338 | | /// |
339 | | /// If a specific `TransportErrorKind` does not apply use |
340 | | /// `TransportErrorKind::Unknown`. |
341 | | pub kind: TransportErrorKind, |
342 | | /// Human-readable error message. |
343 | | pub message: String, |
344 | | } |
345 | | |
346 | | impl TransportError { |
347 | | /// Create a new `TransportError`. |
348 | 0 | pub fn new<S: Into<String>>(kind: TransportErrorKind, message: S) -> TransportError { |
349 | 0 | TransportError { |
350 | 0 | kind, |
351 | 0 | message: message.into(), |
352 | 0 | } |
353 | 0 | } |
354 | | } |
355 | | |
356 | | /// I/O error categories. |
357 | | /// |
358 | | /// This list may grow, and it is not recommended to match against it. |
359 | | #[non_exhaustive] |
360 | | #[derive(Clone, Copy, Eq, Debug, PartialEq)] |
361 | | pub enum TransportErrorKind { |
362 | | /// Catch-all I/O error. |
363 | | Unknown = 0, |
364 | | /// An I/O operation was attempted when the transport channel was not open. |
365 | | NotOpen = 1, |
366 | | /// The transport channel cannot be opened because it was opened previously. |
367 | | AlreadyOpen = 2, |
368 | | /// An I/O operation timed out. |
369 | | TimedOut = 3, |
370 | | /// A read could not complete because no bytes were available. |
371 | | EndOfFile = 4, |
372 | | /// An invalid (buffer/message) size was requested or received. |
373 | | NegativeSize = 5, |
374 | | /// Too large a buffer or message size was requested or received. |
375 | | SizeLimit = 6, |
376 | | } |
377 | | |
378 | | impl Display for TransportError { |
379 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
380 | 0 | let error_text = match self.kind { |
381 | 0 | TransportErrorKind::Unknown => "transport error", |
382 | 0 | TransportErrorKind::NotOpen => "not open", |
383 | 0 | TransportErrorKind::AlreadyOpen => "already open", |
384 | 0 | TransportErrorKind::TimedOut => "timed out", |
385 | 0 | TransportErrorKind::EndOfFile => "end of file", |
386 | 0 | TransportErrorKind::NegativeSize => "negative size message", |
387 | 0 | TransportErrorKind::SizeLimit => "message too long", |
388 | | }; |
389 | | |
390 | 0 | write!(f, "{}", error_text) |
391 | 0 | } |
392 | | } |
393 | | |
394 | | impl TryFrom<i32> for TransportErrorKind { |
395 | | type Error = Error; |
396 | 0 | fn try_from(from: i32) -> Result<Self, Self::Error> { |
397 | 0 | match from { |
398 | 0 | 0 => Ok(TransportErrorKind::Unknown), |
399 | 0 | 1 => Ok(TransportErrorKind::NotOpen), |
400 | 0 | 2 => Ok(TransportErrorKind::AlreadyOpen), |
401 | 0 | 3 => Ok(TransportErrorKind::TimedOut), |
402 | 0 | 4 => Ok(TransportErrorKind::EndOfFile), |
403 | 0 | 5 => Ok(TransportErrorKind::NegativeSize), |
404 | 0 | 6 => Ok(TransportErrorKind::SizeLimit), |
405 | 0 | _ => Err(Error::Protocol(ProtocolError { |
406 | 0 | kind: ProtocolErrorKind::Unknown, |
407 | 0 | message: format!("cannot convert {} to TransportErrorKind", from), |
408 | 0 | })), |
409 | | } |
410 | 0 | } |
411 | | } |
412 | | |
413 | | impl From<io::Error> for Error { |
414 | 6.95k | fn from(err: io::Error) -> Self { |
415 | 6.95k | match err.kind() { |
416 | | io::ErrorKind::ConnectionReset |
417 | | | io::ErrorKind::ConnectionRefused |
418 | 0 | | io::ErrorKind::NotConnected => Error::Transport(TransportError { |
419 | 0 | kind: TransportErrorKind::NotOpen, |
420 | 0 | message: err.to_string(), |
421 | 0 | }), |
422 | 0 | io::ErrorKind::AlreadyExists => Error::Transport(TransportError { |
423 | 0 | kind: TransportErrorKind::AlreadyOpen, |
424 | 0 | message: err.to_string(), |
425 | 0 | }), |
426 | 0 | io::ErrorKind::TimedOut => Error::Transport(TransportError { |
427 | 0 | kind: TransportErrorKind::TimedOut, |
428 | 0 | message: err.to_string(), |
429 | 0 | }), |
430 | 5.50k | io::ErrorKind::UnexpectedEof => Error::Transport(TransportError { |
431 | 5.50k | kind: TransportErrorKind::EndOfFile, |
432 | 5.50k | message: err.to_string(), |
433 | 5.50k | }), |
434 | | _ => { |
435 | 1.45k | Error::Transport(TransportError { |
436 | 1.45k | kind: TransportErrorKind::Unknown, |
437 | 1.45k | message: err.to_string(), // FIXME: use io error's debug string |
438 | 1.45k | }) |
439 | | } |
440 | | } |
441 | 6.95k | } |
442 | | } |
443 | | |
444 | | impl From<uuid::Error> for Error { |
445 | 0 | fn from(err: uuid::Error) -> Self { |
446 | 0 | Error::Protocol(ProtocolError { |
447 | 0 | kind: ProtocolErrorKind::InvalidData, |
448 | 0 | message: err.to_string(), // FIXME: use fmt::Error's debug string |
449 | 0 | }) |
450 | 0 | } |
451 | | } |
452 | | |
453 | | impl From<string::FromUtf8Error> for Error { |
454 | 711 | fn from(err: string::FromUtf8Error) -> Self { |
455 | 711 | Error::Protocol(ProtocolError { |
456 | 711 | kind: ProtocolErrorKind::InvalidData, |
457 | 711 | message: err.to_string(), // FIXME: use fmt::Error's debug string |
458 | 711 | }) |
459 | 711 | } |
460 | | } |
461 | | |
462 | | /// Create a new `Error` instance of type `Protocol` that wraps a |
463 | | /// `ProtocolError`. |
464 | 0 | pub fn new_protocol_error<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> Error { |
465 | 0 | Error::Protocol(ProtocolError::new(kind, message)) |
466 | 0 | } |
467 | | |
468 | | /// Information about errors that occur in the runtime library. |
469 | | #[derive(Debug, Eq, PartialEq)] |
470 | | pub struct ProtocolError { |
471 | | /// Protocol error variant. |
472 | | /// |
473 | | /// If a specific `ProtocolErrorKind` does not apply use |
474 | | /// `ProtocolErrorKind::Unknown`. |
475 | | pub kind: ProtocolErrorKind, |
476 | | /// Human-readable error message. |
477 | | pub message: String, |
478 | | } |
479 | | |
480 | | impl ProtocolError { |
481 | | /// Create a new `ProtocolError`. |
482 | 1.83k | pub fn new<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> ProtocolError { |
483 | 1.83k | ProtocolError { |
484 | 1.83k | kind, |
485 | 1.83k | message: message.into(), |
486 | 1.83k | } |
487 | 1.83k | } <thrift::errors::ProtocolError>::new::<alloc::string::String> Line | Count | Source | 482 | 1.46k | pub fn new<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> ProtocolError { | 483 | 1.46k | ProtocolError { | 484 | 1.46k | kind, | 485 | 1.46k | message: message.into(), | 486 | 1.46k | } | 487 | 1.46k | } |
<thrift::errors::ProtocolError>::new::<&str> Line | Count | Source | 482 | 376 | pub fn new<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> ProtocolError { | 483 | 376 | ProtocolError { | 484 | 376 | kind, | 485 | 376 | message: message.into(), | 486 | 376 | } | 487 | 376 | } |
|
488 | | } |
489 | | |
490 | | /// Runtime library error categories. |
491 | | /// |
492 | | /// This list may grow, and it is not recommended to match against it. |
493 | | #[non_exhaustive] |
494 | | #[derive(Clone, Copy, Eq, Debug, PartialEq)] |
495 | | pub enum ProtocolErrorKind { |
496 | | /// Catch-all runtime-library error. |
497 | | Unknown = 0, |
498 | | /// An invalid argument was supplied to a library function, or invalid data |
499 | | /// was received from a Thrift endpoint. |
500 | | InvalidData = 1, |
501 | | /// An invalid size was received in an encoded field. |
502 | | NegativeSize = 2, |
503 | | /// Thrift message or field was too long. |
504 | | SizeLimit = 3, |
505 | | /// Unsupported or unknown Thrift protocol version. |
506 | | BadVersion = 4, |
507 | | /// Unsupported Thrift protocol, server or field type. |
508 | | NotImplemented = 5, |
509 | | /// Reached the maximum nested depth to which an encoded Thrift field could |
510 | | /// be skipped. |
511 | | DepthLimit = 6, |
512 | | } |
513 | | |
514 | | impl Display for ProtocolError { |
515 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
516 | 0 | let error_text = match self.kind { |
517 | 0 | ProtocolErrorKind::Unknown => "protocol error", |
518 | 0 | ProtocolErrorKind::InvalidData => "bad data", |
519 | 0 | ProtocolErrorKind::NegativeSize => "negative message size", |
520 | 0 | ProtocolErrorKind::SizeLimit => "message too long", |
521 | 0 | ProtocolErrorKind::BadVersion => "invalid thrift version", |
522 | 0 | ProtocolErrorKind::NotImplemented => "not implemented", |
523 | 0 | ProtocolErrorKind::DepthLimit => "maximum skip depth reached", |
524 | | }; |
525 | | |
526 | 0 | write!(f, "{}", error_text) |
527 | 0 | } |
528 | | } |
529 | | |
530 | | impl TryFrom<i32> for ProtocolErrorKind { |
531 | | type Error = Error; |
532 | 0 | fn try_from(from: i32) -> Result<Self, Self::Error> { |
533 | 0 | match from { |
534 | 0 | 0 => Ok(ProtocolErrorKind::Unknown), |
535 | 0 | 1 => Ok(ProtocolErrorKind::InvalidData), |
536 | 0 | 2 => Ok(ProtocolErrorKind::NegativeSize), |
537 | 0 | 3 => Ok(ProtocolErrorKind::SizeLimit), |
538 | 0 | 4 => Ok(ProtocolErrorKind::BadVersion), |
539 | 0 | 5 => Ok(ProtocolErrorKind::NotImplemented), |
540 | 0 | 6 => Ok(ProtocolErrorKind::DepthLimit), |
541 | 0 | _ => Err(Error::Protocol(ProtocolError { |
542 | 0 | kind: ProtocolErrorKind::Unknown, |
543 | 0 | message: format!("cannot convert {} to ProtocolErrorKind", from), |
544 | 0 | })), |
545 | | } |
546 | 0 | } |
547 | | } |
548 | | |
549 | | /// Create a new `Error` instance of type `Application` that wraps an |
550 | | /// `ApplicationError`. |
551 | | pub fn new_application_error<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> Error { |
552 | | Error::Application(ApplicationError::new(kind, message)) |
553 | | } |
554 | | |
555 | | /// Information about errors in auto-generated code or in user-implemented |
556 | | /// service handlers. |
557 | | #[derive(Debug, Eq, PartialEq)] |
558 | | pub struct ApplicationError { |
559 | | /// Application error variant. |
560 | | /// |
561 | | /// If a specific `ApplicationErrorKind` does not apply use |
562 | | /// `ApplicationErrorKind::Unknown`. |
563 | | pub kind: ApplicationErrorKind, |
564 | | /// Human-readable error message. |
565 | | pub message: String, |
566 | | } |
567 | | |
568 | | impl ApplicationError { |
569 | | /// Create a new `ApplicationError`. |
570 | 0 | pub fn new<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> ApplicationError { |
571 | 0 | ApplicationError { |
572 | 0 | kind, |
573 | 0 | message: message.into(), |
574 | 0 | } |
575 | 0 | } |
576 | | } |
577 | | |
578 | | /// Auto-generated or user-implemented code error categories. |
579 | | /// |
580 | | /// This list may grow, and it is not recommended to match against it. |
581 | | #[non_exhaustive] |
582 | | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
583 | | pub enum ApplicationErrorKind { |
584 | | /// Catch-all application error. |
585 | | Unknown = 0, |
586 | | /// Made service call to an unknown service method. |
587 | | UnknownMethod = 1, |
588 | | /// Received an unknown Thrift message type. That is, not one of the |
589 | | /// `thrift::protocol::TMessageType` variants. |
590 | | InvalidMessageType = 2, |
591 | | /// Method name in a service reply does not match the name of the |
592 | | /// receiving service method. |
593 | | WrongMethodName = 3, |
594 | | /// Received an out-of-order Thrift message. |
595 | | BadSequenceId = 4, |
596 | | /// Service reply is missing required fields. |
597 | | MissingResult = 5, |
598 | | /// Auto-generated code failed unexpectedly. |
599 | | InternalError = 6, |
600 | | /// Thrift protocol error. When possible use `Error::ProtocolError` with a |
601 | | /// specific `ProtocolErrorKind` instead. |
602 | | ProtocolError = 7, |
603 | | /// *Unknown*. Included only for compatibility with existing Thrift implementations. |
604 | | InvalidTransform = 8, // ?? |
605 | | /// Thrift endpoint requested, or is using, an unsupported encoding. |
606 | | InvalidProtocol = 9, // ?? |
607 | | /// Thrift endpoint requested, or is using, an unsupported auto-generated client type. |
608 | | UnsupportedClientType = 10, // ?? |
609 | | } |
610 | | |
611 | | impl Display for ApplicationError { |
612 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
613 | 0 | let error_text = match self.kind { |
614 | 0 | ApplicationErrorKind::Unknown => "service error", |
615 | 0 | ApplicationErrorKind::UnknownMethod => "unknown service method", |
616 | 0 | ApplicationErrorKind::InvalidMessageType => "wrong message type received", |
617 | 0 | ApplicationErrorKind::WrongMethodName => "unknown method reply received", |
618 | 0 | ApplicationErrorKind::BadSequenceId => "out of order sequence id", |
619 | 0 | ApplicationErrorKind::MissingResult => "missing method result", |
620 | 0 | ApplicationErrorKind::InternalError => "remote service threw exception", |
621 | 0 | ApplicationErrorKind::ProtocolError => "protocol error", |
622 | 0 | ApplicationErrorKind::InvalidTransform => "invalid transform", |
623 | 0 | ApplicationErrorKind::InvalidProtocol => "invalid protocol requested", |
624 | 0 | ApplicationErrorKind::UnsupportedClientType => "unsupported protocol client", |
625 | | }; |
626 | | |
627 | 0 | write!(f, "{}", error_text) |
628 | 0 | } |
629 | | } |
630 | | |
631 | | impl TryFrom<i32> for ApplicationErrorKind { |
632 | | type Error = Error; |
633 | 0 | fn try_from(from: i32) -> Result<Self, Self::Error> { |
634 | 0 | match from { |
635 | 0 | 0 => Ok(ApplicationErrorKind::Unknown), |
636 | 0 | 1 => Ok(ApplicationErrorKind::UnknownMethod), |
637 | 0 | 2 => Ok(ApplicationErrorKind::InvalidMessageType), |
638 | 0 | 3 => Ok(ApplicationErrorKind::WrongMethodName), |
639 | 0 | 4 => Ok(ApplicationErrorKind::BadSequenceId), |
640 | 0 | 5 => Ok(ApplicationErrorKind::MissingResult), |
641 | 0 | 6 => Ok(ApplicationErrorKind::InternalError), |
642 | 0 | 7 => Ok(ApplicationErrorKind::ProtocolError), |
643 | 0 | 8 => Ok(ApplicationErrorKind::InvalidTransform), |
644 | 0 | 9 => Ok(ApplicationErrorKind::InvalidProtocol), |
645 | 0 | 10 => Ok(ApplicationErrorKind::UnsupportedClientType), |
646 | 0 | _ => Err(Error::Application(ApplicationError { |
647 | 0 | kind: ApplicationErrorKind::Unknown, |
648 | 0 | message: format!("cannot convert {} to ApplicationErrorKind", from), |
649 | 0 | })), |
650 | | } |
651 | 0 | } |
652 | | } |