diff --git a/src/address/envelope.rs b/src/address/envelope.rs index 3a4aae1..3a706dd 100644 --- a/src/address/envelope.rs +++ b/src/address/envelope.rs @@ -29,7 +29,7 @@ pub struct Envelope { mod serde_forward_path { use super::Address; /// dummy type required for serde - /// see example: https://serde.rs/deserialize-map.html + /// see example: struct CustomVisitor; impl<'de> serde::de::Visitor<'de> for CustomVisitor { type Value = Vec
; diff --git a/src/lib.rs b/src/lib.rs index 345e942..b31f9e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,7 +149,14 @@ clippy::wildcard_imports, clippy::str_to_string, clippy::empty_structs_with_brackets, - clippy::zero_sized_map_values + clippy::zero_sized_map_values, + clippy::manual_let_else, + clippy::semicolon_if_nothing_returned, + clippy::unnecessary_wraps, + clippy::doc_markdown, + clippy::explicit_iter_loop, + clippy::redundant_closure_for_method_calls, + // Rust 1.86: clippy::unnecessary_semicolon, )] #![cfg_attr(docsrs, feature(doc_cfg))] diff --git a/src/message/dkim.rs b/src/message/dkim.rs index bb38b52..cfb3c90 100644 --- a/src/message/dkim.rs +++ b/src/message/dkim.rs @@ -69,7 +69,7 @@ impl Display for DkimSigningAlgorithm { } } -/// Describe DkimSigning key error +/// Describe [`DkimSigning`] key error #[derive(Debug)] pub struct DkimSigningKeyError(InnerDkimSigningKeyError); @@ -100,7 +100,7 @@ impl StdError for DkimSigningKeyError { } } -/// Describe a signing key to be carried by DkimConfig struct +/// Describe a signing key to be carried by [`DkimConfig`] struct #[derive(Debug)] pub struct DkimSigningKey(InnerDkimSigningKey); @@ -183,7 +183,7 @@ impl DkimConfig { } } - /// Create a DkimConfig + /// Create a [`DkimConfig`] pub fn new( selector: String, domain: String, @@ -283,19 +283,19 @@ fn dkim_canonicalize_headers_relaxed(headers: &str) -> String { // End of header. [b'\r', b'\n', ..] => { *out += "\r\n"; - name(&h[2..], out) + name(&h[2..], out); } // Sequential whitespace. [b' ' | b'\t', b' ' | b'\t' | b'\r', ..] => value(&h[1..], out), // All whitespace becomes spaces. [b'\t', ..] => { out.push(' '); - value(&h[1..], out) + value(&h[1..], out); } [_, ..] => { let mut chars = h.chars(); out.push(chars.next().unwrap()); - value(chars.as_str(), out) + value(chars.as_str(), out); } [] => {} } @@ -317,7 +317,7 @@ fn dkim_canonicalize_header_tag( } } -/// Canonicalize signed headers passed as headers_list among mail_headers using canonicalization +/// Canonicalize signed headers passed as `headers_list` among `mail_headers` using canonicalization fn dkim_canonicalize_headers<'a>( headers_list: impl IntoIterator, mail_headers: &Headers, @@ -344,9 +344,9 @@ fn dkim_canonicalize_headers<'a>( } /// Sign with Dkim a message by adding Dkim-Signature header created with configuration expressed by -/// dkim_config +/// `dkim_config` pub fn dkim_sign(message: &mut Message, dkim_config: &DkimConfig) { - dkim_sign_fixed_time(message, dkim_config, SystemTime::now()) + dkim_sign_fixed_time(message, dkim_config, SystemTime::now()); } fn dkim_sign_fixed_time(message: &mut Message, dkim_config: &DkimConfig, timestamp: SystemTime) { @@ -377,7 +377,7 @@ fn dkim_sign_fixed_time(message: &mut Message, dkim_config: &DkimConfig, timesta } let dkim_header = dkim_header_format(dkim_config, timestamp, &signed_headers_list, &bh, ""); let signed_headers = dkim_canonicalize_headers( - dkim_config.headers.iter().map(|h| h.as_ref()), + dkim_config.headers.iter().map(AsRef::as_ref), headers, dkim_config.canonicalization.header, ); @@ -487,14 +487,14 @@ cJ5Ku0OTwRtSMaseRPX+T4EfG1Caa/eunPPN4rh+CSup2BVVarOT fn test_headers_simple_canonicalize() { let message = test_message(); dbg!(message.headers.to_string()); - assert_eq!(dkim_canonicalize_headers(["From", "Test"], &message.headers, DkimCanonicalizationType::Simple), "From: =?utf-8?b?VGVzdCBPJ0xlYXJ5?= \r\nTest: test test very very long with spaces and extra spaces \twill be\r\n folded to several lines \r\n") + assert_eq!(dkim_canonicalize_headers(["From", "Test"], &message.headers, DkimCanonicalizationType::Simple), "From: =?utf-8?b?VGVzdCBPJ0xlYXJ5?= \r\nTest: test test very very long with spaces and extra spaces \twill be\r\n folded to several lines \r\n"); } #[test] fn test_headers_relaxed_canonicalize() { let message = test_message(); dbg!(message.headers.to_string()); - assert_eq!(dkim_canonicalize_headers(["From", "Test"], &message.headers, DkimCanonicalizationType::Relaxed),"from:=?utf-8?b?VGVzdCBPJ0xlYXJ5?= \r\ntest:test test very very long with spaces and extra spaces will be folded to several lines\r\n") + assert_eq!(dkim_canonicalize_headers(["From", "Test"], &message.headers, DkimCanonicalizationType::Relaxed),"from:=?utf-8?b?VGVzdCBPJ0xlYXJ5?= \r\ntest:test test very very long with spaces and extra spaces will be folded to several lines\r\n"); } #[test] diff --git a/src/message/header/mod.rs b/src/message/header/mod.rs index 12ac6e7..89ae3b1 100644 --- a/src/message/header/mod.rs +++ b/src/message/header/mod.rs @@ -415,7 +415,7 @@ mod tests { #[test] fn empty_headername() { - assert!(HeaderName::new_from_ascii(String::from("")).is_err()); + assert!(HeaderName::new_from_ascii("".to_owned()).is_err()); } #[test] diff --git a/src/message/mailbox/types.rs b/src/message/mailbox/types.rs index f533333..16ef53b 100644 --- a/src/message/mailbox/types.rs +++ b/src/message/mailbox/types.rs @@ -351,7 +351,7 @@ impl FromStr for Mailboxes { })?; for (name, (user, domain)) in parsed_mailboxes { - mailboxes.push(Mailbox::new(name, Address::new(user, domain)?)) + mailboxes.push(Mailbox::new(name, Address::new(user, domain)?)); } Ok(Mailboxes(mailboxes)) @@ -531,7 +531,7 @@ mod test { assert_eq!( format!( "{}", - Mailbox::new(Some("".into()), "kayo@example.com".parse().unwrap()) + Mailbox::new(Some("".to_owned()), "kayo@example.com".parse().unwrap()) ), "kayo@example.com" ); diff --git a/src/message/mod.rs b/src/message/mod.rs index b45d07a..442160d 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -527,7 +527,7 @@ impl Message { match &self.body { MessageBody::Mime(p) => p.format_body(&mut out), MessageBody::Raw(r) => out.extend_from_slice(r), - }; + } out.extend_from_slice(b"\r\n"); out } @@ -605,7 +605,7 @@ impl EmailFormat for Message { MessageBody::Mime(p) => p.format(out), MessageBody::Raw(r) => { out.extend_from_slice(b"\r\n"); - out.extend_from_slice(r) + out.extend_from_slice(r); } } } @@ -769,7 +769,7 @@ mod test { continue; } - assert_eq!(line.0, line.1) + assert_eq!(line.0, line.1); } } diff --git a/src/transport/file/error.rs b/src/transport/file/error.rs index 06e2bd5..7e0f6e8 100644 --- a/src/transport/file/error.rs +++ b/src/transport/file/error.rs @@ -68,7 +68,7 @@ impl fmt::Display for Error { Kind::Io => f.write_str("response error")?, #[cfg(feature = "file-transport-envelope")] Kind::Envelope => f.write_str("internal client error")?, - }; + } if let Some(e) = &self.inner.source { write!(f, ": {e}")?; diff --git a/src/transport/sendmail/error.rs b/src/transport/sendmail/error.rs index d812d85..2db4591 100644 --- a/src/transport/sendmail/error.rs +++ b/src/transport/sendmail/error.rs @@ -65,7 +65,7 @@ impl fmt::Display for Error { match self.inner.kind { Kind::Response => f.write_str("response error")?, Kind::Client => f.write_str("internal client error")?, - }; + } if let Some(e) = &self.inner.source { write!(f, ": {e}")?; diff --git a/src/transport/sendmail/mod.rs b/src/transport/sendmail/mod.rs index 0fb7709..6a35111 100644 --- a/src/transport/sendmail/mod.rs +++ b/src/transport/sendmail/mod.rs @@ -123,7 +123,7 @@ impl SendmailTransport { /// Creates a new transport with the `sendmail` command /// /// Note: This uses the `sendmail` command in the current `PATH`. To use another command, - /// use [SendmailTransport::new_with_command]. + /// use [`SendmailTransport::new_with_command`]. pub fn new() -> SendmailTransport { SendmailTransport { command: DEFAULT_SENDMAIL.into(), @@ -160,7 +160,7 @@ where /// Creates a new transport with the `sendmail` command /// /// Note: This uses the `sendmail` command in the current `PATH`. To use another command, - /// use [AsyncSendmailTransport::new_with_command]. + /// use [`AsyncSendmailTransport::new_with_command`]. pub fn new() -> Self { Self { inner: SendmailTransport::new(), diff --git a/src/transport/smtp/client/async_net.rs b/src/transport/smtp/client/async_net.rs index b9e89c5..7343387 100644 --- a/src/transport/smtp/client/async_net.rs +++ b/src/transport/smtp/client/async_net.rs @@ -170,7 +170,7 @@ impl AsyncNetworkStream { last_err = Some(io::Error::new( io::ErrorKind::TimedOut, "connection timed out", - )) + )); } } } else { @@ -222,7 +222,7 @@ impl AsyncNetworkStream { last_err = Some(io::Error::new( io::ErrorKind::TimedOut, "connection timed out", - )) + )); } } } @@ -270,9 +270,8 @@ impl AsyncNetworkStream { InnerAsyncNetworkStream::Tokio1Tcp(_) => { // get owned TcpStream let tcp_stream = mem::replace(&mut self.inner, InnerAsyncNetworkStream::None); - let tcp_stream = match tcp_stream { - InnerAsyncNetworkStream::Tokio1Tcp(tcp_stream) => tcp_stream, - _ => unreachable!(), + let InnerAsyncNetworkStream::Tokio1Tcp(tcp_stream) = tcp_stream else { + unreachable!() }; self.inner = Self::upgrade_tokio1_tls(tcp_stream, tls_parameters) @@ -290,9 +289,8 @@ impl AsyncNetworkStream { InnerAsyncNetworkStream::AsyncStd1Tcp(_) => { // get owned TcpStream let tcp_stream = mem::replace(&mut self.inner, InnerAsyncNetworkStream::None); - let tcp_stream = match tcp_stream { - InnerAsyncNetworkStream::AsyncStd1Tcp(tcp_stream) => tcp_stream, - _ => unreachable!(), + let InnerAsyncNetworkStream::AsyncStd1Tcp(tcp_stream) = tcp_stream else { + unreachable!() }; self.inner = Self::upgrade_asyncstd1_tls(tcp_stream, tls_parameters) diff --git a/src/transport/smtp/client/net.rs b/src/transport/smtp/client/net.rs index 60304a7..4e7fae3 100644 --- a/src/transport/smtp/client/net.rs +++ b/src/transport/smtp/client/net.rs @@ -160,9 +160,8 @@ impl NetworkStream { InnerNetworkStream::Tcp(_) => { // get owned TcpStream let tcp_stream = mem::replace(&mut self.inner, InnerNetworkStream::None); - let tcp_stream = match tcp_stream { - InnerNetworkStream::Tcp(tcp_stream) => tcp_stream, - _ => unreachable!(), + let InnerNetworkStream::Tcp(tcp_stream) = tcp_stream else { + unreachable!() }; self.inner = Self::upgrade_tls_impl(tcp_stream, tls_parameters)?; diff --git a/src/transport/smtp/client/tls.rs b/src/transport/smtp/client/tls.rs index c96a207..215a917 100644 --- a/src/transport/smtp/client/tls.rs +++ b/src/transport/smtp/client/tls.rs @@ -423,7 +423,7 @@ impl TlsParametersBuilder { let mut root_cert_store = RootCertStore::empty(); #[cfg(feature = "rustls-native-certs")] - fn load_native_roots(store: &mut RootCertStore) -> Result<(), Error> { + fn load_native_roots(store: &mut RootCertStore) { let rustls_native_certs::CertificateResult { certs, errors, .. } = rustls_native_certs::load_native_certs(); let errors_len = errors.len(); @@ -433,7 +433,6 @@ impl TlsParametersBuilder { tracing::debug!( "loaded platform certs with {errors_len} failing to load, {added} valid and {ignored} ignored (invalid) certs" ); - Ok(()) } #[cfg(feature = "rustls-tls")] @@ -444,7 +443,7 @@ impl TlsParametersBuilder { match self.cert_store { CertificateStore::Default => { #[cfg(feature = "rustls-native-certs")] - load_native_roots(&mut root_cert_store)?; + load_native_roots(&mut root_cert_store); #[cfg(not(feature = "rustls-native-certs"))] load_webpki_roots(&mut root_cert_store); } @@ -662,10 +661,11 @@ impl Identity { #[cfg(feature = "rustls-tls")] fn from_pem_rustls_tls( pem: &[u8], - key: &[u8], + mut key: &[u8], ) -> Result<(Vec>, PrivateKeyDer<'static>), Error> { - let mut key = key; - let key = rustls_pemfile::private_key(&mut key).unwrap().unwrap(); + let key = rustls_pemfile::private_key(&mut key) + .map_err(error::tls)? + .ok_or_else(|| error::tls("no private key found"))?; Ok((vec![pem.to_owned().into()], key)) } diff --git a/src/transport/smtp/connection_url.rs b/src/transport/smtp/connection_url.rs index 13b5458..8084b05 100644 --- a/src/transport/smtp/connection_url.rs +++ b/src/transport/smtp/connection_url.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use url::Url; #[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] @@ -84,26 +86,26 @@ pub(crate) fn from_connection_url(connection_url: &str) -> ("smtp", Some("required")) => { builder = builder .port(connection_url.port().unwrap_or(SUBMISSION_PORT)) - .tls(Tls::Required(TlsParameters::new(host.into())?)) + .tls(Tls::Required(TlsParameters::new(host.into())?)); } #[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] ("smtp", Some("opportunistic")) => { builder = builder .port(connection_url.port().unwrap_or(SUBMISSION_PORT)) - .tls(Tls::Opportunistic(TlsParameters::new(host.into())?)) + .tls(Tls::Opportunistic(TlsParameters::new(host.into())?)); } #[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] ("smtps", _) => { builder = builder .port(connection_url.port().unwrap_or(SUBMISSIONS_PORT)) - .tls(Tls::Wrapper(TlsParameters::new(host.into())?)) + .tls(Tls::Wrapper(TlsParameters::new(host.into())?)); } (scheme, tls) => { return Err(error::connection(format!( "Unknown scheme '{scheme}' or tls parameter '{tls:?}', note that a transport with TLS requires one of the TLS features" ))) } - }; + } // use the path segment of the URL as name in the name in the HELO / EHLO command if connection_url.path().len() > 1 { @@ -115,7 +117,7 @@ pub(crate) fn from_connection_url(connection_url: &str) -> let percent_decode = |s: &str| { percent_encoding::percent_decode_str(s) .decode_utf8() - .map(|cow| cow.into_owned()) + .map(Cow::into_owned) .map_err(error::connection) }; let credentials = Credentials::new( diff --git a/src/transport/smtp/error.rs b/src/transport/smtp/error.rs index 49fa254..ca59cdc 100644 --- a/src/transport/smtp/error.rs +++ b/src/transport/smtp/error.rs @@ -142,7 +142,7 @@ impl fmt::Display for Error { Kind::Permanent(code) => { write!(f, "permanent error ({code})")?; } - }; + } if let Some(e) = &self.inner.source { write!(f, ": {e}")?; diff --git a/src/transport/smtp/extension.rs b/src/transport/smtp/extension.rs index 00026b9..ff5b4c4 100644 --- a/src/transport/smtp/extension.rs +++ b/src/transport/smtp/extension.rs @@ -129,9 +129,8 @@ impl Display for ServerInfo { impl ServerInfo { /// Parses a EHLO response to create a `ServerInfo` pub fn from_response(response: &Response) -> Result { - let name = match response.first_word() { - Some(name) => name, - None => return Err(error::response("Could not read server name")), + let Some(name) = response.first_word() else { + return Err(error::response("Could not read server name")); }; let mut features: HashSet = HashSet::new(); @@ -169,7 +168,7 @@ impl ServerInfo { } } _ => (), - }; + } } Ok(ServerInfo { diff --git a/src/transport/smtp/pool/async_impl.rs b/src/transport/smtp/pool/async_impl.rs index 732fb35..74ab614 100644 --- a/src/transport/smtp/pool/async_impl.rs +++ b/src/transport/smtp/pool/async_impl.rs @@ -109,7 +109,7 @@ impl Pool { #[cfg(feature = "tracing")] tracing::debug!("dropped {} idle connections", dropped.len()); - abort_concurrent(dropped.into_iter().map(|conn| conn.unpark())) + abort_concurrent(dropped.into_iter().map(ParkedConnection::unpark)) .await; } } @@ -229,7 +229,7 @@ impl Drop for Pool { handle.shutdown().await; } - abort_concurrent(connections.into_iter().map(|conn| conn.unpark())).await; + abort_concurrent(connections.into_iter().map(ParkedConnection::unpark)).await; }); } } diff --git a/src/transport/smtp/util.rs b/src/transport/smtp/util.rs index 17c17fc..51eb1b7 100644 --- a/src/transport/smtp/util.rs +++ b/src/transport/smtp/util.rs @@ -38,9 +38,7 @@ mod tests { ("bjørn", "bjørn"), ("Ø+= ❤️‰", "Ø+2B+3D+20❤️‰"), ("+", "+2B"), - ] - .iter() - { + ] { assert_eq!(format!("{}", XText(input)), (*expect).to_owned()); } }