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