1use std::error::Error as StdError;
2use std::fmt;
3
4type Source = Box<dyn StdError + Send + Sync + 'static>;
5
6pub struct Error {
7 inner: ErrorImpl,
8}
9
10struct ErrorImpl {
11 kind: Kind,
12 source: Option<Source>,
13}
14
15#[derive(Debug)]
16enum Kind {
17 Connect,
18 NotConnected,
19 Request,
20 Conversion,
21 EventStreamDisconnect,
22 EventStream,
23}
24
25impl Error {
26 fn new(kind: Kind) -> Self {
27 Self {
28 inner: ErrorImpl { kind, source: None },
29 }
30 }
31
32 pub(crate) fn with(mut self, source: impl Into<Source>) -> Self {
33 self.inner.source = Some(source.into());
34 self
35 }
36
37 pub(crate) fn connect(source: impl Into<Source>) -> Self {
38 Error::new(Kind::Connect).with(source)
39 }
40
41 pub(crate) fn not_connected() -> Self {
42 Error::new(Kind::NotConnected)
43 }
44
45 pub(crate) fn request(source: impl Into<Source>) -> Self {
46 Error::new(Kind::Request).with(source)
47 }
48
49 pub(crate) fn conversion(source: impl Into<Source>) -> Self {
50 Error::new(Kind::Conversion).with(source)
51 }
52
53 pub(crate) fn event_stream_disconnect() -> Self {
54 Error::new(Kind::EventStreamDisconnect)
55 }
56
57 pub(crate) fn event_stream(source: impl Into<Source>) -> Self {
58 Error::new(Kind::EventStream).with(source)
59 }
60
61 fn description(&self) -> &str {
62 match &self.inner.kind {
63 Kind::Connect => "failed to connect to Ark server",
64 Kind::NotConnected => "no connection to Ark server",
65 Kind::Request => "request failed",
66 Kind::Conversion => "failed to convert between types",
67 Kind::EventStreamDisconnect => "got disconnected from event stream",
68 Kind::EventStream => "error via event stream",
69 }
70 }
71}
72
73impl fmt::Debug for Error {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 let mut f = f.debug_tuple("ark_grpc::Error");
76
77 f.field(&self.inner.kind);
78
79 if let Some(source) = &self.inner.source {
80 f.field(source);
81 }
82
83 f.finish()
84 }
85}
86
87impl fmt::Display for Error {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 f.write_str(self.description())?;
90 if let Some(source) = self.source() {
91 f.write_str(&source.to_string())?;
92 }
93
94 Ok(())
95 }
96}
97
98impl StdError for Error {
99 fn source(&self) -> Option<&(dyn StdError + 'static)> {
100 self.inner
101 .source
102 .as_ref()
103 .map(|source| &**source as &(dyn StdError + 'static))
104 }
105}