1use std::{error::Error as StdError, fmt};
26
27type Source = Box<dyn StdError + Send + Sync + 'static>;
28
29pub struct Error {
31 inner: ErrorImpl,
32}
33
34struct ErrorImpl {
35 kind: Kind,
36 source: Option<Source>,
37}
38
39#[derive(Debug)]
40pub(crate) enum Kind {
41 Transport,
42 #[cfg(feature = "channel")]
43 InvalidUri,
44 #[cfg(feature = "channel")]
45 InvalidUserAgent,
46 #[cfg(all(feature = "_tls-any", feature = "channel"))]
47 InvalidTlsConfigForUds,
48}
49
50impl Error {
51 pub(crate) fn new(kind: Kind) -> Self {
52 Self {
53 inner: ErrorImpl { kind, source: None },
54 }
55 }
56
57 pub(crate) fn with(mut self, source: impl Into<Source>) -> Self {
58 self.inner.source = Some(source.into());
59 self
60 }
61
62 pub(crate) fn from_source(source: impl Into<crate::BoxError>) -> Self {
63 Error::new(Kind::Transport).with(source)
64 }
65
66 #[cfg(feature = "channel")]
67 pub(crate) fn new_invalid_uri() -> Self {
68 Error::new(Kind::InvalidUri)
69 }
70
71 #[cfg(feature = "channel")]
72 pub(crate) fn new_invalid_user_agent() -> Self {
73 Error::new(Kind::InvalidUserAgent)
74 }
75
76 fn description(&self) -> &str {
77 match &self.inner.kind {
78 Kind::Transport => "transport error",
79 #[cfg(feature = "channel")]
80 Kind::InvalidUri => "invalid URI",
81 #[cfg(feature = "channel")]
82 Kind::InvalidUserAgent => "user agent is not a valid header value",
83 #[cfg(all(feature = "_tls-any", feature = "channel"))]
84 Kind::InvalidTlsConfigForUds => "cannot apply TLS config for unix domain socket",
85 }
86 }
87}
88
89impl fmt::Debug for Error {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 let mut f = f.debug_tuple("tonic::transport::Error");
92
93 f.field(&self.inner.kind);
94
95 if let Some(source) = &self.inner.source {
96 f.field(source);
97 }
98
99 f.finish()
100 }
101}
102
103impl fmt::Display for Error {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.write_str(self.description())
106 }
107}
108
109impl StdError for Error {
110 fn source(&self) -> Option<&(dyn StdError + 'static)> {
111 self.inner
112 .source
113 .as_ref()
114 .map(|source| &**source as &(dyn StdError + 'static))
115 }
116}