blob: fc263309d41381e7eb1ff8b0639419e41a4a05a9 [file] [log] [blame]
Allen George8b96bfb2016-11-02 08:01:08 -04001// 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
Allen George55c3e4c2021-03-01 23:19:52 -050018use std::convert::TryFrom;
Allen George8b96bfb2016-11-02 08:01:08 -040019use std::convert::{From, Into};
Allen George8b96bfb2016-11-02 08:01:08 -040020use std::fmt::{Debug, Display, Formatter};
21use std::{error, fmt, io, string};
Allen George8b96bfb2016-11-02 08:01:08 -040022
Allen George55c3e4c2021-03-01 23:19:52 -050023use crate::protocol::{
24 TFieldIdentifier, TInputProtocol, TOutputProtocol, TStructIdentifier, TType,
25};
Allen George8b96bfb2016-11-02 08:01:08 -040026
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/// ```
Allen George8b96bfb2016-11-02 08:01:08 -040062/// 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/// ```
Allen George8b96bfb2016-11-02 08:01:08 -0400107/// 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/// ```
Allen George8b96bfb2016-11-02 08:01:08 -0400136/// 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
Allen Georgea1942762021-03-06 17:39:02 -0500148/// impl Error for Xception { }
Allen George8b96bfb2016-11-02 08:01:08 -0400149///
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 {
Allen Georgea1942762021-03-06 17:39:02 -0500160/// write!(f, "remote service threw Xception")
Allen George8b96bfb2016-11-02 08:01:08 -0400161/// }
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/// ```
169pub 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.
Danny Browning77d96c12019-08-21 13:41:07 -0600188 User(Box<dyn error::Error + Sync + Send>),
Allen George8b96bfb2016-11-02 08:01:08 -0400189}
190
191impl Error {
192 /// Create an `ApplicationError` from its wire representation.
193 ///
194 /// Application code **should never** call this method directly.
Allen Georgeef7a1892018-12-16 18:01:37 -0500195 pub fn read_application_error_from_in_protocol(
Danny Browning77d96c12019-08-21 13:41:07 -0600196 i: &mut dyn TInputProtocol,
Allen Georgeb0d14132020-03-29 11:48:55 -0400197 ) -> crate::Result<ApplicationError> {
Allen George8b96bfb2016-11-02 08:01:08 -0400198 let mut message = "general remote error".to_owned();
199 let mut kind = ApplicationErrorKind::Unknown;
200
201 i.read_struct_begin()?;
202
203 loop {
204 let field_ident = i.read_field_begin()?;
205
206 if field_ident.field_type == TType::Stop {
207 break;
208 }
209
Allen George0e22c362017-01-30 07:15:00 -0500210 let id = field_ident
211 .id
212 .expect("sender should always specify id for non-STOP field");
Allen George8b96bfb2016-11-02 08:01:08 -0400213
214 match id {
215 1 => {
216 let remote_message = i.read_string()?;
217 i.read_field_end()?;
218 message = remote_message;
219 }
220 2 => {
221 let remote_type_as_int = i.read_i32()?;
Allen Georgeef7a1892018-12-16 18:01:37 -0500222 let remote_kind: ApplicationErrorKind = TryFrom::try_from(remote_type_as_int)
223 .unwrap_or(ApplicationErrorKind::Unknown);
Allen George8b96bfb2016-11-02 08:01:08 -0400224 i.read_field_end()?;
225 kind = remote_kind;
226 }
227 _ => {
228 i.skip(field_ident.field_type)?;
229 }
230 }
231 }
232
233 i.read_struct_end()?;
234
Allen George55c3e4c2021-03-01 23:19:52 -0500235 Ok(ApplicationError { kind, message })
Allen George8b96bfb2016-11-02 08:01:08 -0400236 }
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.
Allen George0e22c362017-01-30 07:15:00 -0500242 pub fn write_application_error_to_out_protocol(
243 e: &ApplicationError,
Danny Browning77d96c12019-08-21 13:41:07 -0600244 o: &mut dyn TOutputProtocol,
Allen Georgeb0d14132020-03-29 11:48:55 -0400245 ) -> crate::Result<()> {
Allen Georgeef7a1892018-12-16 18:01:37 -0500246 o.write_struct_begin(&TStructIdentifier {
247 name: "TApplicationException".to_owned(),
248 })?;
Allen George8b96bfb2016-11-02 08:01:08 -0400249
250 let message_field = TFieldIdentifier::new("message", TType::String, 1);
251 let type_field = TFieldIdentifier::new("type", TType::I32, 2);
252
253 o.write_field_begin(&message_field)?;
254 o.write_string(&e.message)?;
255 o.write_field_end()?;
256
257 o.write_field_begin(&type_field)?;
258 o.write_i32(e.kind as i32)?;
259 o.write_field_end()?;
260
261 o.write_field_stop()?;
262 o.write_struct_end()?;
263
264 o.flush()
265 }
266}
267
Allen Georgea1942762021-03-06 17:39:02 -0500268impl error::Error for Error {}
Allen George8b96bfb2016-11-02 08:01:08 -0400269
270impl Debug for Error {
Allen George7ddbcc02020-11-08 09:51:19 -0500271 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Allen George8b96bfb2016-11-02 08:01:08 -0400272 match *self {
273 Error::Transport(ref e) => Debug::fmt(e, f),
274 Error::Protocol(ref e) => Debug::fmt(e, f),
275 Error::Application(ref e) => Debug::fmt(e, f),
276 Error::User(ref e) => Debug::fmt(e, f),
277 }
278 }
279}
280
281impl Display for Error {
Allen George7ddbcc02020-11-08 09:51:19 -0500282 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Allen George8b96bfb2016-11-02 08:01:08 -0400283 match *self {
284 Error::Transport(ref e) => Display::fmt(e, f),
285 Error::Protocol(ref e) => Display::fmt(e, f),
286 Error::Application(ref e) => Display::fmt(e, f),
287 Error::User(ref e) => Display::fmt(e, f),
288 }
289 }
290}
291
292impl From<String> for Error {
293 fn from(s: String) -> Self {
Allen Georgeef7a1892018-12-16 18:01:37 -0500294 Error::Application(ApplicationError {
295 kind: ApplicationErrorKind::Unknown,
296 message: s,
297 })
Allen George8b96bfb2016-11-02 08:01:08 -0400298 }
299}
300
301impl<'a> From<&'a str> for Error {
302 fn from(s: &'a str) -> Self {
Allen Georgeef7a1892018-12-16 18:01:37 -0500303 Error::Application(ApplicationError {
304 kind: ApplicationErrorKind::Unknown,
305 message: String::from(s),
306 })
Allen George8b96bfb2016-11-02 08:01:08 -0400307 }
308}
309
310impl From<TransportError> for Error {
311 fn from(e: TransportError) -> Self {
312 Error::Transport(e)
313 }
314}
315
316impl From<ProtocolError> for Error {
317 fn from(e: ProtocolError) -> Self {
318 Error::Protocol(e)
319 }
320}
321
322impl From<ApplicationError> for Error {
323 fn from(e: ApplicationError) -> Self {
324 Error::Application(e)
325 }
326}
327
328/// Create a new `Error` instance of type `Transport` that wraps a
329/// `TransportError`.
330pub fn new_transport_error<S: Into<String>>(kind: TransportErrorKind, message: S) -> Error {
331 Error::Transport(TransportError::new(kind, message))
332}
333
334/// Information about I/O errors.
Allen Georgebc1344d2017-04-28 10:22:03 -0400335#[derive(Debug, Eq, PartialEq)]
Allen George8b96bfb2016-11-02 08:01:08 -0400336pub 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
346impl TransportError {
347 /// Create a new `TransportError`.
348 pub fn new<S: Into<String>>(kind: TransportErrorKind, message: S) -> TransportError {
349 TransportError {
Allen George7ddbcc02020-11-08 09:51:19 -0500350 kind,
Allen George8b96bfb2016-11-02 08:01:08 -0400351 message: message.into(),
352 }
353 }
354}
355
356/// I/O error categories.
357///
358/// This list may grow, and it is not recommended to match against it.
Allen Georgea1942762021-03-06 17:39:02 -0500359#[non_exhaustive]
Allen George8b96bfb2016-11-02 08:01:08 -0400360#[derive(Clone, Copy, Eq, Debug, PartialEq)]
361pub 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
Allen Georgea1942762021-03-06 17:39:02 -0500378impl Display for TransportError {
379 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
380 let error_text = match self.kind {
Allen George8b96bfb2016-11-02 08:01:08 -0400381 TransportErrorKind::Unknown => "transport error",
382 TransportErrorKind::NotOpen => "not open",
383 TransportErrorKind::AlreadyOpen => "already open",
384 TransportErrorKind::TimedOut => "timed out",
385 TransportErrorKind::EndOfFile => "end of file",
386 TransportErrorKind::NegativeSize => "negative size message",
387 TransportErrorKind::SizeLimit => "message too long",
Allen Georgea1942762021-03-06 17:39:02 -0500388 };
Allen George8b96bfb2016-11-02 08:01:08 -0400389
Allen Georgea1942762021-03-06 17:39:02 -0500390 write!(f, "{}", error_text)
Allen George8b96bfb2016-11-02 08:01:08 -0400391 }
392}
393
394impl TryFrom<i32> for TransportErrorKind {
Danny Browningddec4312019-03-08 14:20:41 -0700395 type Error = Error;
396 fn try_from(from: i32) -> Result<Self, Self::Error> {
Allen George8b96bfb2016-11-02 08:01:08 -0400397 match from {
398 0 => Ok(TransportErrorKind::Unknown),
399 1 => Ok(TransportErrorKind::NotOpen),
400 2 => Ok(TransportErrorKind::AlreadyOpen),
401 3 => Ok(TransportErrorKind::TimedOut),
402 4 => Ok(TransportErrorKind::EndOfFile),
403 5 => Ok(TransportErrorKind::NegativeSize),
404 6 => Ok(TransportErrorKind::SizeLimit),
Allen Georgeef7a1892018-12-16 18:01:37 -0500405 _ => Err(Error::Protocol(ProtocolError {
406 kind: ProtocolErrorKind::Unknown,
407 message: format!("cannot convert {} to TransportErrorKind", from),
408 })),
Allen George8b96bfb2016-11-02 08:01:08 -0400409 }
410 }
411}
412
413impl From<io::Error> for Error {
414 fn from(err: io::Error) -> Self {
415 match err.kind() {
Allen Georgeef7a1892018-12-16 18:01:37 -0500416 io::ErrorKind::ConnectionReset
417 | io::ErrorKind::ConnectionRefused
418 | io::ErrorKind::NotConnected => Error::Transport(TransportError {
419 kind: TransportErrorKind::NotOpen,
Allen Georgea1942762021-03-06 17:39:02 -0500420 message: err.to_string(),
Allen Georgeef7a1892018-12-16 18:01:37 -0500421 }),
422 io::ErrorKind::AlreadyExists => Error::Transport(TransportError {
423 kind: TransportErrorKind::AlreadyOpen,
Allen Georgea1942762021-03-06 17:39:02 -0500424 message: err.to_string(),
Allen Georgeef7a1892018-12-16 18:01:37 -0500425 }),
426 io::ErrorKind::TimedOut => Error::Transport(TransportError {
427 kind: TransportErrorKind::TimedOut,
Allen Georgea1942762021-03-06 17:39:02 -0500428 message: err.to_string(),
Allen Georgeef7a1892018-12-16 18:01:37 -0500429 }),
430 io::ErrorKind::UnexpectedEof => Error::Transport(TransportError {
431 kind: TransportErrorKind::EndOfFile,
Allen Georgea1942762021-03-06 17:39:02 -0500432 message: err.to_string(),
Allen Georgeef7a1892018-12-16 18:01:37 -0500433 }),
Allen George8b96bfb2016-11-02 08:01:08 -0400434 _ => {
Allen Georgeef7a1892018-12-16 18:01:37 -0500435 Error::Transport(TransportError {
436 kind: TransportErrorKind::Unknown,
Allen Georgea1942762021-03-06 17:39:02 -0500437 message: err.to_string(), // FIXME: use io error's debug string
Allen Georgeef7a1892018-12-16 18:01:37 -0500438 })
Allen George8b96bfb2016-11-02 08:01:08 -0400439 }
440 }
441 }
442}
443
444impl From<string::FromUtf8Error> for Error {
445 fn from(err: string::FromUtf8Error) -> Self {
Allen Georgeef7a1892018-12-16 18:01:37 -0500446 Error::Protocol(ProtocolError {
447 kind: ProtocolErrorKind::InvalidData,
Allen Georgea1942762021-03-06 17:39:02 -0500448 message: err.to_string(), // FIXME: use fmt::Error's debug string
Allen Georgeef7a1892018-12-16 18:01:37 -0500449 })
Allen George8b96bfb2016-11-02 08:01:08 -0400450 }
451}
452
453/// Create a new `Error` instance of type `Protocol` that wraps a
454/// `ProtocolError`.
455pub fn new_protocol_error<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> Error {
456 Error::Protocol(ProtocolError::new(kind, message))
457}
458
459/// Information about errors that occur in the runtime library.
Allen Georgebc1344d2017-04-28 10:22:03 -0400460#[derive(Debug, Eq, PartialEq)]
Allen George8b96bfb2016-11-02 08:01:08 -0400461pub struct ProtocolError {
462 /// Protocol error variant.
463 ///
464 /// If a specific `ProtocolErrorKind` does not apply use
465 /// `ProtocolErrorKind::Unknown`.
466 pub kind: ProtocolErrorKind,
467 /// Human-readable error message.
468 pub message: String,
469}
470
471impl ProtocolError {
472 /// Create a new `ProtocolError`.
473 pub fn new<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> ProtocolError {
474 ProtocolError {
Allen George7ddbcc02020-11-08 09:51:19 -0500475 kind,
Allen George8b96bfb2016-11-02 08:01:08 -0400476 message: message.into(),
477 }
478 }
479}
480
481/// Runtime library error categories.
482///
483/// This list may grow, and it is not recommended to match against it.
Allen Georgea1942762021-03-06 17:39:02 -0500484#[non_exhaustive]
Allen George8b96bfb2016-11-02 08:01:08 -0400485#[derive(Clone, Copy, Eq, Debug, PartialEq)]
486pub enum ProtocolErrorKind {
487 /// Catch-all runtime-library error.
488 Unknown = 0,
489 /// An invalid argument was supplied to a library function, or invalid data
490 /// was received from a Thrift endpoint.
491 InvalidData = 1,
492 /// An invalid size was received in an encoded field.
493 NegativeSize = 2,
494 /// Thrift message or field was too long.
495 SizeLimit = 3,
496 /// Unsupported or unknown Thrift protocol version.
497 BadVersion = 4,
498 /// Unsupported Thrift protocol, server or field type.
499 NotImplemented = 5,
500 /// Reached the maximum nested depth to which an encoded Thrift field could
501 /// be skipped.
502 DepthLimit = 6,
503}
504
Allen Georgea1942762021-03-06 17:39:02 -0500505impl Display for ProtocolError {
506 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
507 let error_text = match self.kind {
Allen George8b96bfb2016-11-02 08:01:08 -0400508 ProtocolErrorKind::Unknown => "protocol error",
509 ProtocolErrorKind::InvalidData => "bad data",
510 ProtocolErrorKind::NegativeSize => "negative message size",
511 ProtocolErrorKind::SizeLimit => "message too long",
512 ProtocolErrorKind::BadVersion => "invalid thrift version",
513 ProtocolErrorKind::NotImplemented => "not implemented",
514 ProtocolErrorKind::DepthLimit => "maximum skip depth reached",
Allen Georgea1942762021-03-06 17:39:02 -0500515 };
Allen George8b96bfb2016-11-02 08:01:08 -0400516
Allen Georgea1942762021-03-06 17:39:02 -0500517 write!(f, "{}", error_text)
Allen George8b96bfb2016-11-02 08:01:08 -0400518 }
519}
520
521impl TryFrom<i32> for ProtocolErrorKind {
Danny Browningddec4312019-03-08 14:20:41 -0700522 type Error = Error;
523 fn try_from(from: i32) -> Result<Self, Self::Error> {
Allen George8b96bfb2016-11-02 08:01:08 -0400524 match from {
525 0 => Ok(ProtocolErrorKind::Unknown),
526 1 => Ok(ProtocolErrorKind::InvalidData),
527 2 => Ok(ProtocolErrorKind::NegativeSize),
528 3 => Ok(ProtocolErrorKind::SizeLimit),
529 4 => Ok(ProtocolErrorKind::BadVersion),
530 5 => Ok(ProtocolErrorKind::NotImplemented),
531 6 => Ok(ProtocolErrorKind::DepthLimit),
Allen Georgeef7a1892018-12-16 18:01:37 -0500532 _ => Err(Error::Protocol(ProtocolError {
533 kind: ProtocolErrorKind::Unknown,
534 message: format!("cannot convert {} to ProtocolErrorKind", from),
535 })),
Allen George8b96bfb2016-11-02 08:01:08 -0400536 }
537 }
538}
539
540/// Create a new `Error` instance of type `Application` that wraps an
541/// `ApplicationError`.
542pub fn new_application_error<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> Error {
543 Error::Application(ApplicationError::new(kind, message))
544}
545
546/// Information about errors in auto-generated code or in user-implemented
547/// service handlers.
Allen Georgebc1344d2017-04-28 10:22:03 -0400548#[derive(Debug, Eq, PartialEq)]
Allen George8b96bfb2016-11-02 08:01:08 -0400549pub struct ApplicationError {
550 /// Application error variant.
551 ///
552 /// If a specific `ApplicationErrorKind` does not apply use
553 /// `ApplicationErrorKind::Unknown`.
554 pub kind: ApplicationErrorKind,
555 /// Human-readable error message.
556 pub message: String,
557}
558
559impl ApplicationError {
560 /// Create a new `ApplicationError`.
561 pub fn new<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> ApplicationError {
562 ApplicationError {
Allen George7ddbcc02020-11-08 09:51:19 -0500563 kind,
Allen George8b96bfb2016-11-02 08:01:08 -0400564 message: message.into(),
565 }
566 }
567}
568
569/// Auto-generated or user-implemented code error categories.
570///
571/// This list may grow, and it is not recommended to match against it.
Allen Georgea1942762021-03-06 17:39:02 -0500572#[non_exhaustive]
Allen George8b96bfb2016-11-02 08:01:08 -0400573#[derive(Clone, Copy, Debug, Eq, PartialEq)]
574pub enum ApplicationErrorKind {
575 /// Catch-all application error.
576 Unknown = 0,
577 /// Made service call to an unknown service method.
578 UnknownMethod = 1,
579 /// Received an unknown Thrift message type. That is, not one of the
580 /// `thrift::protocol::TMessageType` variants.
581 InvalidMessageType = 2,
582 /// Method name in a service reply does not match the name of the
583 /// receiving service method.
584 WrongMethodName = 3,
585 /// Received an out-of-order Thrift message.
586 BadSequenceId = 4,
587 /// Service reply is missing required fields.
588 MissingResult = 5,
589 /// Auto-generated code failed unexpectedly.
590 InternalError = 6,
591 /// Thrift protocol error. When possible use `Error::ProtocolError` with a
592 /// specific `ProtocolErrorKind` instead.
593 ProtocolError = 7,
594 /// *Unknown*. Included only for compatibility with existing Thrift implementations.
595 InvalidTransform = 8, // ??
596 /// Thrift endpoint requested, or is using, an unsupported encoding.
597 InvalidProtocol = 9, // ??
598 /// Thrift endpoint requested, or is using, an unsupported auto-generated client type.
599 UnsupportedClientType = 10, // ??
600}
601
Allen Georgea1942762021-03-06 17:39:02 -0500602impl Display for ApplicationError {
603 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
604 let error_text = match self.kind {
Allen George8b96bfb2016-11-02 08:01:08 -0400605 ApplicationErrorKind::Unknown => "service error",
606 ApplicationErrorKind::UnknownMethod => "unknown service method",
607 ApplicationErrorKind::InvalidMessageType => "wrong message type received",
608 ApplicationErrorKind::WrongMethodName => "unknown method reply received",
609 ApplicationErrorKind::BadSequenceId => "out of order sequence id",
610 ApplicationErrorKind::MissingResult => "missing method result",
611 ApplicationErrorKind::InternalError => "remote service threw exception",
612 ApplicationErrorKind::ProtocolError => "protocol error",
613 ApplicationErrorKind::InvalidTransform => "invalid transform",
614 ApplicationErrorKind::InvalidProtocol => "invalid protocol requested",
615 ApplicationErrorKind::UnsupportedClientType => "unsupported protocol client",
Allen Georgea1942762021-03-06 17:39:02 -0500616 };
Allen George8b96bfb2016-11-02 08:01:08 -0400617
Allen Georgea1942762021-03-06 17:39:02 -0500618 write!(f, "{}", error_text)
Allen George8b96bfb2016-11-02 08:01:08 -0400619 }
620}
621
622impl TryFrom<i32> for ApplicationErrorKind {
Danny Browningddec4312019-03-08 14:20:41 -0700623 type Error = Error;
624 fn try_from(from: i32) -> Result<Self, Self::Error> {
Allen George8b96bfb2016-11-02 08:01:08 -0400625 match from {
626 0 => Ok(ApplicationErrorKind::Unknown),
627 1 => Ok(ApplicationErrorKind::UnknownMethod),
628 2 => Ok(ApplicationErrorKind::InvalidMessageType),
629 3 => Ok(ApplicationErrorKind::WrongMethodName),
630 4 => Ok(ApplicationErrorKind::BadSequenceId),
631 5 => Ok(ApplicationErrorKind::MissingResult),
632 6 => Ok(ApplicationErrorKind::InternalError),
633 7 => Ok(ApplicationErrorKind::ProtocolError),
634 8 => Ok(ApplicationErrorKind::InvalidTransform),
635 9 => Ok(ApplicationErrorKind::InvalidProtocol),
636 10 => Ok(ApplicationErrorKind::UnsupportedClientType),
Allen Georgeef7a1892018-12-16 18:01:37 -0500637 _ => Err(Error::Application(ApplicationError {
638 kind: ApplicationErrorKind::Unknown,
639 message: format!("cannot convert {} to ApplicationErrorKind", from),
640 })),
Allen George8b96bfb2016-11-02 08:01:08 -0400641 }
642 }
643}