Skip to content

Commit 9349c7e

Browse files
DanGouldbenalleng
authored andcommitted
Make an io::Error variant public
So that they can be matched on in downstream logic. Keep Internal variants private.
1 parent e2b66a2 commit 9349c7e

File tree

1 file changed

+53
-18
lines changed

1 file changed

+53
-18
lines changed

payjoin/src/io.rs

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,35 +54,50 @@ pub async fn fetch_ohttp_keys_with_cert(
5454

5555
async fn parse_ohttp_keys_response(res: reqwest::Response) -> Result<OhttpKeys, Error> {
5656
if !res.status().is_success() {
57-
return Err(Error(InternalError::UnexpectedStatusCode(res.status())));
57+
return Err(Error::UnexpectedStatusCode(res.status()));
5858
}
5959

6060
let body = res.bytes().await?.to_vec();
61-
OhttpKeys::decode(&body).map_err(|e| Error(InternalError::InvalidOhttpKeys(e.to_string())))
61+
OhttpKeys::decode(&body).map_err(|e| {
62+
Error::Internal(InternalError(InternalErrorInner::InvalidOhttpKeys(e.to_string())))
63+
})
6264
}
6365

6466
#[derive(Debug)]
65-
pub struct Error(InternalError);
67+
#[non_exhaustive]
68+
pub enum Error {
69+
/// When the payjoin directory returns an unexpected status code
70+
UnexpectedStatusCode(http::StatusCode),
71+
/// Internal errors that should not be pattern matched by users
72+
#[doc(hidden)]
73+
Internal(InternalError),
74+
}
75+
76+
#[derive(Debug)]
77+
pub struct InternalError(InternalErrorInner);
6678

6779
#[derive(Debug)]
68-
enum InternalError {
80+
enum InternalErrorInner {
6981
ParseUrl(crate::into_url::Error),
7082
Reqwest(reqwest::Error),
7183
Io(std::io::Error),
7284
#[cfg(feature = "_danger-local-https")]
7385
Rustls(rustls::Error),
7486
InvalidOhttpKeys(String),
75-
UnexpectedStatusCode(http::StatusCode),
7687
}
7788

7889
impl From<url::ParseError> for Error {
79-
fn from(value: url::ParseError) -> Self { Self(InternalError::ParseUrl(value.into())) }
90+
fn from(value: url::ParseError) -> Self {
91+
Self::Internal(InternalError(InternalErrorInner::ParseUrl(value.into())))
92+
}
8093
}
8194

8295
macro_rules! impl_from_error {
8396
($from:ty, $to:ident) => {
8497
impl From<$from> for Error {
85-
fn from(value: $from) -> Self { Self(InternalError::$to(value)) }
98+
fn from(value: $from) -> Self {
99+
Self::Internal(InternalError(InternalErrorInner::$to(value)))
100+
}
86101
}
87102
};
88103
}
@@ -95,18 +110,26 @@ impl_from_error!(rustls::Error, Rustls);
95110

96111
impl std::fmt::Display for Error {
97112
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
98-
use InternalError::*;
113+
match self {
114+
Self::UnexpectedStatusCode(code) => {
115+
write!(f, "Unexpected status code from payjoin directory: {code}")
116+
}
117+
Self::Internal(InternalError(e)) => e.fmt(f),
118+
}
119+
}
120+
}
99121

100-
match &self.0 {
122+
impl std::fmt::Display for InternalErrorInner {
123+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
124+
use InternalErrorInner::*;
125+
126+
match &self {
101127
Reqwest(e) => e.fmt(f),
102128
ParseUrl(e) => e.fmt(f),
103129
Io(e) => e.fmt(f),
104130
InvalidOhttpKeys(e) => {
105131
write!(f, "Invalid ohttp keys returned from payjoin directory: {e}")
106132
}
107-
UnexpectedStatusCode(code) => {
108-
write!(f, "Unexpected status code from payjoin directory: {code}")
109-
}
110133
#[cfg(feature = "_danger-local-https")]
111134
Rustls(e) => e.fmt(f),
112135
}
@@ -115,22 +138,34 @@ impl std::fmt::Display for Error {
115138

116139
impl std::error::Error for Error {
117140
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
118-
use InternalError::*;
141+
match self {
142+
Self::Internal(InternalError(e)) => e.source(),
143+
Self::UnexpectedStatusCode(_) => None,
144+
}
145+
}
146+
}
147+
148+
impl std::error::Error for InternalErrorInner {
149+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
150+
use InternalErrorInner::*;
119151

120-
match &self.0 {
152+
match self {
121153
Reqwest(e) => Some(e),
122154
ParseUrl(e) => Some(e),
123155
Io(e) => Some(e),
124156
InvalidOhttpKeys(_) => None,
125-
UnexpectedStatusCode(_) => None,
126157
#[cfg(feature = "_danger-local-https")]
127158
Rustls(e) => Some(e),
128159
}
129160
}
130161
}
131162

132163
impl From<InternalError> for Error {
133-
fn from(value: InternalError) -> Self { Self(value) }
164+
fn from(value: InternalError) -> Self { Self::Internal(value) }
165+
}
166+
167+
impl From<InternalErrorInner> for Error {
168+
fn from(value: InternalErrorInner) -> Self { Self::Internal(InternalError(value)) }
134169
}
135170

136171
#[cfg(test)]
@@ -170,7 +205,7 @@ mod tests {
170205
for status in error_codes {
171206
let response = mock_response(status, vec![]);
172207
match parse_ohttp_keys_response(response).await {
173-
Err(Error(InternalError::UnexpectedStatusCode(code))) => assert_eq!(code, status),
208+
Err(Error::UnexpectedStatusCode(code)) => assert_eq!(code, status),
174209
result => panic!(
175210
"Expected UnexpectedStatusCode error for status code: {status}, got: {result:?}"
176211
),
@@ -188,7 +223,7 @@ mod tests {
188223
assert!(
189224
matches!(
190225
parse_ohttp_keys_response(response).await,
191-
Err(Error(InternalError::InvalidOhttpKeys(_)))
226+
Err(Error::Internal(InternalError(InternalErrorInner::InvalidOhttpKeys(_))))
192227
),
193228
"expected InvalidOhttpKeys error"
194229
);

0 commit comments

Comments
 (0)