diff --git a/resources/address.json b/resources/address.json index 75bef97..057f759 100644 --- a/resources/address.json +++ b/resources/address.json @@ -777,5 +777,16 @@ } ] } + }, + { + "header": "John Doe", + "expected": { + "List": [ + { + "name": "John Doe", + "address": null + } + ] + } } ] diff --git a/src/parsers/fields/address.rs b/src/parsers/fields/address.rs index 885040e..e5c8277 100644 --- a/src/parsers/fields/address.rs +++ b/src/parsers/fields/address.rs @@ -209,20 +209,18 @@ impl<'x> MessageStream<'x> { result: Vec::new(), }; - while let Some(ch) = self.next() { - match ch { - b'\n' => { + loop { + match self.next() { + Some(b'\n') | None => { parser.add_token(self, false); if self.try_next_is_space() { - if !parser.is_token_start { - parser.is_token_start = true; - } + parser.is_token_start = true; continue; } else { break; } } - b'\\' if parser.state != AddressState::Name && !parser.is_escaped => { + Some(b'\\') if parser.state != AddressState::Name && !parser.is_escaped => { if parser.token_start > 0 { if parser.state == AddressState::Quote { parser.token_end = self.offset() - 1; @@ -232,24 +230,24 @@ impl<'x> MessageStream<'x> { parser.is_escaped = true; continue; } - b',' if parser.state == AddressState::Name => { + Some(b',') if parser.state == AddressState::Name => { parser.add_token(self, false); parser.add_address(); continue; } - b'<' if parser.state == AddressState::Name => { + Some(b'<') if parser.state == AddressState::Name => { parser.is_token_email = false; parser.add_token(self, false); parser.state_stack.push(AddressState::Name); parser.state = AddressState::Address; continue; } - b'>' if parser.state == AddressState::Address => { + Some(b'>') if parser.state == AddressState::Address => { parser.add_token(self, false); parser.state = parser.state_stack.pop().unwrap(); continue; } - b'"' if !parser.is_escaped => match parser.state { + Some(b'"') if !parser.is_escaped => match parser.state { AddressState::Name => { parser.state_stack.push(AddressState::Name); parser.state = AddressState::Quote; @@ -263,10 +261,12 @@ impl<'x> MessageStream<'x> { } _ => (), }, - b'@' if parser.state == AddressState::Name => { + Some(b'@') if parser.state == AddressState::Name => { parser.is_token_email = true; } - b'=' if parser.is_token_start && !parser.is_escaped && self.peek_char(b'?') => { + Some(b'=') + if parser.is_token_start && !parser.is_escaped && self.peek_char(b'?') => + { self.checkpoint(); if let Some(token) = self.decode_rfc2047() { let add_space = parser.state != AddressState::Quote; // Make borrow-checker happy @@ -281,13 +281,10 @@ impl<'x> MessageStream<'x> { } self.restore(); } - b' ' | b'\t' => { - if !parser.is_token_start { - parser.is_token_start = true; - } - if parser.is_escaped { - parser.is_escaped = false; - } + Some(b' ' | b'\t') => { + parser.is_token_start = true; + parser.is_escaped = false; + if parser.state == AddressState::Quote { if parser.token_start == 0 { parser.token_start = self.offset(); @@ -298,8 +295,8 @@ impl<'x> MessageStream<'x> { } continue; } - b'\r' => continue, - b'(' if parser.state != AddressState::Quote && !parser.is_escaped => { + Some(b'\r') => continue, + Some(b'(') if parser.state != AddressState::Quote && !parser.is_escaped => { parser.state_stack.push(parser.state); if parser.state != AddressState::Comment { parser.add_token(self, false); @@ -307,7 +304,7 @@ impl<'x> MessageStream<'x> { continue; } } - b')' if parser.state == AddressState::Comment && !parser.is_escaped => { + Some(b')') if parser.state == AddressState::Comment && !parser.is_escaped => { let new_state = parser.state_stack.pop().unwrap(); if parser.state != new_state { parser.add_token(self, false); @@ -315,13 +312,13 @@ impl<'x> MessageStream<'x> { continue; } } - b':' if parser.state == AddressState::Name && !parser.is_escaped => { + Some(b':') if parser.state == AddressState::Name && !parser.is_escaped => { parser.add_group(); parser.add_token(self, false); parser.add_group_details(); continue; } - b';' if parser.state == AddressState::Name => { + Some(b';') if parser.state == AddressState::Name => { parser.add_token(self, false); parser.add_address(); parser.add_group(); @@ -330,13 +327,8 @@ impl<'x> MessageStream<'x> { _ => (), } - if parser.is_escaped { - parser.is_escaped = false; - } - - if parser.is_token_start { - parser.is_token_start = false; - } + parser.is_escaped = false; + parser.is_token_start = false; if parser.token_start == 0 { parser.token_start = self.offset(); @@ -360,12 +352,14 @@ impl<'x> MessageStream<'x> { } fn concat_tokens<'x>(tokens: &mut Vec>) -> Cow<'x, str> { - if tokens.len() == 1 { - tokens.pop().unwrap() - } else { + if 1 < tokens.len() { let result = tokens.concat(); tokens.clear(); result.into() + } else if let Some(tok) = tokens.pop() { + tok + } else { + Cow::Borrowed("") } } @@ -461,14 +455,14 @@ mod tests { #[test] fn parse_addresses() { for test in load_tests("address.json") { - assert_eq!( - MessageStream::new(test.header.as_bytes()) - .parse_address() - .unwrap_address(), - test.expected, - "failed for {:?}", - test.header - ); + let with_trim = MessageStream::new(test.header.trim().as_bytes()) + .parse_address() + .unwrap_address(); + let without_trim = MessageStream::new(test.header.as_bytes()) + .parse_address() + .unwrap_address(); + assert_eq!(with_trim, without_trim); + assert_eq!(without_trim, test.expected, "failed for {:?}", test.header); } } }