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