diff options
Diffstat (limited to 'headers/src/header_components/message_id.rs')
-rw-r--r-- | headers/src/header_components/message_id.rs | 243 |
1 files changed, 118 insertions, 125 deletions
diff --git a/headers/src/header_components/message_id.rs b/headers/src/header_components/message_id.rs index 6ee8a61..e2bed1e 100644 --- a/headers/src/header_components/message_id.rs +++ b/headers/src/header_components/message_id.rs @@ -1,20 +1,16 @@ -use std::fmt::{self, Display}; use nom::IResult; +use std::fmt::{self, Display}; +#[cfg(feature = "serde")] +use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use soft_ascii_string::{SoftAsciiChar, SoftAsciiStr, SoftAsciiString}; use vec1::Vec1; -#[cfg(feature="serde")] -use serde::{ - Serialize, Serializer, - Deserialize, Deserializer, - de::Error -}; +use data::{Input, SimpleItem}; +use error::ComponentCreationError; +use internals::encoder::{EncodableInHeader, EncodingWriter}; use internals::error::EncodingError; -use internals::encoder::{EncodingWriter, EncodableInHeader}; -use ::{HeaderTryFrom, HeaderTryInto}; -use ::error::ComponentCreationError; -use ::data::{ Input, SimpleItem }; +use {HeaderTryFrom, HeaderTryInto}; /// # Implementation Details /// @@ -25,94 +21,98 @@ use ::data::{ Input, SimpleItem }; /// only supports the later one. #[derive(Debug, Clone, Hash, Eq, PartialEq)] pub struct MessageId { - message_id: SimpleItem + message_id: SimpleItem, } - impl MessageId { - /// creates a message id from a string without checking for validity /// /// The string is expected to have the format `<left_part> "@" <right_part>`, /// i.e. it should not include the `"<"`, `">"` surrounding message id's in /// more or less all places they are used. pub fn from_unchecked(string: String) -> Self { - let item = - match SoftAsciiString::from_string(string) { - Ok(ascii) => ascii.into(), - Err(err) => err.into_source().into() - }; + let item = match SoftAsciiString::from_string(string) { + Ok(ascii) => ascii.into(), + Err(err) => err.into_source().into(), + }; MessageId { message_id: item } } - pub fn new(left_part: &SoftAsciiStr, right_part: &SoftAsciiStr) - -> Result<Self, ComponentCreationError> - { - use self::{parser_parts as parser}; + pub fn new( + left_part: &SoftAsciiStr, + right_part: &SoftAsciiStr, + ) -> Result<Self, ComponentCreationError> { + use self::parser_parts as parser; match parser::id_left(left_part.as_str()) { - IResult::Done( "", _part ) => {}, + IResult::Done("", _part) => {} _other => { return Err(ComponentCreationError::new_with_str( - "MessageId", format!("{}@{}", left_part, right_part))); + "MessageId", + format!("{}@{}", left_part, right_part), + )); } } match parser::id_right(right_part.as_str()) { - IResult::Done( "", _part ) => {}, + IResult::Done("", _part) => {} _other => { return Err(ComponentCreationError::new_with_str( - "MessageId", format!("{}@{}", left_part, right_part))); + "MessageId", + format!("{}@{}", left_part, right_part), + )); } } - let id = SoftAsciiString::from_unchecked( - format!("{}@{}", left_part, right_part)); + let id = SoftAsciiString::from_unchecked(format!("{}@{}", left_part, right_part)); let item = SimpleItem::Ascii(id.into()); Ok(MessageId { message_id: item }) } //FIXME make into AsRef<str> for MessageId - pub fn as_str( &self ) -> &str { + pub fn as_str(&self) -> &str { self.message_id.as_str() } } -#[cfg(feature="serde")] +#[cfg(feature = "serde")] impl Serialize for MessageId { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where S: Serializer + where + S: Serializer, { serializer.serialize_str(self.as_str()) } } -#[cfg(feature="serde")] +#[cfg(feature = "serde")] impl<'de> Deserialize<'de> for MessageId { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where D: Deserializer<'de> + where + D: Deserializer<'de>, { let as_string = String::deserialize(deserializer)?; let as_ascii = SoftAsciiStr::from_str(&as_string) .map_err(|err| D::Error::custom(format!("message id is not ascii: {}", err)))?; - let split_point = - if as_ascii.as_str().ends_with("]") { - as_ascii.as_str() - .bytes() - .rposition(|bch| bch == b'[') - .and_then(|pos| pos.checked_sub(1)) - .ok_or_else(|| D::Error::custom("invalid message id format"))? - } else { - as_ascii.as_str() - .bytes() - .rposition(|bch| bch == b'@') - .ok_or_else(|| D::Error::custom("invalid message id format"))? - }; + let split_point = if as_ascii.as_str().ends_with("]") { + as_ascii + .as_str() + .bytes() + .rposition(|bch| bch == b'[') + .and_then(|pos| pos.checked_sub(1)) + .ok_or_else(|| D::Error::custom("invalid message id format"))? + } else { + as_ascii + .as_str() + .bytes() + .rposition(|bch| bch == b'@') + .ok_or_else(|| D::Error::custom("invalid message id format"))? + }; let left_part = &as_ascii[..split_point]; - let right_part = &as_ascii[split_point+1..]; + let right_part = &as_ascii[split_point + 1..]; MessageId::new(left_part, right_part) .map_err(|err| D::Error::custom(format!("invalid message id format: {}", err))) } @@ -125,37 +125,41 @@ impl Display for MessageId { } impl<T> HeaderTryFrom<T> for MessageId - where T: HeaderTryInto<Input> +where + T: HeaderTryInto<Input>, { - fn try_from( input: T ) -> Result<Self, ComponentCreationError> { + fn try_from(input: T) -> Result<Self, ComponentCreationError> { use self::parser_parts::parse_message_id; let input = input.try_into()?; match parse_message_id(input.as_str()) { - IResult::Done( "", _msg_id ) => {}, + IResult::Done("", _msg_id) => {} _other => { - return Err(ComponentCreationError::new_with_str("MessageId", input.as_str())); + return Err(ComponentCreationError::new_with_str( + "MessageId", + input.as_str(), + )); } } - - Ok( MessageId { message_id: input.into() } ) + Ok(MessageId { + message_id: input.into(), + }) } } -impl EncodableInHeader for MessageId { - +impl EncodableInHeader for MessageId { fn encode(&self, handle: &mut EncodingWriter) -> Result<(), EncodingError> { handle.mark_fws_pos(); - handle.write_char( SoftAsciiChar::from_unchecked('<') )?; + handle.write_char(SoftAsciiChar::from_unchecked('<'))?; match self.message_id { - SimpleItem::Ascii( ref ascii ) => handle.write_str( ascii )?, - SimpleItem::Utf8( ref utf8 ) => handle.write_utf8( utf8 )? + SimpleItem::Ascii(ref ascii) => handle.write_str(ascii)?, + SimpleItem::Utf8(ref utf8) => handle.write_utf8(utf8)?, } - handle.write_char( SoftAsciiChar::from_unchecked('>') )?; + handle.write_char(SoftAsciiChar::from_unchecked('>'))?; handle.mark_fws_pos(); - Ok( () ) + Ok(()) } fn boxed_clone(&self) -> Box<EncodableInHeader> { @@ -164,18 +168,17 @@ impl EncodableInHeader for MessageId { } #[derive(Debug, Clone)] -#[cfg_attr(feature="serde", derive(Serialize, Deserialize))] -pub struct MessageIdList( pub Vec1<MessageId> ); +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct MessageIdList(pub Vec1<MessageId>); -deref0!{ +mut MessageIdList => Vec1<MessageId> } - -impl EncodableInHeader for MessageIdList { +deref0! { +mut MessageIdList => Vec1<MessageId> } +impl EncodableInHeader for MessageIdList { fn encode(&self, handle: &mut EncodingWriter) -> Result<(), EncodingError> { for msg_id in self.iter() { - msg_id.encode( handle )?; + msg_id.encode(handle)?; } - Ok( () ) + Ok(()) } fn boxed_clone(&self) -> Box<EncodableInHeader> { @@ -183,19 +186,13 @@ impl EncodableInHeader for MessageIdList { } } - mod parser_parts { - use nom::IResult; use internals::grammar::{is_atext, is_dtext}; use internals::MailType; + use nom::IResult; - pub fn parse_message_id( input: &str) -> IResult<&str, (&str, &str)> { - do_parse!( input, - l: id_left >> - char!( '@' ) >> - r: id_right >> - (l, r) - ) + pub fn parse_message_id(input: &str) -> IResult<&str, (&str, &str)> { + do_parse!(input, l: id_left >> char!('@') >> r: id_right >> (l, r)) } pub fn id_left(input: &str) -> IResult<&str, &str> { @@ -203,51 +200,51 @@ mod parser_parts { } pub fn id_right(input: &str) -> IResult<&str, &str> { - alt!( - input, - no_fold_literal | - dot_atom_text - ) + alt!(input, no_fold_literal | dot_atom_text) } - fn no_fold_literal( input: &str ) -> IResult<&str, &str> { - recognize!( input, + fn no_fold_literal(input: &str) -> IResult<&str, &str> { + recognize!( + input, tuple!( - char!( '[' ), - take_while!( call!( is_dtext, MailType::Internationalized ) ), - char!( ']' ) + char!('['), + take_while!(call!(is_dtext, MailType::Internationalized)), + char!(']') ) ) } fn dot_atom_text(input: &str) -> IResult<&str, &str> { - recognize!( input, tuple!( - take_while1!( call!( is_atext, MailType::Internationalized ) ), - many0!(tuple!( - char!( '.' ), - take_while1!( call!( is_atext, MailType::Internationalized ) ) - )) - ) ) + recognize!( + input, + tuple!( + take_while1!(call!(is_atext, MailType::Internationalized)), + many0!(tuple!( + char!('.'), + take_while1!(call!(is_atext, MailType::Internationalized)) + )) + ) + ) } #[cfg(test)] mod test { - use nom; use super::*; + use nom; #[test] fn rec_dot_atom_text_no_dot() { - match dot_atom_text( "abc" ) { - IResult::Done( "", "abc" ) => {}, - other => panic!("excepted Done(\"\",\"abc\") got {:?}", other ) + match dot_atom_text("abc") { + IResult::Done("", "abc") => {} + other => panic!("excepted Done(\"\",\"abc\") got {:?}", other), } } #[test] fn rec_dot_atom_text_dots() { - match dot_atom_text( "abc.def.ghi" ) { - IResult::Done( "", "abc.def.ghi" ) => {}, - other => panic!("excepted Done(\"\",\"abc.def.ghi\") got {:?}", other ) + match dot_atom_text("abc.def.ghi") { + IResult::Done("", "abc.def.ghi") => {} + other => panic!("excepted Done(\"\",\"abc.def.ghi\") got {:?}", other), } } @@ -255,35 +252,33 @@ mod parser_parts { fn rec_dot_atom_text_no_end_dot() { let test_str = "abc."; let need_size = test_str.len() + 1; - match dot_atom_text( test_str ) { - IResult::Incomplete( nom::Needed::Size( ns ) ) if ns == need_size => {} - other => panic!("excepted Incomplete(Complete) got {:?}", other ) + match dot_atom_text(test_str) { + IResult::Incomplete(nom::Needed::Size(ns)) if ns == need_size => {} + other => panic!("excepted Incomplete(Complete) got {:?}", other), } } #[test] fn rec_dot_atom_text_no_douple_dot() { - match dot_atom_text( "abc..de" ) { - IResult::Done( "..de", "abc" ) => {}, - other => panic!( "excepted Done(\"..de\",\"abc\") got {:?}", other ) + match dot_atom_text("abc..de") { + IResult::Done("..de", "abc") => {} + other => panic!("excepted Done(\"..de\",\"abc\") got {:?}", other), } } #[test] fn rec_dot_atom_text_no_start_dot() { - match dot_atom_text( ".abc" ) { - IResult::Error( .. ) => {}, - other => panic!( "expected error got {:?}", other ) + match dot_atom_text(".abc") { + IResult::Error(..) => {} + other => panic!("expected error got {:?}", other), } } - - #[test] fn no_empty() { - match dot_atom_text( "" ) { - IResult::Incomplete( nom::Needed::Size( 1 ) ) => {}, - other => panic!( "excepted Incomplete(Size(1)) got {:?}", other ) + match dot_atom_text("") { + IResult::Incomplete(nom::Needed::Size(1)) => {} + other => panic!("excepted Incomplete(Size(1)) got {:?}", other), } } } @@ -291,11 +286,11 @@ mod parser_parts { #[cfg(test)] mod test { - use internals::MailType; - use internals::encoder::EncodingBuffer; use super::*; + use internals::encoder::EncodingBuffer; + use internals::MailType; - ec_test!{ new, { + ec_test! { new, { MessageId::new( SoftAsciiStr::from_unchecked("just.me"), SoftAsciiStr::from_unchecked("[127.0.0.1]") @@ -306,7 +301,7 @@ mod test { MarkFWS ]} - ec_test!{ simple, { + ec_test! { simple, { MessageId::try_from( "affen@haus" )? } => ascii => [ MarkFWS, @@ -316,7 +311,7 @@ mod test { MarkFWS ]} - ec_test!{ utf8, { + ec_test! { utf8, { MessageId::try_from( "↓@↑.utf8")? } => utf8 => [ MarkFWS, @@ -328,12 +323,12 @@ mod test { fn utf8_fails() { let mut encoder = EncodingBuffer::new(MailType::Ascii); let mut handle = encoder.writer(); - let mid = MessageId::try_from( "abc@øpunny.code" ).unwrap(); - assert_err!(mid.encode( &mut handle )); + let mid = MessageId::try_from("abc@øpunny.code").unwrap(); + assert_err!(mid.encode(&mut handle)); handle.undo_header(); } - ec_test!{ multipls, { + ec_test! { multipls, { let fst = MessageId::try_from( "affen@haus" )?; let snd = MessageId::try_from( "obst@salat" )?; MessageIdList( vec1! [ @@ -349,5 +344,3 @@ mod test { MarkFWS, ]} } - - |