1 // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 3 use std::ffi::CString; 4 use std::{error, fmt, result}; 5 6 use crate::call::RpcStatus; 7 use crate::grpc_sys::grpc_call_error; 8 9 #[cfg(feature = "protobuf-codec")] 10 use protobuf::ProtobufError; 11 12 #[cfg(feature = "protobufv3-codec")] 13 use protobufv3::Error as ProtobufError; 14 15 /// Errors generated from this library. 16 #[derive(Debug)] 17 pub enum Error { 18 /// Codec error. 19 Codec(Box<dyn error::Error + Send + Sync>), 20 /// Failed to start an internal async call. 21 CallFailure(grpc_call_error), 22 /// Rpc request fail. 23 RpcFailure(RpcStatus), 24 /// Try to write to a finished rpc call. 25 RpcFinished(Option<RpcStatus>), 26 /// Remote is stopped. 27 RemoteStopped, 28 /// Failed to shutdown. 29 ShutdownFailed, 30 /// Failed to bind. 31 BindFail(CString), 32 /// gRPC completion queue is shutdown. 33 QueueShutdown, 34 /// Failed to create Google default credentials. 35 GoogleAuthenticationFailed, 36 /// Invalid format of metadata. 37 InvalidMetadata(String), 38 } 39 40 impl fmt::Display for Error { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result41 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 42 match self { 43 Error::RpcFailure(s) => { 44 if s.message().is_empty() { 45 write!(fmt, "RpcFailure: {}", s.code()) 46 } else { 47 write!(fmt, "RpcFailure: {} {}", s.code(), s.message()) 48 } 49 } 50 other_error => write!(fmt, "{other_error:?}"), 51 } 52 } 53 } 54 55 impl error::Error for Error { source(&self) -> Option<&(dyn error::Error + 'static)>56 fn source(&self) -> Option<&(dyn error::Error + 'static)> { 57 match *self { 58 Error::Codec(ref e) => Some(e.as_ref()), 59 _ => None, 60 } 61 } 62 } 63 64 #[cfg(any(feature = "protobuf-codec", feature = "protobufv3-codec"))] 65 impl From<ProtobufError> for Error { from(e: ProtobufError) -> Error66 fn from(e: ProtobufError) -> Error { 67 Error::Codec(Box::new(e)) 68 } 69 } 70 71 #[cfg(feature = "prost-codec")] 72 impl From<prost::DecodeError> for Error { from(e: prost::DecodeError) -> Error73 fn from(e: prost::DecodeError) -> Error { 74 Error::Codec(Box::new(e)) 75 } 76 } 77 78 #[cfg(feature = "prost-codec")] 79 impl From<prost::EncodeError> for Error { from(e: prost::EncodeError) -> Error80 fn from(e: prost::EncodeError) -> Error { 81 Error::Codec(Box::new(e)) 82 } 83 } 84 85 /// Type alias to use this library's [`Error`] type in a `Result`. 86 pub type Result<T> = result::Result<T, Error>; 87 88 #[cfg(all(test, feature = "protobuf-codec"))] 89 mod tests { 90 use std::error::Error as StdError; 91 92 use protobuf::error::WireError; 93 use protobuf::ProtobufError; 94 95 use super::Error; 96 97 #[test] test_convert()98 fn test_convert() { 99 let error = ProtobufError::WireError(WireError::UnexpectedEof); 100 let e: Error = error.into(); 101 assert_eq!(e.to_string(), "Codec(WireError(UnexpectedEof))"); 102 assert!(e.source().is_some()); 103 } 104 } 105