From 6afdb0cf3a749bdc43eaa55283ce1d98605a4b99 Mon Sep 17 00:00:00 2001 From: Alexis Mousset Date: Tue, 5 May 2020 22:03:53 +0200 Subject: [PATCH] feat(transport): Make `Transport` result type an actual `Result` (fixes #405) --- src/lib.rs | 13 ++++++---- src/transport/file/error.rs | 5 ---- src/transport/file/mod.rs | 11 +++++--- src/transport/sendmail/error.rs | 3 --- src/transport/sendmail/mod.rs | 9 ++++--- src/transport/smtp/client/mod.rs | 18 ++++++++----- src/transport/smtp/error.rs | 3 --- src/transport/smtp/mod.rs | 10 +++++--- src/transport/stub/mod.rs | 44 ++++++++++++++++++++++++-------- tests/transport_stub.rs | 4 +-- 10 files changed, 72 insertions(+), 48 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e77a6c9..e193e2b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,8 @@ pub use crate::transport::smtp::{SmtpTransport, Tls}; pub use crate::transport::stub::StubTransport; #[cfg(feature = "builder")] use std::convert::TryFrom; +use std::error::Error as StdError; +use std::fmt; /// Simple email envelope representation /// @@ -117,17 +119,18 @@ impl TryFrom<&Headers> for Envelope { } /// Transport method for emails -pub trait Transport<'a> { - /// Result type for the transport - type Result; +pub trait Transport { + /// Result types for the transport + type Ok: fmt::Debug; + type Error: StdError; /// Sends the email - fn send(&self, message: &Message) -> Self::Result { + fn send(&self, message: &Message) -> Result { let raw = message.formatted(); self.send_raw(message.envelope(), &raw) } - fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result; + fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result; } #[cfg(test)] diff --git a/src/transport/file/error.rs b/src/transport/file/error.rs index 5fbbd04..572edbb 100644 --- a/src/transport/file/error.rs +++ b/src/transport/file/error.rs @@ -55,8 +55,3 @@ impl From<&'static str> for Error { Error::Client(string) } } - -type Id = String; - -/// SMTP result type -pub type FileResult = Result; diff --git a/src/transport/file/mod.rs b/src/transport/file/mod.rs index f7f2d32..c3d6fd7 100644 --- a/src/transport/file/mod.rs +++ b/src/transport/file/mod.rs @@ -35,7 +35,7 @@ //! TODO //! ``` -use crate::{transport::file::error::FileResult, Envelope, Transport}; +use crate::{transport::file::error::Error, Envelope, Transport}; use std::{ fs::File, io::prelude::*, @@ -46,6 +46,8 @@ use uuid::Uuid; pub mod error; +type Id = String; + /// Writes the content and the envelope information to a file #[derive(Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -70,10 +72,11 @@ struct SerializableEmail<'a> { message: Option<&'a str>, } -impl<'a> Transport<'a> for FileTransport { - type Result = FileResult; +impl Transport for FileTransport { + type Ok = Id; + type Error = Error; - fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result { + fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result { let email_id = Uuid::new_v4(); let mut file = self.path.clone(); diff --git a/src/transport/sendmail/error.rs b/src/transport/sendmail/error.rs index 975f726..1c09957 100644 --- a/src/transport/sendmail/error.rs +++ b/src/transport/sendmail/error.rs @@ -50,6 +50,3 @@ impl From for Error { Utf8Parsing(err) } } - -/// sendmail result type -pub type SendmailResult = Result<(), Error>; diff --git a/src/transport/sendmail/mod.rs b/src/transport/sendmail/mod.rs index 909c398..925f62b 100644 --- a/src/transport/sendmail/mod.rs +++ b/src/transport/sendmail/mod.rs @@ -23,7 +23,7 @@ //! # } //! ``` -use crate::{transport::sendmail::error::SendmailResult, Envelope, Transport}; +use crate::{transport::sendmail::error::Error, Envelope, Transport}; use std::{ convert::AsRef, io::prelude::*, @@ -55,10 +55,11 @@ impl SendmailTransport { } } -impl<'a> Transport<'a> for SendmailTransport { - type Result = SendmailResult; +impl Transport for SendmailTransport { + type Ok = (); + type Error = Error; - fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result { + fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result { // Spawn the sendmail command let mut process = Command::new(&self.command) .arg("-i") diff --git a/src/transport/smtp/client/mod.rs b/src/transport/smtp/client/mod.rs index b2eb1f2..c8fe50a 100644 --- a/src/transport/smtp/client/mod.rs +++ b/src/transport/smtp/client/mod.rs @@ -5,7 +5,7 @@ use crate::{ authentication::{Credentials, Mechanism}, client::net::{NetworkStream, TlsParameters}, commands::*, - error::{Error, SmtpResult}, + error::Error, extension::{ClientId, Extension, MailBodyParameter, MailParameter, ServerInfo}, response::Response, }, @@ -140,7 +140,7 @@ impl SmtpConnection { Ok(conn) } - pub fn send(&mut self, envelope: &Envelope, email: &[u8]) -> SmtpResult { + pub fn send(&mut self, envelope: &Envelope, email: &[u8]) -> Result { // Mail let mut mail_options = vec![]; @@ -210,7 +210,7 @@ impl SmtpConnection { Ok(()) } - pub fn quit(&mut self) -> SmtpResult { + pub fn quit(&mut self) -> Result { Ok(try_smtp!(self.command(Quit), self)) } @@ -244,7 +244,11 @@ impl SmtpConnection { } /// Sends an AUTH command with the given mechanism, and handles challenge if needed - pub fn auth(&mut self, mechanisms: &[Mechanism], credentials: &Credentials) -> SmtpResult { + pub fn auth( + &mut self, + mechanisms: &[Mechanism], + credentials: &Credentials, + ) -> Result { let mechanism = match self.server_info.get_auth_mechanism(mechanisms) { Some(m) => m, None => { @@ -278,7 +282,7 @@ impl SmtpConnection { } /// Sends the message content - pub fn message(&mut self, message: &[u8]) -> SmtpResult { + pub fn message(&mut self, message: &[u8]) -> Result { let mut out_buf: Vec = vec![]; let mut codec = ClientCodec::new(); codec.encode(message, &mut out_buf)?; @@ -288,7 +292,7 @@ impl SmtpConnection { } /// Sends an SMTP command - pub fn command(&mut self, command: C) -> SmtpResult { + pub fn command(&mut self, command: C) -> Result { self.write(command.to_string().as_bytes())?; self.read_response() } @@ -307,7 +311,7 @@ impl SmtpConnection { } /// Gets the SMTP response - pub fn read_response(&mut self) -> SmtpResult { + pub fn read_response(&mut self) -> Result { let mut raw_response = String::new(); let mut response = raw_response.parse::(); diff --git a/src/transport/smtp/error.rs b/src/transport/smtp/error.rs index 0652f11..edb311c 100644 --- a/src/transport/smtp/error.rs +++ b/src/transport/smtp/error.rs @@ -152,6 +152,3 @@ impl From<&'static str> for Error { Client(string) } } - -/// SMTP result type -pub type SmtpResult = Result; diff --git a/src/transport/smtp/mod.rs b/src/transport/smtp/mod.rs index 2afa932..a958a4d 100644 --- a/src/transport/smtp/mod.rs +++ b/src/transport/smtp/mod.rs @@ -182,8 +182,9 @@ use crate::{ transport::smtp::{ authentication::{Credentials, Mechanism, DEFAULT_MECHANISMS}, client::SmtpConnection, - error::{Error, SmtpResult}, + error::Error, extension::ClientId, + response::Response, }, Envelope, Transport, }; @@ -419,11 +420,12 @@ impl SmtpTransport { } } -impl<'a> Transport<'a> for SmtpTransport { - type Result = SmtpResult; +impl Transport for SmtpTransport { + type Ok = Response; + type Error = Error; /// Sends an email - fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result { + fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result { #[cfg(feature = "r2d2")] let mut conn: Box> = match self.pool { Some(ref p) => Box::new(p.get()?), diff --git a/src/transport/stub/mod.rs b/src/transport/stub/mod.rs index 50705cb..0fbd7e8 100644 --- a/src/transport/stub/mod.rs +++ b/src/transport/stub/mod.rs @@ -17,38 +17,60 @@ //! .body("Be happy!") //! .unwrap(); //! -//! let mut sender = StubTransport::new_positive(); +//! let mut sender = StubTransport::new_ok(); //! let result = sender.send(&email); //! assert!(result.is_ok()); //! ``` use crate::{Envelope, Transport}; +use std::error::Error as StdError; +use std::fmt; + +#[derive(Debug, Copy, Clone)] +pub struct Error; + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "stub error") + } +} + +impl StdError for Error { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + None + } +} /// This transport logs the message envelope and returns the given response #[derive(Debug, Clone, Copy)] pub struct StubTransport { - response: StubResult, + response: Result<(), Error>, } impl StubTransport { - /// Creates a new transport that always returns the given response - pub fn new(response: StubResult) -> StubTransport { + /// Creates aResult new transport that always returns the given response + pub fn new(response: Result<(), Error>) -> StubTransport { StubTransport { response } } /// Creates a new transport that always returns a success response - pub fn new_positive() -> StubTransport { + pub fn new_ok() -> StubTransport { StubTransport { response: Ok(()) } } + + /// Creates a new transport that always returns an error + pub fn new_error() -> StubTransport { + StubTransport { + response: Err(Error), + } + } } -/// SMTP result type -pub type StubResult = Result<(), ()>; +impl Transport for StubTransport { + type Ok = (); + type Error = Error; -impl<'a> Transport<'a> for StubTransport { - type Result = StubResult; - - fn send_raw(&self, _envelope: &Envelope, _email: &[u8]) -> Self::Result { + fn send_raw(&self, _envelope: &Envelope, _email: &[u8]) -> Result { self.response } } diff --git a/tests/transport_stub.rs b/tests/transport_stub.rs index 980c421..4d57348 100644 --- a/tests/transport_stub.rs +++ b/tests/transport_stub.rs @@ -2,8 +2,8 @@ use lettre::{transport::stub::StubTransport, Message, Transport}; #[test] fn stub_transport() { - let sender_ok = StubTransport::new_positive(); - let sender_ko = StubTransport::new(Err(())); + let sender_ok = StubTransport::new_ok(); + let sender_ko = StubTransport::new_error(); let email = Message::builder() .from("NoBody ".parse().unwrap()) .reply_to("Yuin ".parse().unwrap())