1use std::error::Error;
19
20use arrow_schema::ArrowError;
21
22#[derive(Debug)]
24pub enum FlightError {
25 Arrow(ArrowError),
27 NotYetImplemented(String),
29 Tonic(tonic::Status),
31 ProtocolError(String),
33 DecodeError(String),
35 ExternalError(Box<dyn Error + Send + Sync>),
37}
38
39impl FlightError {
40 pub fn protocol(message: impl Into<String>) -> Self {
42 Self::ProtocolError(message.into())
43 }
44
45 pub fn from_external_error(error: Box<dyn Error + Send + Sync>) -> Self {
47 Self::ExternalError(error)
48 }
49}
50
51impl std::fmt::Display for FlightError {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 match self {
54 FlightError::Arrow(source) => write!(f, "Arrow error: {}", source),
55 FlightError::NotYetImplemented(desc) => write!(f, "Not yet implemented: {}", desc),
56 FlightError::Tonic(source) => write!(f, "Tonic error: {}", source),
57 FlightError::ProtocolError(desc) => write!(f, "Protocol error: {}", desc),
58 FlightError::DecodeError(desc) => write!(f, "Decode error: {}", desc),
59 FlightError::ExternalError(source) => write!(f, "External error: {}", source),
60 }
61 }
62}
63
64impl Error for FlightError {
65 fn source(&self) -> Option<&(dyn Error + 'static)> {
66 match self {
67 FlightError::Arrow(source) => Some(source),
68 FlightError::Tonic(source) => Some(source),
69 FlightError::ExternalError(source) => Some(source.as_ref()),
70 _ => None,
71 }
72 }
73}
74
75impl From<tonic::Status> for FlightError {
76 fn from(status: tonic::Status) -> Self {
77 Self::Tonic(status)
78 }
79}
80
81impl From<ArrowError> for FlightError {
82 fn from(value: ArrowError) -> Self {
83 Self::Arrow(value)
84 }
85}
86
87impl From<FlightError> for tonic::Status {
90 fn from(value: FlightError) -> Self {
91 match value {
92 FlightError::Arrow(e) => tonic::Status::internal(e.to_string()),
93 FlightError::NotYetImplemented(e) => tonic::Status::internal(e),
94 FlightError::Tonic(status) => status,
95 FlightError::ProtocolError(e) => tonic::Status::internal(e),
96 FlightError::DecodeError(e) => tonic::Status::internal(e),
97 FlightError::ExternalError(e) => tonic::Status::internal(e.to_string()),
98 }
99 }
100}
101
102pub type Result<T> = std::result::Result<T, FlightError>;
104
105#[cfg(test)]
106mod test {
107 use super::*;
108
109 #[test]
110 fn error_source() {
111 let e1 = FlightError::DecodeError("foo".into());
112 assert!(e1.source().is_none());
113
114 let e2 = FlightError::ExternalError(Box::new(e1));
116 let source = e2.source().unwrap().downcast_ref::<FlightError>().unwrap();
117 assert!(matches!(source, FlightError::DecodeError(_)));
118
119 let e3 = FlightError::ExternalError(Box::new(e2));
120 let source = e3
121 .source()
122 .unwrap()
123 .downcast_ref::<FlightError>()
124 .unwrap()
125 .source()
126 .unwrap()
127 .downcast_ref::<FlightError>()
128 .unwrap();
129
130 assert!(matches!(source, FlightError::DecodeError(_)));
131 }
132
133 #[test]
134 fn error_through_arrow() {
135 let e1 = FlightError::DecodeError("foo".into());
137 let e2 = ArrowError::ExternalError(Box::new(e1));
138 let e3 = FlightError::ExternalError(Box::new(e2));
139
140 let mut root_error: &dyn Error = &e3;
142 while let Some(source) = root_error.source() {
143 root_error = source;
145 }
146
147 let source = root_error.downcast_ref::<FlightError>().unwrap();
148 assert!(matches!(source, FlightError::DecodeError(_)));
149 }
150}