diff options
Diffstat (limited to 'internals/src/encoder')
-rw-r--r-- | internals/src/encoder/encodable.rs | 59 | ||||
-rw-r--r-- | internals/src/encoder/mod.rs | 751 | ||||
-rw-r--r-- | internals/src/encoder/trace.rs | 30 |
3 files changed, 428 insertions, 412 deletions
diff --git a/internals/src/encoder/encodable.rs b/internals/src/encoder/encodable.rs index ff1e29a..154fb0f 100644 --- a/internals/src/encoder/encodable.rs +++ b/internals/src/encoder/encodable.rs @@ -1,10 +1,10 @@ use std::any::{Any, TypeId}; use std::fmt::{self, Debug}; -use std::result::{ Result as StdResult }; +use std::result::Result as StdResult; use std::sync::Arc; -use ::error::EncodingError; -use super::{EncodingWriter}; +use super::EncodingWriter; +use error::EncodingError; // can not be moved to `super::traits` as it depends on the // EncodingWriter defined here @@ -13,7 +13,7 @@ use super::{EncodingWriter}; /// This trait can be turned into a trait object allowing runtime /// genericallity over the "components" if needed. pub trait EncodableInHeader: Send + Sync + Any + Debug { - fn encode(&self, encoder: &mut EncodingWriter) -> Result<(), EncodingError>; + fn encode(&self, encoder: &mut EncodingWriter) -> Result<(), EncodingError>; fn boxed_clone(&self) -> Box<EncodableInHeader>; @@ -25,17 +25,15 @@ pub trait EncodableInHeader: Send + Sync + Any + Debug { //TODO we now could use MOPA or similar crates impl EncodableInHeader { - #[inline(always)] pub fn is<T: EncodableInHeader>(&self) -> bool { EncodableInHeader::type_id(self) == TypeId::of::<T>() } - #[inline] pub fn downcast_ref<T: EncodableInHeader>(&self) -> Option<&T> { if self.is::<T>() { - Some( unsafe { &*( self as *const EncodableInHeader as *const T) } ) + Some(unsafe { &*(self as *const EncodableInHeader as *const T) }) } else { None } @@ -44,7 +42,7 @@ impl EncodableInHeader { #[inline] pub fn downcast_mut<T: EncodableInHeader>(&mut self) -> Option<&mut T> { if self.is::<T>() { - Some( unsafe { &mut *( self as *mut EncodableInHeader as *mut T) } ) + Some(unsafe { &mut *(self as *mut EncodableInHeader as *mut T) }) } else { None } @@ -52,37 +50,33 @@ impl EncodableInHeader { } impl Clone for Box<EncodableInHeader> { - fn clone(&self) -> Self { self.boxed_clone() } } - pub trait EncodableInHeaderBoxExt: Sized { fn downcast<T: EncodableInHeader>(self) -> StdResult<Box<T>, Self>; } impl EncodableInHeaderBoxExt for Box<EncodableInHeader> { - fn downcast<T: EncodableInHeader>(self) -> StdResult<Box<T>, Self> { if EncodableInHeader::is::<T>(&*self) { let ptr: *mut EncodableInHeader = Box::into_raw(self); - Ok( unsafe { Box::from_raw(ptr as *mut T) } ) + Ok(unsafe { Box::from_raw(ptr as *mut T) }) } else { - Err( self ) + Err(self) } } } -impl EncodableInHeaderBoxExt for Box<EncodableInHeader+Send> { - +impl EncodableInHeaderBoxExt for Box<EncodableInHeader + Send> { fn downcast<T: EncodableInHeader>(self) -> StdResult<Box<T>, Self> { if EncodableInHeader::is::<T>(&*self) { let ptr: *mut EncodableInHeader = Box::into_raw(self); - Ok( unsafe { Box::from_raw(ptr as *mut T) } ) + Ok(unsafe { Box::from_raw(ptr as *mut T) }) } else { - Err( self ) + Err(self) } } } @@ -92,14 +86,14 @@ impl EncodableInHeaderBoxExt for Box<EncodableInHeader+Send> { /// (Mainly used in the inside of tests.) #[macro_export] macro_rules! enc_func { - (|$enc:ident : &mut EncodingWriter| $block:block) => ({ + (|$enc:ident : &mut EncodingWriter| $block:block) => {{ use $crate::error::EncodingError; fn _anonym($enc: &mut EncodingWriter) -> Result<(), EncodingError> { $block } let fn_pointer = _anonym as fn(&mut EncodingWriter) -> Result<(), EncodingError>; $crate::encoder::EncodeFn::new(fn_pointer) - }); + }}; } type _EncodeFn = for<'a, 'b> fn(&'a mut EncodingWriter<'b>) -> Result<(), EncodingError>; @@ -115,7 +109,7 @@ impl EncodeFn { } impl EncodableInHeader for EncodeFn { - fn encode(&self, encoder: &mut EncodingWriter) -> Result<(), EncodingError> { + fn encode(&self, encoder: &mut EncodingWriter) -> Result<(), EncodingError> { (self.0)(encoder) } @@ -142,12 +136,12 @@ macro_rules! enc_closure { /// A wrapper for an closure making it implement `EncodableInHeader`. pub struct EncodeClosure<FN: 'static>(Arc<FN>) - where FN: Send + Sync + - for<'a, 'b> Fn(&'a mut EncodingWriter<'b>) -> Result<(), EncodingError>; +where + FN: Send + Sync + for<'a, 'b> Fn(&'a mut EncodingWriter<'b>) -> Result<(), EncodingError>; impl<FN: 'static> EncodeClosure<FN> - where FN: Send + Sync + - for<'a, 'b> Fn(&'a mut EncodingWriter<'b>) -> Result<(), EncodingError> +where + FN: Send + Sync + for<'a, 'b> Fn(&'a mut EncodingWriter<'b>) -> Result<(), EncodingError>, { pub fn new(closure: FN) -> Self { EncodeClosure(Arc::new(closure)) @@ -155,10 +149,10 @@ impl<FN: 'static> EncodeClosure<FN> } impl<FN: 'static> EncodableInHeader for EncodeClosure<FN> - where FN: Send + Sync + - for<'a, 'b> Fn(&'a mut EncodingWriter<'b>) -> Result<(), EncodingError> +where + FN: Send + Sync + for<'a, 'b> Fn(&'a mut EncodingWriter<'b>) -> Result<(), EncodingError>, { - fn encode(&self, encoder: &mut EncodingWriter) -> Result<(), EncodingError> { + fn encode(&self, encoder: &mut EncodingWriter) -> Result<(), EncodingError> { (self.0)(encoder) } @@ -168,20 +162,19 @@ impl<FN: 'static> EncodableInHeader for EncodeClosure<FN> } impl<FN: 'static> Clone for EncodeClosure<FN> - where FN: Send + Sync + - for<'a, 'b> Fn(&'a mut EncodingWriter<'b>) -> Result<(), EncodingError> +where + FN: Send + Sync + for<'a, 'b> Fn(&'a mut EncodingWriter<'b>) -> Result<(), EncodingError>, { fn clone(&self) -> Self { EncodeClosure(self.0.clone()) } } - impl<FN: 'static> Debug for EncodeClosure<FN> - where FN: Send + Sync + - for<'a, 'b> Fn(&'a mut EncodingWriter<'b>) -> Result<(), EncodingError> +where + FN: Send + Sync + for<'a, 'b> Fn(&'a mut EncodingWriter<'b>) -> Result<(), EncodingError>, { fn fmt(&self, fter: &mut fmt::Formatter) -> fmt::Result { write!(fter, "EncodeClosure(..)") } -}
\ No newline at end of file +} diff --git a/internals/src/encoder/mod.rs b/internals/src/encoder/mod.rs index 760da2f..61a710d 100644 --- a/internals/src/encoder/mod.rs +++ b/internals/src/encoder/mod.rs @@ -18,29 +18,22 @@ use std::borrow::Cow; use std::str; use failure::Fail; -use soft_ascii_string::{SoftAsciiStr, SoftAsciiChar}; +use soft_ascii_string::{SoftAsciiChar, SoftAsciiStr}; +use error::{EncodingError, EncodingErrorKind, UNKNOWN, US_ASCII, UTF_8}; use grammar::is_atext; -use ::utils::{ - is_utf8_continuation_byte, - vec_insert_bytes -}; -use ::MailType; -use ::error::{ - EncodingError, EncodingErrorKind, - UNKNOWN, UTF_8, US_ASCII -}; - -#[cfg(feature="traceing")] -#[cfg_attr(test, macro_use)] -mod trace; +use utils::{is_utf8_continuation_byte, vec_insert_bytes}; +use MailType; + #[cfg_attr(test, macro_use)] mod encodable; +#[cfg(feature = "traceing")] +#[cfg_attr(test, macro_use)] +mod trace; - -#[cfg(feature="traceing")] -pub use self::trace::*; pub use self::encodable::*; +#[cfg(feature = "traceing")] +pub use self::trace::*; /// as specified in RFC 5322 not including CRLF pub const LINE_LEN_SOFT_LIMIT: usize = 78; @@ -50,29 +43,27 @@ pub const LINE_LEN_HARD_LIMIT: usize = 998; pub const NEWLINE: &str = "\r\n"; pub const NEWLINE_WITH_SPACE: &str = "\r\n "; - /// EncodingBuffer for a Mail providing a buffer for encodable traits. pub struct EncodingBuffer { mail_type: MailType, buffer: Vec<u8>, - #[cfg(feature="traceing")] - pub trace: Vec<TraceToken> + #[cfg(feature = "traceing")] + pub trace: Vec<TraceToken>, } impl EncodingBuffer { - /// Create a new buffer only allowing input compatible with a the specified mail type. pub fn new(mail_type: MailType) -> Self { EncodingBuffer { mail_type, buffer: Vec::new(), - #[cfg(feature="traceing")] - trace: Vec::new() + #[cfg(feature = "traceing")] + trace: Vec::new(), } } /// Returns the mail type for which the buffer was created. - pub fn mail_type( &self ) -> MailType { + pub fn mail_type(&self) -> MailType { self.mail_type } @@ -80,11 +71,11 @@ impl EncodingBuffer { /// a mutable reference to the current string buffer /// pub fn writer(&mut self) -> EncodingWriter { - #[cfg(not(feature="traceing"))] + #[cfg(not(feature = "traceing"))] { EncodingWriter::new(self.mail_type, &mut self.buffer) } - #[cfg(feature="traceing")] + #[cfg(feature = "traceing")] { EncodingWriter::new(self.mail_type, &mut self.buffer, &mut self.trace) } @@ -98,27 +89,29 @@ impl EncodingBuffer { /// writes /// - if `func` succeeded `handle.finish_header()` is called pub fn write_header_line<FN>(&mut self, func: FN) -> Result<(), EncodingError> - where FN: FnOnce(&mut EncodingWriter) -> Result<(), EncodingError> + where + FN: FnOnce(&mut EncodingWriter) -> Result<(), EncodingError>, { - let mut handle = self.writer(); + let mut handle = self.writer(); match func(&mut handle) { Ok(()) => { handle.finish_header(); Ok(()) - }, + } Err(e) => { handle.undo_header(); Err(e) } } - } pub fn write_blank_line(&mut self) { //TODO/BENCH push_str vs. extends(&[u8]) self.buffer.extend(NEWLINE.as_bytes()); - #[cfg(feature="traceing")] - { self.trace.push(TraceToken::BlankLine); } + #[cfg(feature = "traceing")] + { + self.trace.push(TraceToken::BlankLine); + } } /// writes a body to the internal buffer, without verifying it's correctness @@ -142,16 +135,15 @@ impl EncodingBuffer { /// /// This can fail if a body does not contain valid utf8. pub fn as_str(&self) -> Result<&str, EncodingError> { - str::from_utf8(self.buffer.as_slice()) - .map_err(|err| { - EncodingError::from(( - err.context(EncodingErrorKind::InvalidTextEncoding { - expected_encoding: UTF_8, - got_encoding: UNKNOWN - }), - self.mail_type() - )) - }) + str::from_utf8(self.buffer.as_slice()).map_err(|err| { + EncodingError::from(( + err.context(EncodingErrorKind::InvalidTextEncoding { + expected_encoding: UTF_8, + got_encoding: UNKNOWN, + }), + self.mail_type(), + )) + }) } /// Converts the internal buffer into an utf-8 string if possible. @@ -168,10 +160,8 @@ impl EncodingBuffer { pub fn as_slice(&self) -> &[u8] { &self.buffer } - } - impl Into<Vec<u8>> for EncodingBuffer { fn into(self) -> Vec<u8> { self.buffer @@ -184,10 +174,14 @@ impl Into<(MailType, Vec<u8>)> for EncodingBuffer { } } -#[cfg(feature="traceing")] +#[cfg(feature = "traceing")] impl Into<(MailType, Vec<u8>, Vec<TraceToken>)> for EncodingBuffer { fn into(self) -> (MailType, Vec<u8>, Vec<TraceToken>) { - let EncodingBuffer { mail_type, buffer, trace } = self; + let EncodingBuffer { + mail_type, + buffer, + trace, + } = self; (mail_type, buffer, trace) } } @@ -211,7 +205,7 @@ impl Into<(MailType, Vec<u8>, Vec<TraceToken>)> for EncodingBuffer { /// pub struct EncodingWriter<'a> { buffer: &'a mut Vec<u8>, - #[cfg(feature="traceing")] + #[cfg(feature = "traceing")] trace: &'a mut Vec<TraceToken>, mail_type: MailType, line_start_idx: usize, @@ -228,16 +222,15 @@ pub struct EncodingWriter<'a> { /// represents if if a FWS was just marked (opt-FWS) or was written out last_fws_has_char: bool, header_start_idx: usize, - #[cfg(feature="traceing")] - trace_start_idx: usize + #[cfg(feature = "traceing")] + trace_start_idx: usize, } -#[cfg(feature="traceing")] +#[cfg(feature = "traceing")] impl<'a> Drop for EncodingWriter<'a> { - fn drop(&mut self) { use std::thread; - if !thread::panicking() && self.has_unfinished_parts() { + if !thread::panicking() && self.has_unfinished_parts() { // we really should panic as the back buffer i.e. the mail will contain // some partially written header which definitely is a bug panic!("dropped Handle which partially wrote header to back buffer (use `finish_header` or `discard`)") @@ -246,12 +239,8 @@ impl<'a> Drop for EncodingWriter<'a> { } impl<'inner> EncodingWriter<'inner> { - - #[cfg(not(feature="traceing"))] - fn new( - mail_type: MailType, - buffer: &'inner mut Vec<u8>, - ) -> Self { + #[cfg(not(feature = "traceing"))] + fn new(mail_type: MailType, buffer: &'inner mut Vec<u8>) -> Self { let start_idx = buffer.len(); EncodingWriter { buffer, @@ -266,11 +255,11 @@ impl<'inner> EncodingWriter<'inner> { } } - #[cfg(feature="traceing")] + #[cfg(feature = "traceing")] fn new( mail_type: MailType, buffer: &'inner mut Vec<u8>, - trace: &'inner mut Vec<TraceToken> + trace: &'inner mut Vec<TraceToken>, ) -> Self { let start_idx = buffer.len(); let trace_start_idx = trace.len(); @@ -285,7 +274,7 @@ impl<'inner> EncodingWriter<'inner> { content_before_fws: false, header_start_idx: start_idx, last_fws_has_char: false, - trace_start_idx + trace_start_idx, } } @@ -297,8 +286,10 @@ impl<'inner> EncodingWriter<'inner> { self.content_since_fws = false; self.content_before_fws = false; self.header_start_idx = start_idx; - #[cfg(feature="traceing")] - { self.trace_start_idx = self.trace.len(); } + #[cfg(feature = "traceing")] + { + self.trace_start_idx = self.trace.len(); + } } /// Returns true if this type thinks we are in the process of writing a header. @@ -331,8 +322,10 @@ impl<'inner> EncodingWriter<'inner> { /// # Trace (test build only) /// does push a `MarkFWS` Token pub fn mark_fws_pos(&mut self) { - #[cfg(feature="traceing")] - { self.trace.push(TraceToken::MarkFWS) } + #[cfg(feature = "traceing")] + { + self.trace.push(TraceToken::MarkFWS) + } self.content_before_fws |= self.content_since_fws; self.content_since_fws = false; self.last_fws_idx = self.buffer.len(); @@ -348,9 +341,11 @@ impl<'inner> EncodingWriter<'inner> { /// /// # Trace (test build only) /// does push `NowChar` and then can push `Text`,`CRLF` - pub fn write_char(&mut self, ch: SoftAsciiChar) -> Result<(), EncodingError> { - #[cfg(feature="traceing")] - { self.trace.push(TraceToken::NowChar) } + pub fn write_char(&mut self, ch: SoftAsciiChar) -> Result<(), EncodingError> { + #[cfg(feature = "traceing")] + { + self.trace.push(TraceToken::NowChar) + } let mut buffer = [0xff_u8; 4]; let ch: char = ch.into(); let slice = ch.encode_utf8(&mut buffer); @@ -372,13 +367,14 @@ impl<'inner> EncodingWriter<'inner> { /// # Trace (test build only) /// does push `NowStr` and then can push `Text`,`CRLF` /// - pub fn write_str(&mut self, s: &SoftAsciiStr) -> Result<(), EncodingError> { - #[cfg(feature="traceing")] - { self.trace.push(TraceToken::NowStr) } + pub fn write_str(&mut self, s: &SoftAsciiStr) -> Result<(), EncodingError> { + #[cfg(feature = "traceing")] + { + self.trace.push(TraceToken::NowStr) + } self.internal_write_str(s.as_str()) } - /// writes a utf8 str into a buffer for an internationalized mail /// /// # Error (ConditionalWriteResult) @@ -394,12 +390,15 @@ impl<'inner> EncodingWriter<'inner> { /// /// # Trace (test build only) /// does push `NowUtf8` and then can push `Text`,`CRLF` - pub fn write_if_utf8<'short>(&'short mut self, s: &str) - -> ConditionalWriteResult<'short, 'inner> - { + pub fn write_if_utf8<'short>( + &'short mut self, + s: &str, + ) -> ConditionalWriteResult<'short, 'inner> { if self.mail_type().is_internationalized() { - #[cfg(feature="traceing")] - { self.trace.push(TraceToken::NowUtf8) } + #[cfg(feature = "traceing")] + { + self.trace.push(TraceToken::NowUtf8) + } self.internal_write_str(s).into() } else { ConditionalWriteResult::ConditionFailure(self) @@ -408,16 +407,18 @@ impl<'inner> EncodingWriter<'inner> { pub fn write_utf8(&mut self, s: &str) -> Result<(), EncodingError> { if self.mail_type().is_internationalized() { - #[cfg(feature="traceing")] - { self.trace.push(TraceToken::NowUtf8) } + #[cfg(feature = "traceing")] + { + self.trace.push(TraceToken::NowUtf8) + } self.internal_write_str(s) } else { let mut err = EncodingError::from(( EncodingErrorKind::InvalidTextEncoding { expected_encoding: US_ASCII, - got_encoding: UTF_8 + got_encoding: UTF_8, }, - self.mail_type() + self.mail_type(), )); let raw_line = &self.buffer[self.line_start_idx..]; let mut line = String::from_utf8_lossy(raw_line).into_owned(); @@ -454,12 +455,15 @@ impl<'inner> EncodingWriter<'inner> { /// # Trace (test build only) /// does push `NowAText` and then can push `Text` /// - pub fn write_if_atext<'short>(&'short mut self, s: &str) - -> ConditionalWriteResult<'short, 'inner> - { - if s.chars().all( |ch| is_atext( ch, self.mail_type() ) ) { - #[cfg(feature="traceing")] - { self.trace.push(TraceToken::NowAText) } + pub fn write_if_atext<'short>( + &'short mut self, + s: &str, + ) -> ConditionalWriteResult<'short, 'inner> { + if s.chars().all(|ch| is_atext(ch, self.mail_type())) { + #[cfg(feature = "traceing")] + { + self.trace.push(TraceToken::NowAText) + } // the ascii or not aspect is already converted by `is_atext` self.internal_write_str(s).into() } else { @@ -471,13 +475,19 @@ impl<'inner> EncodingWriter<'inner> { /// then writes it _without additional checks_ to the buffer if `cond` returned /// true /// - pub fn write_if<'short, FN>(&'short mut self, s: &str, cond: FN) - -> ConditionalWriteResult<'short, 'inner> - where FN: FnOnce(&str) -> bool + pub fn write_if<'short, FN>( + &'short mut self, + s: &str, + cond: FN, + ) -> ConditionalWriteResult<'short, 'inner> + where + FN: FnOnce(&str) -> bool, { if cond(s) { - #[cfg(feature="traceing")] - { self.trace.push(TraceToken::NowCondText) } + #[cfg(feature = "traceing")] + { + self.trace.push(TraceToken::NowCondText) + } // the ascii or not aspect is already converted by `is_atext` self.internal_write_str(s).into() } else { @@ -509,9 +519,11 @@ impl<'inner> EncodingWriter<'inner> { /// /// through is gives a different tracing its roughly equivalent. /// - pub fn write_str_unchecked( &mut self, s: &str) -> Result<(), EncodingError> { - #[cfg(feature="traceing")] - { self.trace.push(TraceToken::NowUnchecked) } + pub fn write_str_unchecked(&mut self, s: &str) -> Result<(), EncodingError> { + #[cfg(feature = "traceing")] + { + self.trace.push(TraceToken::NowUnchecked) + } self.internal_write_str(s) } @@ -523,9 +535,13 @@ impl<'inner> EncodingWriter<'inner> { /// is written correctly. So you _normally_ should /// not use it. pub fn commit_partial_header(&mut self) { - #[cfg(feature="traceing")] - { if let Some(&TraceToken::End) = self.trace.last() {} - else { self.trace.push(TraceToken::End) } } + #[cfg(feature = "traceing")] + { + if let Some(&TraceToken::End) = self.trace.last() { + } else { + self.trace.push(TraceToken::End) + } + } self.reinit(); } @@ -548,9 +564,13 @@ impl<'inner> EncodingWriter<'inner> { /// will not generate multiple `End` tokens, just one pub fn finish_header(&mut self) { self.start_new_line(); - #[cfg(feature="traceing")] - { if let Some(&TraceToken::End) = self.trace.last() {} - else { self.trace.push(TraceToken::End) } } + #[cfg(feature = "traceing")] + { + if let Some(&TraceToken::End) = self.trace.last() { + } else { + self.trace.push(TraceToken::End) + } + } self.reinit(); } @@ -565,13 +585,13 @@ impl<'inner> EncodingWriter<'inner> { /// pub fn undo_header(&mut self) { self.buffer.truncate(self.header_start_idx); - #[cfg(feature="traceing")] - { self.trace.truncate(self.trace_start_idx); } + #[cfg(feature = "traceing")] + { + self.trace.truncate(self.trace_start_idx); + } self.reinit(); } - - //---------------------------------------------------------------------------------------------/ //-/////////////////////////// methods only using the public iface /////////////////////////-/ @@ -594,8 +614,6 @@ impl<'inner> EncodingWriter<'inner> { let _ = self.write_char(SoftAsciiChar::from_unchecked(' ')); } - - //---------------------------------------------------------------------------------------------/ //-/////////////////////////// private methods ////////////////////////-/ @@ -603,7 +621,7 @@ impl<'inner> EncodingWriter<'inner> { /// while we could implement a undo option it makes /// little sense for the use case the generally available /// `undo_header` is enough. - fn internal_write_str(&mut self, s: &str) -> Result<(), EncodingError> { + fn internal_write_str(&mut self, s: &str) -> Result<(), EncodingError> { if s.is_empty() { return Ok(()); } @@ -631,13 +649,15 @@ impl<'inner> EncodingWriter<'inner> { /// removing the blank line (not that WS are only ' ' and '\r') fn start_new_line(&mut self) { if self.line_has_content() { - #[cfg(feature="traceing")] - { self.trace.push(TraceToken::CRLF) } + #[cfg(feature = "traceing")] + { + self.trace.push(TraceToken::CRLF) + } self.buffer.push(b'\r'); self.buffer.push(b'\n'); } else { - #[cfg(feature="traceing")] + #[cfg(feature = "traceing")] { if self.buffer.len() > self.line_start_idx { self.trace.push(TraceToken::TruncateToCRLF); @@ -653,18 +673,16 @@ impl<'inner> EncodingWriter<'inner> { self.content_since_fws = false; self.content_before_fws = false; self.last_fws_idx = self.line_start_idx; - } fn break_line_on_fws(&mut self) -> bool { if self.content_before_fws && self.last_fws_idx > self.line_start_idx { - let newline = - if self.last_fws_has_char { - debug_assert!([b' ', b'\t'].contains(&self.buffer[self.last_fws_idx])); - NEWLINE - } else { - NEWLINE_WITH_SPACE - }; + let newline = if self.last_fws_has_char { + debug_assert!([b' ', b'\t'].contains(&self.buffer[self.last_fws_idx])); + NEWLINE + } else { + NEWLINE_WITH_SPACE + }; vec_insert_bytes(&mut self.buffer, self.last_fws_idx, newline.as_bytes()); self.line_start_idx = self.last_fws_idx + 2; @@ -732,7 +750,7 @@ impl<'inner> EncodingWriter<'inner> { } self.buffer.extend(unchecked_utf8_char.as_bytes()); - #[cfg(feature="traceing")] + #[cfg(feature = "traceing")] { //FIXME[rust/nll]: just use a `if let`-`else` with NLL's let need_new = @@ -747,7 +765,6 @@ impl<'inner> EncodingWriter<'inner> { string.push_str(unchecked_utf8_char); self.trace.push(TraceToken::Text(string)) } - } // we can't allow "blank" lines @@ -763,53 +780,47 @@ impl<'inner> EncodingWriter<'inner> { pub enum ConditionalWriteResult<'a, 'b: 'a> { Ok, ConditionFailure(&'a mut EncodingWriter<'b>), - GeneralFailure(EncodingError) + GeneralFailure(EncodingError), } impl<'a, 'b: 'a> From<Result<(), EncodingError>> for ConditionalWriteResult<'a, 'b> { fn from(v: Result<(), EncodingError>) -> Self { match v { Ok(()) => ConditionalWriteResult::Ok, - Err(e) => ConditionalWriteResult::GeneralFailure(e) + Err(e) => ConditionalWriteResult::GeneralFailure(e), } } } impl<'a, 'b: 'a> ConditionalWriteResult<'a, 'b> { - #[inline] pub fn handle_condition_failure<FN>(self, func: FN) -> Result<(), EncodingError> - where FN: FnOnce(&mut EncodingWriter) -> Result<(), EncodingError> + where + FN: FnOnce(&mut EncodingWriter) -> Result<(), EncodingError>, { use self::ConditionalWriteResult as CWR; match self { CWR::Ok => Ok(()), - CWR::ConditionFailure(handle) => { - func(handle) - }, - CWR::GeneralFailure(err) => Err(err) + CWR::ConditionFailure(handle) => func(handle), + CWR::GeneralFailure(err) => Err(err), } } } - - - - #[cfg(test)] mod test { - use soft_ascii_string::{ SoftAsciiChar, SoftAsciiStr}; - use ::MailType; - use ::error::EncodingErrorKind; + use error::EncodingErrorKind; + use soft_ascii_string::{SoftAsciiChar, SoftAsciiStr}; + use MailType; + use super::EncodingBuffer as _Encoder; use super::TraceToken::*; - use super::{EncodingBuffer as _Encoder}; mod test_test_utilities { - use encoder::TraceToken::*; use super::super::simplify_trace_tokens; + use encoder::TraceToken::*; #[test] fn does_simplify_tokens_strip_nows() { @@ -827,21 +838,23 @@ mod test { Text("up!".into()), CRLF, NowAText, - Text("abc".into()) + Text("abc".into()), ]; let out = simplify_trace_tokens(inp); - assert_eq!(out, vec![ - Text("h".into()), - CRLF, - Text("y yo".into()), - CRLF, - Text(", what's".into()), - CRLF, - Text("up!".into()), - CRLF, - Text("abc".into()) - ]) - + assert_eq!( + out, + vec![ + Text("h".into()), + CRLF, + Text("y yo".into()), + CRLF, + Text(", what's".into()), + CRLF, + Text("up!".into()), + CRLF, + Text("abc".into()) + ] + ) } #[test] @@ -856,53 +869,36 @@ mod test { NowUnchecked, Text(" up! ".into()), NowAText, - Text("abc".into()) + Text("abc".into()), ]; let out = simplify_trace_tokens(inp); - assert_eq!(out, vec![ - Text("hy yo, what's up! abc".into()) - ]); + assert_eq!(out, vec![Text("hy yo, what's up! abc".into())]); } #[test] fn simplify_works_with_empty_text() { - let inp = vec![ - NowStr, - Text("".into()), - CRLF, - ]; - assert_eq!(simplify_trace_tokens(inp), vec![ - Text("".into()), - CRLF - ]) + let inp = vec![NowStr, Text("".into()), CRLF]; + assert_eq!(simplify_trace_tokens(inp), vec![Text("".into()), CRLF]) } #[test] fn simplify_works_with_trailing_empty_text() { - let inp = vec![ - Text("a".into()), - CRLF, - Text("".into()), - ]; - assert_eq!(simplify_trace_tokens(inp), vec![ - Text("a".into()), - CRLF, - Text("".into()) - ]) + let inp = vec![Text("a".into()), CRLF, Text("".into())]; + assert_eq!( + simplify_trace_tokens(inp), + vec![Text("a".into()), CRLF, Text("".into())] + ) } - } mod EncodableInHeader { #![allow(non_snake_case)] - use super::super::*; use self::TraceToken::*; + use super::super::*; #[test] fn is_implemented_for_closures() { - let closure = enc_func!(|handle: &mut EncodingWriter| { - handle.write_utf8("hy ho") - }); + let closure = enc_func!(|handle: &mut EncodingWriter| { handle.write_utf8("hy ho") }); let mut encoder = EncodingBuffer::new(MailType::Internationalized); { @@ -910,20 +906,17 @@ mod test { assert_ok!(closure.encode(&mut handle)); handle.finish_header(); } - assert_eq!(encoder.trace.as_slice(), &[ - NowUtf8, - Text("hy ho".into()), - CRLF, - End - ]) + assert_eq!( + encoder.trace.as_slice(), + &[NowUtf8, Text("hy ho".into()), CRLF, End] + ) } } - mod EncodingBuffer { #![allow(non_snake_case)] + use super::_Encoder as EncodingBuffer; use super::*; - use super::{ _Encoder as EncodingBuffer }; #[test] fn new_encoder() { @@ -943,23 +936,18 @@ mod test { assert_eq!( encoder.as_slice(), - concat!( - "una body\r\n", - "\r\n", - "another body\r\n" - ).as_bytes() + concat!("una body\r\n", "\r\n", "another body\r\n").as_bytes() ) } } - mod EncodingWriter { #![allow(non_snake_case)] use std::mem; use std::str; + use super::_Encoder as EncodingBuffer; use super::*; - use super::{ _Encoder as EncodingBuffer }; #[test] fn commit_partial_and_drop_does_not_panic() { @@ -977,8 +965,7 @@ mod test { let mut encoder = EncodingBuffer::new(MailType::Ascii); { let mut handle = encoder.writer(); - assert_ok!( - handle.write_str(SoftAsciiStr::from_unchecked("Header-One: 12"))); + assert_ok!(handle.write_str(SoftAsciiStr::from_unchecked("Header-One: 12"))); handle.undo_header(); } assert_eq!(encoder.as_slice(), b""); @@ -1024,19 +1011,22 @@ mod test { let mut encoder = EncodingBuffer::new(MailType::Ascii); { let mut handle = encoder.writer(); - assert_ok!(handle.write_str(SoftAsciiStr::from_str("Header-One: 12\r\n ").unwrap())); + assert_ok!( + handle.write_str(SoftAsciiStr::from_str("Header-One: 12\r\n ").unwrap()) + ); handle.finish_header(); } assert_eq!(encoder.as_slice(), b"Header-One: 12\r\n"); } - #[test] fn finish_can_handle_fws() { let mut encoder = EncodingBuffer::new(MailType::Ascii); { let mut handle = encoder.writer(); - assert_ok!(handle.write_str(SoftAsciiStr::from_str("Header-One: 12 +\r\n 4").unwrap())); + assert_ok!( + handle.write_str(SoftAsciiStr::from_str("Header-One: 12 +\r\n 4").unwrap()) + ); handle.finish_header(); } assert_eq!(encoder.as_slice(), b"Header-One: 12 +\r\n 4\r\n"); @@ -1047,14 +1037,14 @@ mod test { let mut encoder = EncodingBuffer::new(MailType::Ascii); { let mut handle = encoder.writer(); - assert_ok!(handle.write_str( - SoftAsciiStr::from_str("Header-One: 12 +\r\n 4 ").unwrap())); + assert_ok!( + handle.write_str(SoftAsciiStr::from_str("Header-One: 12 +\r\n 4 ").unwrap()) + ); handle.finish_header(); } assert_eq!(encoder.as_slice(), b"Header-One: 12 +\r\n 4 \r\n"); } - #[test] fn orphan_lf_error |