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