Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions src/core/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl MessageParser {
pub fn new() -> Self {
Self {
header_map: Default::default(),
def_hdr_parse_fnc: |s| s.parse_raw(),
def_hdr_parse_fnc: |s| s.parse_raw().into(),
}
}

Expand Down Expand Up @@ -122,19 +122,21 @@ impl MessageParser {
/// Parse a header as text decoding RFC 2047 encoded words.
pub fn header_text(mut self, header: impl Into<HeaderName<'static>>) -> Self {
self.header_map
.insert(header.into(), |s| s.parse_unstructured());
.insert(header.into(), |s| s.parse_unstructured().into());
self
}

/// Parse a header as a RFC 5322 date.
pub fn header_date(mut self, header: impl Into<HeaderName<'static>>) -> Self {
self.header_map.insert(header.into(), |s| s.parse_date());
self.header_map
.insert(header.into(), |s| s.parse_date().into());
self
}

/// Parse a header as an address.
pub fn header_address(mut self, header: impl Into<HeaderName<'static>>) -> Self {
self.header_map.insert(header.into(), |s| s.parse_address());
self.header_map
.insert(header.into(), |s| s.parse_address().into());
self
}

Expand All @@ -147,7 +149,7 @@ impl MessageParser {
/// Parse a header as a MIME `Content-Type` or `Content-Disposition` type.
pub fn header_content_type(mut self, header: impl Into<HeaderName<'static>>) -> Self {
self.header_map
.insert(header.into(), |s| s.parse_content_type());
.insert(header.into(), |s| s.parse_content_type().into());
self
}

Expand All @@ -161,13 +163,14 @@ impl MessageParser {
/// Parse a header as a received header.
pub fn header_received(mut self, header: impl Into<HeaderName<'static>>) -> Self {
self.header_map
.insert(header.into(), |s| s.parse_received());
.insert(header.into(), |s| s.parse_received().map(Box::new).into());
self
}

/// Parse a header as a raw string, no RFC 2047 decoding is done.
pub fn header_raw(mut self, header: impl Into<HeaderName<'static>>) -> Self {
self.header_map.insert(header.into(), |s| s.parse_raw());
self.header_map
.insert(header.into(), |s| s.parse_raw().into());
self
}

Expand All @@ -182,13 +185,13 @@ impl MessageParser {

/// Parse all other headers as text decoding RFC 2047 encoded words.
pub fn default_header_text(mut self) -> Self {
self.def_hdr_parse_fnc = |s| s.parse_unstructured();
self.def_hdr_parse_fnc = |s| s.parse_unstructured().into();
self
}

/// Parse all other headers as raw strings, no RFC 2047 decoding is done.
pub fn default_header_raw(mut self) -> Self {
self.def_hdr_parse_fnc = |s| s.parse_raw();
self.def_hdr_parse_fnc = |s| s.parse_raw().into();
self
}

Expand Down
14 changes: 9 additions & 5 deletions src/core/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,18 @@ impl<'x> Message<'x> {
HeaderForm::Raw => HeaderValue::Text(
std::str::from_utf8(bytes).unwrap_or_default().trim().into(),
),
HeaderForm::Text => MessageStream::new(bytes).parse_unstructured(),
HeaderForm::Addresses => MessageStream::new(bytes).parse_address(),
HeaderForm::Text => {
MessageStream::new(bytes).parse_unstructured().into()
}
HeaderForm::Addresses => {
MessageStream::new(bytes).parse_address().into()
}
HeaderForm::GroupedAddresses => {
MessageStream::new(bytes).parse_address()
MessageStream::new(bytes).parse_address().into()
}
HeaderForm::MessageIds => MessageStream::new(bytes).parse_id(),
HeaderForm::Date => MessageStream::new(bytes).parse_date(),
HeaderForm::URLs => MessageStream::new(bytes).parse_address(),
HeaderForm::Date => MessageStream::new(bytes).parse_date().into(),
HeaderForm::URLs => MessageStream::new(bytes).parse_address().into(),
}),
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/decoders/encoded_word.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ mod tests {
//println!("Decoded '{}'", string);
assert_eq!(result, expected_result);
}
_ => panic!("Failed to decode '{}'", input),
_ => panic!("Failed to decode '{input}'"),
}
}
}
Expand Down
44 changes: 44 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,50 @@ pub mod decoders;
pub mod mailbox;
pub mod parsers;

impl<'x> From<Option<Address<'x>>> for HeaderValue<'x> {
fn from(src: Option<Address<'x>>) -> HeaderValue<'x> {
match src {
Some(x) => HeaderValue::Address(x),
None => HeaderValue::Empty,
}
}
}
impl<'x> From<Option<Cow<'x, str>>> for HeaderValue<'x> {
fn from(src: Option<Cow<'x, str>>) -> HeaderValue<'x> {
match src {
Some(x) => HeaderValue::Text(x),
None => HeaderValue::Empty,
}
}
}

impl<'x> From<Option<DateTime>> for HeaderValue<'x> {
fn from(src: Option<DateTime>) -> HeaderValue<'x> {
match src {
Some(x) => HeaderValue::DateTime(x),
None => HeaderValue::Empty,
}
}
}

impl<'x> From<Option<ContentType<'x>>> for HeaderValue<'x> {
fn from(src: Option<ContentType<'x>>) -> HeaderValue<'x> {
match src {
Some(x) => HeaderValue::ContentType(x),
None => HeaderValue::Empty,
}
}
}

impl<'x> From<Option<Box<Received<'x>>>> for HeaderValue<'x> {
fn from(src: Option<Box<Received<'x>>>) -> HeaderValue<'x> {
match src {
Some(x) => HeaderValue::Received(x),
None => HeaderValue::Empty,
}
}
}

use parsers::MessageStream;
use std::{borrow::Cow, collections::HashMap, hash::Hash, net::IpAddr};

Expand Down
12 changes: 6 additions & 6 deletions src/parsers/fields/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use std::borrow::Cow;

use crate::{parsers::MessageStream, Addr, Address, Group, HeaderValue};
use crate::{parsers::MessageStream, Addr, Address, Group};

#[derive(PartialEq, Clone, Copy, Debug)]
enum AddressState {
Expand Down Expand Up @@ -191,7 +191,7 @@ impl<'x> AddressParser<'x> {
}

impl<'x> MessageStream<'x> {
pub fn parse_address(&mut self) -> HeaderValue<'x> {
pub fn parse_address(&mut self) -> Option<Address<'x>> {
let mut parser = AddressParser {
token_start: 0,
token_end: 0,
Expand Down Expand Up @@ -354,11 +354,11 @@ impl<'x> MessageStream<'x> {

if parser.group_name.is_some() || !parser.result.is_empty() {
parser.add_group();
HeaderValue::Address(Address::Group(parser.result))
Some(Address::Group(parser.result))
} else if !parser.addresses.is_empty() {
HeaderValue::Address(Address::List(parser.addresses))
Some(Address::List(parser.addresses))
} else {
HeaderValue::Empty
None
}
}
}
Expand Down Expand Up @@ -468,7 +468,7 @@ mod tests {
assert_eq!(
MessageStream::new(test.header.as_bytes())
.parse_address()
.unwrap_address(),
.unwrap(),
test.expected,
"failed for {:?}",
test.header
Expand Down
20 changes: 7 additions & 13 deletions src/parsers/fields/content_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::borrow::Cow;
use crate::{
decoders::{charsets::map::charset_decoder, hex::decode_hex},
parsers::MessageStream,
Attribute, ContentType, HeaderValue,
Attribute, ContentType,
};

#[derive(Clone, Copy, PartialEq, Debug)]
Expand Down Expand Up @@ -252,7 +252,7 @@ impl<'x> ContentTypeParser<'x> {
}

impl<'x> MessageStream<'x> {
pub fn parse_content_type(&mut self) -> HeaderValue<'x> {
pub fn parse_content_type(&mut self) -> Option<ContentType<'x>> {
let mut parser = ContentTypeParser {
state: ContentState::Type,
state_stack: Vec::new(),
Expand Down Expand Up @@ -345,7 +345,7 @@ impl<'x> MessageStream<'x> {
}

return if let Some(content_type) = parser.c_type {
HeaderValue::ContentType(ContentType {
Some(ContentType {
c_type: content_type,
c_subtype: parser.c_subtype.take(),
attributes: if !parser.attributes.is_empty() {
Expand All @@ -355,7 +355,7 @@ impl<'x> MessageStream<'x> {
},
})
} else {
HeaderValue::Empty
None
};
}
}
Expand Down Expand Up @@ -513,7 +513,7 @@ impl<'x> MessageStream<'x> {
}
}

HeaderValue::Empty
None
}
}
#[cfg(test)]
Expand All @@ -523,14 +523,8 @@ mod tests {
#[test]
fn parse_content_fields() {
for test in load_tests("content_type.json") {
assert_eq!(
MessageStream::new(test.header.as_bytes())
.parse_content_type()
.into_content_type(),
test.expected,
"failed for {:?}",
test.header
);
let content_type = MessageStream::new(test.header.as_bytes()).parse_content_type();
assert_eq!(content_type, test.expected, "failed for {:?}", test.header);
}

/*let mut builder = crate::parsers::fields::TestBuilder::new("content_type.json");
Expand Down
17 changes: 6 additions & 11 deletions src/parsers/fields/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use std::fmt;

use crate::{parsers::MessageStream, DateTime, HeaderValue};
use crate::{parsers::MessageStream, DateTime};

pub static DOW: &[&str] = &["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
pub static MONTH: &[&str] = &[
Expand All @@ -16,10 +16,7 @@ pub static MONTH: &[&str] = &[
impl DateTime {
/// Parses an RFC822 date
pub fn parse_rfc822(value: &str) -> Option<Self> {
match MessageStream::new(value.as_bytes()).parse_date() {
HeaderValue::DateTime(dt) => dt.into(),
_ => None,
}
MessageStream::new(value.as_bytes()).parse_date()
}

/// Parses an RFC3339 date
Expand Down Expand Up @@ -283,7 +280,7 @@ impl fmt::Display for DateTime {
}

impl<'x> MessageStream<'x> {
pub fn parse_date(&mut self) -> HeaderValue<'x> {
pub fn parse_date(&mut self) -> Option<DateTime> {
let mut pos = 0;
let mut parts = [0u32; 7];
let mut parts_sizes = [
Expand Down Expand Up @@ -413,7 +410,7 @@ impl<'x> MessageStream<'x> {
}

if pos >= 6 {
HeaderValue::DateTime(DateTime {
Some(DateTime {
year: if (0..=49).contains(&parts[2]) {
parts[2] + 2000
} else if (50..=99).contains(&parts[2]) {
Expand All @@ -435,7 +432,7 @@ impl<'x> MessageStream<'x> {
tz_before_gmt: !is_plus,
})
} else {
HeaderValue::Empty
None
}
}
// 4.3 obsolete date and time
Expand Down Expand Up @@ -490,9 +487,7 @@ mod tests {
#[test]
fn parse_dates() {
for test in load_tests("date.json") {
let datetime = MessageStream::new(test.header.as_bytes())
.parse_date()
.into_datetime();
let datetime = MessageStream::new(test.header.as_bytes()).parse_date();
assert_eq!(datetime, test.expected, "failed for {:?}", test.header);

match datetime {
Expand Down
15 changes: 6 additions & 9 deletions src/parsers/fields/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/

use crate::{parsers::MessageStream, HeaderValue};
use crate::parsers::MessageStream;

impl<'x> MessageStream<'x> {
pub fn parse_raw(&mut self) -> HeaderValue<'x> {
pub fn parse_raw(&mut self) -> Option<std::borrow::Cow<'x, str>> {
let mut token_start: usize = 0;
let mut token_end: usize = 0;

Expand All @@ -32,11 +32,11 @@ impl<'x> MessageStream<'x> {
}

if token_start > 0 {
HeaderValue::Text(String::from_utf8_lossy(
Some(String::from_utf8_lossy(
self.bytes(token_start - 1..token_end),
))
} else {
HeaderValue::Empty
None
}
}

Expand Down Expand Up @@ -75,12 +75,9 @@ mod tests {

for (input, expected) in inputs {
assert_eq!(
MessageStream::new(input.as_bytes())
.parse_raw()
.unwrap_text(),
MessageStream::new(input.as_bytes()).parse_raw().unwrap(),
expected,
"Failed for '{:?}'",
input
"Failed for '{input:?}'"
);
}
}
Expand Down
Loading