vector_api_client/
error.rs1use snafu::Snafu;
2
3#[derive(Debug, Snafu)]
5#[snafu(visibility(pub))]
6pub enum Error {
7 #[snafu(display("Connection error: {}", source))]
8 Connection { source: tonic::transport::Error },
9
10 #[snafu(display("gRPC error: {}", source))]
11 Grpc { source: tonic::Status },
12
13 #[snafu(display("Invalid URL: {}", message))]
14 InvalidUrl { message: String },
15
16 #[snafu(display("Not connected to gRPC server"))]
17 NotConnected,
18
19 #[snafu(display("Server is not serving (status: {})", status))]
20 NotServing { status: i32 },
21
22 #[snafu(display("Stream error: {}", message))]
23 Stream { message: String },
24}
25
26impl Error {
27 pub fn is_fatal(&self) -> bool {
29 match self {
30 Error::InvalidUrl { .. } => true,
31 Error::Grpc { source } => matches!(
32 source.code(),
33 tonic::Code::InvalidArgument
34 | tonic::Code::OutOfRange
35 | tonic::Code::NotFound
36 | tonic::Code::PermissionDenied
37 | tonic::Code::Unauthenticated
38 | tonic::Code::Unimplemented
39 ),
40 _ => false,
41 }
42 }
43}
44
45impl From<tonic::Status> for Error {
46 fn from(source: tonic::Status) -> Self {
47 Error::Grpc { source }
48 }
49}
50
51impl From<tonic::transport::Error> for Error {
52 fn from(source: tonic::transport::Error) -> Self {
53 Error::Connection { source }
54 }
55}
56
57pub type Result<T> = std::result::Result<T, Error>;
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn test_error_display() {
65 let err = Error::NotConnected;
66 assert_eq!(err.to_string(), "Not connected to gRPC server");
67
68 let err = Error::InvalidUrl {
69 message: "invalid format".to_string(),
70 };
71 assert_eq!(err.to_string(), "Invalid URL: invalid format");
72 }
73
74 #[test]
75 fn test_error_from_tonic_status() {
76 let status = tonic::Status::unavailable("service down");
77 let err: Error = status.into();
78 assert!(matches!(err, Error::Grpc { .. }));
79 }
80}