Skip to content

Commit 2e8931a

Browse files
committed
RUST-739 Stop re-exporting unstable types in ErrorKind
This also consolidates various redundant error cases.
1 parent 7b0da51 commit 2e8931a

File tree

11 files changed

+105
-128
lines changed

11 files changed

+105
-128
lines changed

src/client/options/mod.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -149,22 +149,28 @@ impl StreamAddress {
149149
let hostname = match parts.next() {
150150
Some(part) => part,
151151
None => {
152-
return Err(ErrorKind::InvalidHostname {
153-
hostname: address.to_string(),
152+
return Err(ErrorKind::ArgumentError {
153+
message: format!("invalid server address: \"{}\"", address),
154154
}
155155
.into())
156156
}
157157
};
158158

159159
let port = match parts.next() {
160160
Some(part) => {
161-
let port = u16::from_str(part).map_err(|_| ErrorKind::InvalidHostname {
162-
hostname: address.to_string(),
161+
let port = u16::from_str(part).map_err(|_| ErrorKind::ArgumentError {
162+
message: format!(
163+
"port must be valid 16-bit unsigned integer, instead got: {}",
164+
part
165+
),
163166
})?;
164167

165168
if parts.next().is_some() {
166-
return Err(ErrorKind::InvalidHostname {
167-
hostname: address.to_string(),
169+
return Err(ErrorKind::ArgumentError {
170+
message: format!(
171+
"address \"{}\" contains more than one unescaped ':'",
172+
address
173+
),
168174
}
169175
.into());
170176
}
@@ -592,9 +598,8 @@ impl TlsOptions {
592598
if let Some(path) = self.ca_file_path {
593599
store
594600
.add_pem_file(&mut BufReader::new(File::open(&path)?))
595-
.map_err(|_| ErrorKind::ParseError {
596-
data_type: "PEM-encoded root certificate".to_string(),
597-
file_path: path,
601+
.map_err(|_| ErrorKind::TlsConfigError {
602+
message: format!("Unable to parse PEM-encoded root certificate from {}", path),
598603
})?;
599604
} else {
600605
store.add_server_trust_anchors(&TLS_SERVER_ROOTS);
@@ -607,9 +612,11 @@ impl TlsOptions {
607612
let certs = match pemfile::certs(&mut file) {
608613
Ok(certs) => certs,
609614
Err(()) => {
610-
return Err(ErrorKind::ParseError {
611-
data_type: "PEM-encoded client certificate".to_string(),
612-
file_path: path,
615+
return Err(ErrorKind::TlsConfigError {
616+
message: format!(
617+
"Unable to parse PEM-encoded client certificate from {}",
618+
path
619+
),
613620
}
614621
.into())
615622
}
@@ -619,16 +626,19 @@ impl TlsOptions {
619626
let key = match pemfile::rsa_private_keys(&mut file) {
620627
Ok(key) => key,
621628
Err(()) => {
622-
return Err(ErrorKind::ParseError {
623-
data_type: "PEM-encoded RSA key".to_string(),
624-
file_path: path,
629+
return Err(ErrorKind::TlsConfigError {
630+
message: format!("Unable to parse PEM-encoded RSA key from {}", path),
625631
}
626632
.into())
627633
}
628634
};
629635

630636
// TODO: Get rid of unwrap.
631-
config.set_single_client_cert(certs, key.into_iter().next().unwrap())?;
637+
config
638+
.set_single_client_cert(certs, key.into_iter().next().unwrap())
639+
.map_err(|e| ErrorKind::TlsConfigError {
640+
message: e.to_string(),
641+
})?;
632642
}
633643

634644
Ok(config)

src/cmap/conn/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ impl Connection {
256256
/// Gets the connection's StreamDescription.
257257
pub(crate) fn stream_description(&self) -> Result<&StreamDescription> {
258258
self.stream_description.as_ref().ok_or_else(|| {
259-
ErrorKind::OperationError {
259+
ErrorKind::InternalError {
260260
message: "Stream checked out but not handshaked".to_string(),
261261
}
262262
.into()

src/cmap/conn/wire/header.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl OpCode {
1818
1 => Ok(OpCode::Reply),
1919
2004 => Ok(OpCode::Query),
2020
2013 => Ok(OpCode::Message),
21-
other => Err(ErrorKind::OperationError {
21+
other => Err(ErrorKind::ResponseError {
2222
message: format!("Invalid wire protocol opcode: {}", other),
2323
}
2424
.into()),

src/cmap/conn/wire/message.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl Message {
9090
if length_remaining == 4 && flags.contains(MessageFlags::CHECKSUM_PRESENT) {
9191
checksum = Some(reader.read_u32().await?);
9292
} else if length_remaining != 0 {
93-
return Err(ErrorKind::OperationError {
93+
return Err(ErrorKind::ResponseError {
9494
message: format!(
9595
"The server indicated that the reply would be {} bytes long, but it instead \
9696
was {}",
@@ -193,7 +193,7 @@ impl MessageSection {
193193
}
194194

195195
if length_remaining != count_reader.bytes_read() as i32 {
196-
return Err(ErrorKind::OperationError {
196+
return Err(ErrorKind::ResponseError {
197197
message: format!(
198198
"The server indicated that the reply would be {} bytes long, but it instead \
199199
was {}",

src/cmap/establish/handshake/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ impl From<ClientOptions> for HandshakerOptions {
278278
/// If the given command is not an isMaster, this function will return an error.
279279
pub(crate) async fn is_master(command: Command, conn: &mut Connection) -> Result<IsMasterReply> {
280280
if !command.name.eq_ignore_ascii_case("ismaster") {
281-
return Err(ErrorKind::OperationError {
281+
return Err(ErrorKind::InternalError {
282282
message: format!("invalid ismaster command: {}", command.name),
283283
}
284284
.into());

src/error.rs

Lines changed: 12 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ impl Error {
189189
}
190190
}
191191
}
192+
193+
pub(crate) fn from_resolve_error(error: trust_dns_resolver::error::ResolveError) -> Self {
194+
ErrorKind::DnsResolveError { message: error.to_string() }.into()
195+
}
192196
}
193197

194198
impl<E> From<E> for Error
@@ -240,12 +244,8 @@ impl std::ops::Deref for Error {
240244
#[derive(Clone, Debug, Error)]
241245
#[non_exhaustive]
242246
pub enum ErrorKind {
243-
/// Wrapper around [`std::net::AddrParseError`](https://doc.rust-lang.org/std/net/struct.AddrParseError.html).
244-
#[error("{0}")]
245-
AddrParse(#[from] std::net::AddrParseError),
246-
247-
/// An invalid argument was provided to a database operation.
248-
#[error("An invalid argument was provided to a database operation: {message}")]
247+
/// An invalid argument was provided.
248+
#[error("An invalid argument was provided: {message}")]
249249
#[non_exhaustive]
250250
ArgumentError { message: String },
251251

@@ -271,45 +271,19 @@ pub enum ErrorKind {
271271
#[error("Command failed {0}")]
272272
CommandError(CommandError),
273273

274-
// `trust_dns` does not implement the `Error` trait on their errors, so we have to manually
275-
// implement `From` rather than using the `source annotation.
276-
/// Wrapper around `trust_dns_resolver::error::ResolveError`.
277-
#[error("{0}")]
278-
DnsResolve(trust_dns_resolver::error::ResolveError),
274+
/// An error occurred during DNS resolution.
275+
#[error("An error occurred during DNS resolution: {message}")]
276+
#[non_exhaustive]
277+
DnsResolveError { message: String },
279278

280279
#[error("Internal error: {message}")]
281280
#[non_exhaustive]
282281
InternalError { message: String },
283282

284-
/// Wrapper around `webpki::InvalidDNSNameError`.
285-
#[error("{0}")]
286-
InvalidDnsName(#[from] webpki::InvalidDNSNameError),
287-
288-
/// A hostname could not be parsed.
289-
#[error("Unable to parse hostname: {hostname}")]
290-
#[non_exhaustive]
291-
InvalidHostname { hostname: String },
292-
293283
/// Wrapper around [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html).
294284
#[error("{0}")]
295285
Io(Arc<std::io::Error>),
296286

297-
#[error("No DNS results for domain {0}")]
298-
NoDnsResults(StreamAddress),
299-
300-
/// A database operation failed to send or receive a reply.
301-
#[error("A database operation failed to send or receive a reply: {message}")]
302-
#[non_exhaustive]
303-
OperationError { message: String },
304-
305-
/// Data from a file could not be parsed.
306-
#[error("Unable to parse {data_type} data from {file_path}")]
307-
#[non_exhaustive]
308-
ParseError {
309-
data_type: String,
310-
file_path: String,
311-
},
312-
313287
/// The connection pool for a server was cleared during operation execution due to
314288
/// a concurrent error, causing the operation to fail.
315289
#[error("{message}")]
@@ -326,22 +300,13 @@ pub enum ErrorKind {
326300
#[non_exhaustive]
327301
ServerSelectionError { message: String },
328302

329-
/// An error occurred during SRV record lookup.
330-
#[error("An error occurred during SRV record lookup: {message}")]
331-
#[non_exhaustive]
332-
SrvLookupError { message: String },
333-
334303
/// The Client does not support sessions.
335304
#[error("Attempted to start a session on a deployment that does not support sessions")]
336305
SessionsNotSupported,
337306

338-
#[error("{0}")]
339-
RustlsConfig(#[from] rustls::TLSError),
340-
341-
/// An error occurred during TXT record lookup
342-
#[error("An error occurred during TXT record lookup: {message}")]
307+
#[error("{message}")]
343308
#[non_exhaustive]
344-
TxtLookupError { message: String },
309+
TlsConfigError { message: String },
345310

346311
/// The Client timed out while checking out a connection from connection pool.
347312
#[error(
@@ -355,12 +320,6 @@ pub enum ErrorKind {
355320
WriteError(WriteFailure),
356321
}
357322

358-
impl From<trust_dns_resolver::error::ResolveError> for ErrorKind {
359-
fn from(error: trust_dns_resolver::error::ResolveError) -> Self {
360-
Self::DnsResolve(error)
361-
}
362-
}
363-
364323
impl ErrorKind {
365324
pub(crate) fn is_non_timeout_network_error(&self) -> bool {
366325
matches!(self, ErrorKind::Io(ref io_err) if io_err.kind() != std::io::ErrorKind::TimedOut)

src/operation/find_and_modify/mod.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -103,24 +103,13 @@ where
103103
const NAME: &'static str = "findAndModify";
104104

105105
fn build(&self, description: &StreamDescription) -> Result<Command> {
106-
if self.options.hint.is_some() {
107-
match description.max_wire_version {
108-
Some(version) if version < 8 => {
109-
return Err(ErrorKind::OperationError {
110-
message: "Specifying a hint is not supported on server versions < 4.4"
111-
.to_string(),
112-
}
113-
.into());
114-
}
115-
None => {
116-
return Err(ErrorKind::OperationError {
117-
message: "Specifying a hint is not supported on server versions < 4.4"
118-
.to_string(),
119-
}
120-
.into());
121-
}
122-
_ => {}
106+
if self.options.hint.is_some() && description.max_wire_version.unwrap_or(0) < 8 {
107+
return Err(ErrorKind::ArgumentError {
108+
message: "Specifying a hint to find_one_and_x is not supported on server versions \
109+
< 4.4"
110+
.to_string(),
123111
}
112+
.into());
124113
}
125114

126115
let mut body: Document = doc! {

src/operation/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ pub(crate) trait Operation {
107107

108108
/// Appends a serializable struct to the input document.
109109
/// The serializable struct MUST serialize to a Document, otherwise an error will be thrown.
110-
pub(crate) fn append_options<T: Serialize>(doc: &mut Document, options: Option<&T>) -> Result<()> {
110+
pub(crate) fn append_options<T: Serialize + Debug>(
111+
doc: &mut Document,
112+
options: Option<&T>,
113+
) -> Result<()> {
111114
match options {
112115
Some(options) => {
113116
let temp_doc = bson::to_bson(options)?;
@@ -116,8 +119,8 @@ pub(crate) fn append_options<T: Serialize>(doc: &mut Document, options: Option<&
116119
doc.extend(d);
117120
Ok(())
118121
}
119-
_ => Err(ErrorKind::OperationError {
120-
message: "options did not serialize to a Document".to_string(),
122+
_ => Err(ErrorKind::InternalError {
123+
message: format!("options did not serialize to a Document: {:?}", options),
121124
}
122125
.into()),
123126
}

src/runtime/resolver.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use trust_dns_resolver::{
22
config::ResolverConfig,
3+
error::ResolveErrorKind,
34
lookup::{SrvLookup, TxtLookup},
45
IntoName,
56
};
67

7-
use crate::error::Result;
8+
use crate::error::{Error, Result};
89

910
/// An async runtime agnostic DNS resolver.
1011
pub(crate) struct AsyncResolver {
@@ -20,15 +21,21 @@ impl AsyncResolver {
2021
#[cfg(feature = "tokio-runtime")]
2122
let resolver = match config {
2223
Some(config) => {
23-
trust_dns_resolver::TokioAsyncResolver::tokio(config, Default::default())?
24+
trust_dns_resolver::TokioAsyncResolver::tokio(config, Default::default())
25+
.map_err(Error::from_resolve_error)?
2426
}
25-
None => trust_dns_resolver::TokioAsyncResolver::tokio_from_system_conf()?,
27+
None => trust_dns_resolver::TokioAsyncResolver::tokio_from_system_conf()
28+
.map_err(Error::from_resolve_error)?,
2629
};
2730

2831
#[cfg(feature = "async-std-runtime")]
2932
let resolver = match config {
30-
Some(config) => async_std_resolver::resolver(config, Default::default()).await?,
31-
None => async_std_resolver::resolver_from_system_conf().await?,
33+
Some(config) => async_std_resolver::resolver(config, Default::default())
34+
.await
35+
.map_err(Error::from_resolve_error)?,
36+
None => async_std_resolver::resolver_from_system_conf()
37+
.await
38+
.map_err(Error::from_resolve_error)?,
3239
};
3340

3441
Ok(Self { resolver })
@@ -37,12 +44,22 @@ impl AsyncResolver {
3744

3845
impl AsyncResolver {
3946
pub async fn srv_lookup<N: IntoName>(&self, query: N) -> Result<SrvLookup> {
40-
let lookup = self.resolver.srv_lookup(query).await?;
47+
let lookup = self
48+
.resolver
49+
.srv_lookup(query)
50+
.await
51+
.map_err(Error::from_resolve_error)?;
4152
Ok(lookup)
4253
}
4354

44-
pub async fn txt_lookup<N: IntoName>(&self, query: N) -> Result<TxtLookup> {
45-
let lookup = self.resolver.txt_lookup(query).await?;
46-
Ok(lookup)
55+
pub async fn txt_lookup<N: IntoName>(&self, query: N) -> Result<Option<TxtLookup>> {
56+
let lookup_result = self.resolver.txt_lookup(query).await;
57+
match lookup_result {
58+
Ok(lookup) => Ok(Some(lookup)),
59+
Err(e) => match e.kind() {
60+
ResolveErrorKind::NoRecordsFound { .. } => Ok(None),
61+
_ => Err(Error::from_resolve_error(e)),
62+
},
63+
}
4764
}
4865
}

0 commit comments

Comments
 (0)