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}