parquet_format_async_temp/thrift/
errors.rs

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
18use std::convert::TryFrom;
19use std::convert::{From, Into};
20use std::fmt::{Debug, Display, Formatter};
21use std::{error, fmt, io, string};
22
23use crate::thrift::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/// ```
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}
188
189impl Error {
190    /// Create an `ApplicationError` from its wire representation.
191    ///
192    /// Application code **should never** call this method directly.
193    pub fn read_application_error_from_in_protocol(
194        i: &mut dyn TInputProtocol,
195    ) -> crate::thrift::Result<ApplicationError> {
196        let mut message = "general remote error".to_owned();
197        let mut kind = ApplicationErrorKind::Unknown;
198
199        i.read_struct_begin()?;
200
201        loop {
202            let field_ident = i.read_field_begin()?;
203
204            if field_ident.field_type == TType::Stop {
205                break;
206            }
207
208            let id = field_ident
209                .id
210                .expect("sender should always specify id for non-STOP field");
211
212            match id {
213                1 => {
214                    let remote_message = i.read_string()?;
215                    i.read_field_end()?;
216                    message = remote_message;
217                }
218                2 => {
219                    let remote_type_as_int = i.read_i32()?;
220                    let remote_kind: ApplicationErrorKind = TryFrom::try_from(remote_type_as_int)
221                        .unwrap_or(ApplicationErrorKind::Unknown);
222                    i.read_field_end()?;
223                    kind = remote_kind;
224                }
225                _ => {
226                    i.skip(field_ident.field_type)?;
227                }
228            }
229        }
230
231        i.read_struct_end()?;
232
233        Ok(ApplicationError { kind, message })
234    }
235
236    /// Convert an `ApplicationError` into its wire representation and write
237    /// it to the remote.
238    ///
239    /// Application code **should never** call this method directly.
240    pub fn write_application_error_to_out_protocol(
241        e: &ApplicationError,
242        o: &mut dyn TOutputProtocol,
243    ) -> crate::thrift::Result<()> {
244        o.write_struct_begin(&TStructIdentifier {
245            name: "TApplicationException".to_owned(),
246        })?;
247
248        let message_field = TFieldIdentifier::new("message", TType::String, 1);
249        let type_field = TFieldIdentifier::new("type", TType::I32, 2);
250
251        o.write_field_begin(&message_field)?;
252        o.write_string(&e.message)?;
253        o.write_field_end()?;
254
255        o.write_field_begin(&type_field)?;
256        o.write_i32(e.kind as i32)?;
257        o.write_field_end()?;
258
259        o.write_field_stop()?;
260        o.write_struct_end()?;
261
262        o.flush()
263    }
264}
265
266impl error::Error for Error {}
267
268impl Debug for Error {
269    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
270        match *self {
271            Error::Transport(ref e) => Debug::fmt(e, f),
272            Error::Protocol(ref e) => Debug::fmt(e, f),
273            Error::Application(ref e) => Debug::fmt(e, f),
274        }
275    }
276}
277
278impl Display for Error {
279    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
280        match *self {
281            Error::Transport(ref e) => Display::fmt(e, f),
282            Error::Protocol(ref e) => Display::fmt(e, f),
283            Error::Application(ref e) => Display::fmt(e, f),
284        }
285    }
286}
287
288impl From<String> for Error {
289    fn from(s: String) -> Self {
290        Error::Application(ApplicationError {
291            kind: ApplicationErrorKind::Unknown,
292            message: s,
293        })
294    }
295}
296
297impl<'a> From<&'a str> for Error {
298    fn from(s: &'a str) -> Self {
299        Error::Application(ApplicationError {
300            kind: ApplicationErrorKind::Unknown,
301            message: String::from(s),
302        })
303    }
304}
305
306impl From<TransportError> for Error {
307    fn from(e: TransportError) -> Self {
308        Error::Transport(e)
309    }
310}
311
312impl From<ProtocolError> for Error {
313    fn from(e: ProtocolError) -> Self {
314        Error::Protocol(e)
315    }
316}
317
318impl From<ApplicationError> for Error {
319    fn from(e: ApplicationError) -> Self {
320        Error::Application(e)
321    }
322}
323
324/// Create a new `Error` instance of type `Transport` that wraps a
325/// `TransportError`.
326pub fn new_transport_error<S: Into<String>>(kind: TransportErrorKind, message: S) -> Error {
327    Error::Transport(TransportError::new(kind, message))
328}
329
330/// Information about I/O errors.
331#[derive(Debug, Eq, PartialEq)]
332pub struct TransportError {
333    /// I/O error variant.
334    ///
335    /// If a specific `TransportErrorKind` does not apply use
336    /// `TransportErrorKind::Unknown`.
337    pub kind: TransportErrorKind,
338    /// Human-readable error message.
339    pub message: String,
340}
341
342impl TransportError {
343    /// Create a new `TransportError`.
344    pub fn new<S: Into<String>>(kind: TransportErrorKind, message: S) -> TransportError {
345        TransportError {
346            kind,
347            message: message.into(),
348        }
349    }
350}
351
352/// I/O error categories.
353///
354/// This list may grow, and it is not recommended to match against it.
355#[non_exhaustive]
356#[derive(Clone, Copy, Eq, Debug, PartialEq)]
357pub enum TransportErrorKind {
358    /// Catch-all I/O error.
359    Unknown = 0,
360    /// An I/O operation was attempted when the transport channel was not open.
361    NotOpen = 1,
362    /// The transport channel cannot be opened because it was opened previously.
363    AlreadyOpen = 2,
364    /// An I/O operation timed out.
365    TimedOut = 3,
366    /// A read could not complete because no bytes were available.
367    EndOfFile = 4,
368    /// An invalid (buffer/message) size was requested or received.
369    NegativeSize = 5,
370    /// Too large a buffer or message size was requested or received.
371    SizeLimit = 6,
372}
373
374impl Display for TransportError {
375    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
376        let error_text = match self.kind {
377            TransportErrorKind::Unknown => "transport error",
378            TransportErrorKind::NotOpen => "not open",
379            TransportErrorKind::AlreadyOpen => "already open",
380            TransportErrorKind::TimedOut => "timed out",
381            TransportErrorKind::EndOfFile => "end of file",
382            TransportErrorKind::NegativeSize => "negative size message",
383            TransportErrorKind::SizeLimit => "message too long",
384        };
385
386        write!(f, "{}", error_text)
387    }
388}
389
390impl TryFrom<i32> for TransportErrorKind {
391    type Error = Error;
392    fn try_from(from: i32) -> Result<Self, Self::Error> {
393        match from {
394            0 => Ok(TransportErrorKind::Unknown),
395            1 => Ok(TransportErrorKind::NotOpen),
396            2 => Ok(TransportErrorKind::AlreadyOpen),
397            3 => Ok(TransportErrorKind::TimedOut),
398            4 => Ok(TransportErrorKind::EndOfFile),
399            5 => Ok(TransportErrorKind::NegativeSize),
400            6 => Ok(TransportErrorKind::SizeLimit),
401            _ => Err(Error::Protocol(ProtocolError {
402                kind: ProtocolErrorKind::Unknown,
403                message: format!("cannot convert {} to TransportErrorKind", from),
404            })),
405        }
406    }
407}
408
409impl From<io::Error> for Error {
410    fn from(err: io::Error) -> Self {
411        match err.kind() {
412            io::ErrorKind::ConnectionReset
413            | io::ErrorKind::ConnectionRefused
414            | io::ErrorKind::NotConnected => Error::Transport(TransportError {
415                kind: TransportErrorKind::NotOpen,
416                message: err.to_string(),
417            }),
418            io::ErrorKind::AlreadyExists => Error::Transport(TransportError {
419                kind: TransportErrorKind::AlreadyOpen,
420                message: err.to_string(),
421            }),
422            io::ErrorKind::TimedOut => Error::Transport(TransportError {
423                kind: TransportErrorKind::TimedOut,
424                message: err.to_string(),
425            }),
426            io::ErrorKind::UnexpectedEof => Error::Transport(TransportError {
427                kind: TransportErrorKind::EndOfFile,
428                message: err.to_string(),
429            }),
430            _ => {
431                Error::Transport(TransportError {
432                    kind: TransportErrorKind::Unknown,
433                    message: err.to_string(), // FIXME: use io error's debug string
434                })
435            }
436        }
437    }
438}
439
440impl From<string::FromUtf8Error> for Error {
441    fn from(err: string::FromUtf8Error) -> Self {
442        Error::Protocol(ProtocolError {
443            kind: ProtocolErrorKind::InvalidData,
444            message: err.to_string(), // FIXME: use fmt::Error's debug string
445        })
446    }
447}
448
449/// Create a new `Error` instance of type `Protocol` that wraps a
450/// `ProtocolError`.
451pub fn new_protocol_error<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> Error {
452    Error::Protocol(ProtocolError::new(kind, message))
453}
454
455/// Information about errors that occur in the runtime library.
456#[derive(Debug, Eq, PartialEq)]
457pub struct ProtocolError {
458    /// Protocol error variant.
459    ///
460    /// If a specific `ProtocolErrorKind` does not apply use
461    /// `ProtocolErrorKind::Unknown`.
462    pub kind: ProtocolErrorKind,
463    /// Human-readable error message.
464    pub message: String,
465}
466
467impl ProtocolError {
468    /// Create a new `ProtocolError`.
469    pub fn new<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> ProtocolError {
470        ProtocolError {
471            kind,
472            message: message.into(),
473        }
474    }
475}
476
477/// Runtime library error categories.
478///
479/// This list may grow, and it is not recommended to match against it.
480#[non_exhaustive]
481#[derive(Clone, Copy, Eq, Debug, PartialEq)]
482pub enum ProtocolErrorKind {
483    /// Catch-all runtime-library error.
484    Unknown = 0,
485    /// An invalid argument was supplied to a library function, or invalid data
486    /// was received from a Thrift endpoint.
487    InvalidData = 1,
488    /// An invalid size was received in an encoded field.
489    NegativeSize = 2,
490    /// Thrift message or field was too long.
491    SizeLimit = 3,
492    /// Unsupported or unknown Thrift protocol version.
493    BadVersion = 4,
494    /// Unsupported Thrift protocol, server or field type.
495    NotImplemented = 5,
496    /// Reached the maximum nested depth to which an encoded Thrift field could
497    /// be skipped.
498    DepthLimit = 6,
499}
500
501impl Display for ProtocolError {
502    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
503        let error_text = match self.kind {
504            ProtocolErrorKind::Unknown => "protocol error",
505            ProtocolErrorKind::InvalidData => "bad data",
506            ProtocolErrorKind::NegativeSize => "negative message size",
507            ProtocolErrorKind::SizeLimit => "message too long",
508            ProtocolErrorKind::BadVersion => "invalid thrift version",
509            ProtocolErrorKind::NotImplemented => "not implemented",
510            ProtocolErrorKind::DepthLimit => "maximum skip depth reached",
511        };
512
513        write!(f, "{}", error_text)
514    }
515}
516
517impl TryFrom<i32> for ProtocolErrorKind {
518    type Error = Error;
519    fn try_from(from: i32) -> Result<Self, Self::Error> {
520        match from {
521            0 => Ok(ProtocolErrorKind::Unknown),
522            1 => Ok(ProtocolErrorKind::InvalidData),
523            2 => Ok(ProtocolErrorKind::NegativeSize),
524            3 => Ok(ProtocolErrorKind::SizeLimit),
525            4 => Ok(ProtocolErrorKind::BadVersion),
526            5 => Ok(ProtocolErrorKind::NotImplemented),
527            6 => Ok(ProtocolErrorKind::DepthLimit),
528            _ => Err(Error::Protocol(ProtocolError {
529                kind: ProtocolErrorKind::Unknown,
530                message: format!("cannot convert {} to ProtocolErrorKind", from),
531            })),
532        }
533    }
534}
535
536/// Create a new `Error` instance of type `Application` that wraps an
537/// `ApplicationError`.
538pub fn new_application_error<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> Error {
539    Error::Application(ApplicationError::new(kind, message))
540}
541
542/// Information about errors in auto-generated code or in user-implemented
543/// service handlers.
544#[derive(Debug, Eq, PartialEq)]
545pub struct ApplicationError {
546    /// Application error variant.
547    ///
548    /// If a specific `ApplicationErrorKind` does not apply use
549    /// `ApplicationErrorKind::Unknown`.
550    pub kind: ApplicationErrorKind,
551    /// Human-readable error message.
552    pub message: String,
553}
554
555impl ApplicationError {
556    /// Create a new `ApplicationError`.
557    pub fn new<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> ApplicationError {
558        ApplicationError {
559            kind,
560            message: message.into(),
561        }
562    }
563}
564
565/// Auto-generated or user-implemented code error categories.
566///
567/// This list may grow, and it is not recommended to match against it.
568#[non_exhaustive]
569#[derive(Clone, Copy, Debug, Eq, PartialEq)]
570pub enum ApplicationErrorKind {
571    /// Catch-all application error.
572    Unknown = 0,
573    /// Made service call to an unknown service method.
574    UnknownMethod = 1,
575    /// Received an unknown Thrift message type. That is, not one of the
576    /// `thrift::protocol::TMessageType` variants.
577    InvalidMessageType = 2,
578    /// Method name in a service reply does not match the name of the
579    /// receiving service method.
580    WrongMethodName = 3,
581    /// Received an out-of-order Thrift message.
582    BadSequenceId = 4,
583    /// Service reply is missing required fields.
584    MissingResult = 5,
585    /// Auto-generated code failed unexpectedly.
586    InternalError = 6,
587    /// Thrift protocol error. When possible use `Error::ProtocolError` with a
588    /// specific `ProtocolErrorKind` instead.
589    ProtocolError = 7,
590    /// *Unknown*. Included only for compatibility with existing Thrift implementations.
591    InvalidTransform = 8, // ??
592    /// Thrift endpoint requested, or is using, an unsupported encoding.
593    InvalidProtocol = 9, // ??
594    /// Thrift endpoint requested, or is using, an unsupported auto-generated client type.
595    UnsupportedClientType = 10, // ??
596}
597
598impl Display for ApplicationError {
599    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
600        let error_text = match self.kind {
601            ApplicationErrorKind::Unknown => "service error",
602            ApplicationErrorKind::UnknownMethod => "unknown service method",
603            ApplicationErrorKind::InvalidMessageType => "wrong message type received",
604            ApplicationErrorKind::WrongMethodName => "unknown method reply received",
605            ApplicationErrorKind::BadSequenceId => "out of order sequence id",
606            ApplicationErrorKind::MissingResult => "missing method result",
607            ApplicationErrorKind::InternalError => "remote service threw exception",
608            ApplicationErrorKind::ProtocolError => "protocol error",
609            ApplicationErrorKind::InvalidTransform => "invalid transform",
610            ApplicationErrorKind::InvalidProtocol => "invalid protocol requested",
611            ApplicationErrorKind::UnsupportedClientType => "unsupported protocol client",
612        };
613
614        write!(f, "{}", error_text)
615    }
616}
617
618impl TryFrom<i32> for ApplicationErrorKind {
619    type Error = Error;
620    fn try_from(from: i32) -> Result<Self, Self::Error> {
621        match from {
622            0 => Ok(ApplicationErrorKind::Unknown),
623            1 => Ok(ApplicationErrorKind::UnknownMethod),
624            2 => Ok(ApplicationErrorKind::InvalidMessageType),
625            3 => Ok(ApplicationErrorKind::WrongMethodName),
626            4 => Ok(ApplicationErrorKind::BadSequenceId),
627            5 => Ok(ApplicationErrorKind::MissingResult),
628            6 => Ok(ApplicationErrorKind::InternalError),
629            7 => Ok(ApplicationErrorKind::ProtocolError),
630            8 => Ok(ApplicationErrorKind::InvalidTransform),
631            9 => Ok(ApplicationErrorKind::InvalidProtocol),
632            10 => Ok(ApplicationErrorKind::UnsupportedClientType),
633            _ => Err(Error::Application(ApplicationError {
634                kind: ApplicationErrorKind::Unknown,
635                message: format!("cannot convert {} to ApplicationErrorKind", from),
636            })),
637        }
638    }
639}