fix mailbox tests
This commit is contained in:
parent
3c8d851ce6
commit
fd0794fe6e
5 changed files with 163 additions and 167 deletions
|
@ -113,7 +113,7 @@ pub fn addr_spec(input: &[u8]) -> IResult<&[u8], AddrSpec> {
|
||||||
obs_local_part,
|
obs_local_part,
|
||||||
tag(&[ascii::AT]),
|
tag(&[ascii::AT]),
|
||||||
obs_domain,
|
obs_domain,
|
||||||
many0(pair(tag(&[ascii::AT]), obs_domain)), // for compatibility reasons
|
many0(pair(tag(&[ascii::AT]), obs_domain)), // for compatibility reasons with ENRON
|
||||||
)),
|
)),
|
||||||
|(local_part, _, domain, _)| AddrSpec { local_part, domain },
|
|(local_part, _, domain, _)| AddrSpec { local_part, domain },
|
||||||
)(input)
|
)(input)
|
||||||
|
@ -175,7 +175,10 @@ impl<'a> Domain<'a> {
|
||||||
pub fn to_string(&self) -> String {
|
pub fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Domain::Atoms(v) => v.iter().map(|v| encoding_rs::UTF_8.decode_without_bom_handling(v).0.to_string()).collect::<Vec<String>>().join("."),
|
Domain::Atoms(v) => v.iter().map(|v| encoding_rs::UTF_8.decode_without_bom_handling(v).0.to_string()).collect::<Vec<String>>().join("."),
|
||||||
Domain::Litteral(v) => v.iter().map(|v| encoding_rs::UTF_8.decode_without_bom_handling(v).0.to_string()).collect::<Vec<String>>().join(" "),
|
Domain::Litteral(v) => {
|
||||||
|
let inner = v.iter().map(|v| encoding_rs::UTF_8.decode_without_bom_handling(v).0.to_string()).collect::<Vec<String>>().join(" ");
|
||||||
|
format!("[{}]", inner)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,39 +238,28 @@ pub fn is_dtext(c: u8) -> bool {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::text::quoted::QuotedString;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_addr_spec() {
|
fn test_addr_spec() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
addr_spec("alice@example.com"),
|
addr_spec(b"alice@example.com"),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
AddrSpec {
|
AddrSpec {
|
||||||
local_part: "alice".into(),
|
local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom(&b"alice"[..]))]),
|
||||||
domain: "example.com".into()
|
domain: Domain::Atoms(vec![&b"example"[..], &b"com"[..]]),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
addr_spec("jsmith@[192.168.2.1]"),
|
addr_spec(b"jsmith@[192.168.2.1]").unwrap().1.to_string(),
|
||||||
Ok((
|
"jsmith@[192.168.2.1]".to_string(),
|
||||||
"",
|
|
||||||
AddrSpec {
|
|
||||||
local_part: "jsmith".into(),
|
|
||||||
domain: "192.168.2.1".into()
|
|
||||||
}
|
|
||||||
))
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
addr_spec("jsmith@[IPv6:2001:db8::1]"),
|
addr_spec(b"jsmith@[IPv6:2001:db8::1]").unwrap().1.to_string(),
|
||||||
Ok((
|
"jsmith@[IPv6:2001:db8::1]".to_string(),
|
||||||
"",
|
|
||||||
AddrSpec {
|
|
||||||
local_part: "jsmith".into(),
|
|
||||||
domain: "IPv6:2001:db8::1".into()
|
|
||||||
}
|
|
||||||
))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// UTF-8
|
// UTF-8
|
||||||
|
@ -285,52 +277,42 @@ mod tests {
|
||||||
|
|
||||||
// ASCII Edge cases
|
// ASCII Edge cases
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
addr_spec("user+mailbox/department=shipping@example.com"),
|
addr_spec(b"user+mailbox/department=shipping@example.com").unwrap().1.to_string(),
|
||||||
|
"user+mailbox/department=shipping@example.com".to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
addr_spec(b"!#$%&'*+-/=?^_`.{|}~@example.com").unwrap().1.to_string(),
|
||||||
|
"!#$%&'*+-/=?^_`.{|}~@example.com".to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
addr_spec(r#""Abc@def"@example.com"#.as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
AddrSpec {
|
AddrSpec {
|
||||||
local_part: "user+mailbox/department=shipping".into(),
|
local_part: LocalPart(vec![LocalPartToken::Word(Word::Quoted(QuotedString(vec![b"Abc@def"])))]),
|
||||||
domain: "example.com".into()
|
domain: Domain::Atoms(vec![&b"example"[..], &b"com"[..]]),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
addr_spec("!#$%&'*+-/=?^_`.{|}~@example.com"),
|
addr_spec(r#""Fred\ Bloggs"@example.com"#.as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
AddrSpec {
|
AddrSpec {
|
||||||
local_part: "!#$%&'*+-/=?^_`.{|}~".into(),
|
local_part: LocalPart(vec![LocalPartToken::Word(Word::Quoted(QuotedString(vec![b"Fred", b" ", b"Bloggs"])))]),
|
||||||
domain: "example.com".into()
|
domain: Domain::Atoms(vec![&b"example"[..], &b"com"[..]]),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
addr_spec(r#""Abc@def"@example.com"#),
|
addr_spec(r#""Joe.\\Blow"@example.com"#.as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
AddrSpec {
|
AddrSpec {
|
||||||
local_part: "Abc@def".into(),
|
local_part: LocalPart(vec![LocalPartToken::Word(Word::Quoted(QuotedString(vec![b"Joe.", &[ascii::BACKSLASH], b"Blow"])))]),
|
||||||
domain: "example.com".into()
|
domain: Domain::Atoms(vec![&b"example"[..], &b"com"[..]]),
|
||||||
}
|
|
||||||
))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
addr_spec(r#""Fred\ Bloggs"@example.com"#),
|
|
||||||
Ok((
|
|
||||||
"",
|
|
||||||
AddrSpec {
|
|
||||||
local_part: "Fred Bloggs".into(),
|
|
||||||
domain: "example.com".into()
|
|
||||||
}
|
|
||||||
))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
addr_spec(r#""Joe.\\Blow"@example.com"#),
|
|
||||||
Ok((
|
|
||||||
"",
|
|
||||||
AddrSpec {
|
|
||||||
local_part: r#"Joe.\Blow"#.into(),
|
|
||||||
domain: "example.com".into()
|
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -339,84 +321,98 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mailbox() {
|
fn test_mailbox() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mailbox(r#""Joe Q. Public" <john.q.public@example.com>"#),
|
mailbox(r#""Joe Q. Public" <john.q.public@example.com>"#.as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
MailboxRef {
|
MailboxRef {
|
||||||
name: Some("Joe Q. Public".into()),
|
name: Some(Phrase(vec![Word::Quoted(QuotedString(vec![&b"Joe"[..], &[ascii::SP], &b"Q."[..], &[ascii::SP], &b"Public"[..]]))])),
|
||||||
addrspec: AddrSpec {
|
addrspec: AddrSpec {
|
||||||
local_part: "john.q.public".into(),
|
local_part: LocalPart(vec![
|
||||||
domain: "example.com".into(),
|
LocalPartToken::Word(Word::Atom(&b"john"[..])),
|
||||||
|
LocalPartToken::Dot,
|
||||||
|
LocalPartToken::Word(Word::Atom(&b"q"[..])),
|
||||||
|
LocalPartToken::Dot,
|
||||||
|
LocalPartToken::Word(Word::Atom(&b"public"[..])),
|
||||||
|
]),
|
||||||
|
domain: Domain::Atoms(vec![&b"example"[..], &b"com"[..]]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mailbox(r#"Mary Smith <mary@x.test>"#),
|
mailbox(r#"Mary Smith <mary@x.test>"#.as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
MailboxRef {
|
MailboxRef {
|
||||||
name: Some("Mary Smith".into()),
|
name: Some(Phrase(vec![Word::Atom(&b"Mary"[..]), Word::Atom(&b"Smith"[..])])),
|
||||||
addrspec: AddrSpec {
|
addrspec: AddrSpec {
|
||||||
local_part: "mary".into(),
|
local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom(&b"mary"[..]))]),
|
||||||
domain: "x.test".into(),
|
domain: Domain::Atoms(vec![&b"x"[..], &b"test"[..]]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mailbox(r#"jdoe@example.org"#),
|
mailbox(r#"jdoe@example.org"#.as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
MailboxRef {
|
MailboxRef {
|
||||||
name: None,
|
name: None,
|
||||||
addrspec: AddrSpec {
|
addrspec: AddrSpec {
|
||||||
local_part: "jdoe".into(),
|
local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom(&b"jdoe"[..]))]),
|
||||||
domain: "example.org".into(),
|
domain: Domain::Atoms(vec![&b"example"[..], &b"org"[..]]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mailbox(r#"Who? <one@y.test>"#),
|
mailbox(r#"Who? <one@y.test>"#.as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
MailboxRef {
|
MailboxRef {
|
||||||
name: Some("Who?".into()),
|
name: Some(Phrase(vec![Word::Atom(&b"Who?"[..])])),
|
||||||
addrspec: AddrSpec {
|
addrspec: AddrSpec {
|
||||||
local_part: "one".into(),
|
local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom(&b"one"[..]))]),
|
||||||
domain: "y.test".into(),
|
domain: Domain::Atoms(vec![&b"y"[..], &b"test"[..]]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mailbox(r#"<boss@nil.test>"#),
|
mailbox(r#"<boss@nil.test>"#.as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
MailboxRef {
|
MailboxRef {
|
||||||
name: None,
|
name: None,
|
||||||
addrspec: AddrSpec {
|
addrspec: AddrSpec {
|
||||||
local_part: "boss".into(),
|
local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom(&b"boss"[..]))]),
|
||||||
domain: "nil.test".into(),
|
domain: Domain::Atoms(vec![&b"nil"[..], &b"test"[..]]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mailbox(r#""Giant; \"Big\" Box" <sysservices@example.net>"#),
|
mailbox(r#""Giant; \"Big\" Box" <sysservices@example.net>"#.as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
MailboxRef {
|
MailboxRef {
|
||||||
name: Some(r#"Giant; "Big" Box"#.into()),
|
name: Some(Phrase(vec![Word::Quoted(QuotedString(vec![
|
||||||
|
&b"Giant;"[..],
|
||||||
|
&[ascii::SP],
|
||||||
|
&[ascii::DQUOTE],
|
||||||
|
&b"Big"[..],
|
||||||
|
&[ascii::DQUOTE],
|
||||||
|
&[ascii::SP],
|
||||||
|
&b"Box"[..]
|
||||||
|
]))])),
|
||||||
addrspec: AddrSpec {
|
addrspec: AddrSpec {
|
||||||
local_part: "sysservices".into(),
|
local_part: LocalPart(vec![LocalPartToken::Word(Word::Atom(&b"sysservices"[..]))]),
|
||||||
domain: "example.net".into(),
|
domain: Domain::Atoms(vec![&b"example"[..], &b"net"[..]]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
@ -433,17 +429,20 @@ mod tests {
|
||||||
@33+4.com,,,,
|
@33+4.com,,,,
|
||||||
,,,,
|
,,,,
|
||||||
(again)
|
(again)
|
||||||
@example.com,@yep.com,@a,@b,,,@c"#
|
@example.com,@yep.com,@a,@b,,,@c"#.as_bytes()
|
||||||
),
|
),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
vec![
|
vec![
|
||||||
"33+4.com".into(),
|
None,
|
||||||
"example.com".into(),
|
Some(Domain::Atoms(vec![&b"33+4"[..], &b"com"[..]])),
|
||||||
"yep.com".into(),
|
None, None, None, None, None, None, None,
|
||||||
"a".into(),
|
Some(Domain::Atoms(vec![&b"example"[..], &b"com"[..]])),
|
||||||
"b".into(),
|
Some(Domain::Atoms(vec![&b"yep"[..], &b"com"[..]])),
|
||||||
"c".into()
|
Some(Domain::Atoms(vec![&b"a"[..]])),
|
||||||
|
Some(Domain::Atoms(vec![&b"b"[..]])),
|
||||||
|
None, None,
|
||||||
|
Some(Domain::Atoms(vec![&b"c"[..]])),
|
||||||
]
|
]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -452,12 +451,17 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_enron1() {
|
fn test_enron1() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
addr_spec("a..howard@enron.com"),
|
addr_spec("a..howard@enron.com".as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
AddrSpec {
|
AddrSpec {
|
||||||
local_part: "a..howard".into(),
|
local_part: LocalPart(vec![
|
||||||
domain: "enron.com".into(),
|
LocalPartToken::Word(Word::Atom(&b"a"[..])),
|
||||||
|
LocalPartToken::Dot,
|
||||||
|
LocalPartToken::Dot,
|
||||||
|
LocalPartToken::Word(Word::Atom(&b"howard"[..])),
|
||||||
|
]),
|
||||||
|
domain: Domain::Atoms(vec![&b"enron"[..], &b"com"[..]]),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -466,12 +470,15 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_enron2() {
|
fn test_enron2() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
addr_spec(".nelson@enron.com"),
|
addr_spec(".nelson@enron.com".as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
AddrSpec {
|
AddrSpec {
|
||||||
local_part: ".nelson".into(),
|
local_part: LocalPart(vec![
|
||||||
domain: "enron.com".into(),
|
LocalPartToken::Dot,
|
||||||
|
LocalPartToken::Word(Word::Atom(&b"nelson"[..])),
|
||||||
|
]),
|
||||||
|
domain: Domain::Atoms(vec![&b"enron"[..], &b"com"[..]]),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -480,12 +487,17 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_enron3() {
|
fn test_enron3() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
addr_spec("ecn2760.conf.@enron.com"),
|
addr_spec("ecn2760.conf.@enron.com".as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
AddrSpec {
|
AddrSpec {
|
||||||
local_part: "ecn2760.conf.".into(),
|
local_part: LocalPart(vec![
|
||||||
domain: "enron.com".into(),
|
LocalPartToken::Word(Word::Atom(&b"ecn2760"[..])),
|
||||||
|
LocalPartToken::Dot,
|
||||||
|
LocalPartToken::Word(Word::Atom(&b"conf"[..])),
|
||||||
|
LocalPartToken::Dot,
|
||||||
|
]),
|
||||||
|
domain: Domain::Atoms(vec![&b"enron"[..], &b"com"[..]]),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -494,14 +506,18 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_enron4() {
|
fn test_enron4() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mailbox(r#"<"mark_kopinski/intl/acim/americancentury"@americancentury.com@enron.com>"#),
|
mailbox(r#"<"mark_kopinski/intl/acim/americancentury"@americancentury.com@enron.com>"#.as_bytes()),
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
&b""[..],
|
||||||
MailboxRef {
|
MailboxRef {
|
||||||
name: None,
|
name: None,
|
||||||
addrspec: AddrSpec {
|
addrspec: AddrSpec {
|
||||||
local_part: "mark_kopinski/intl/acim/americancentury".into(),
|
local_part: LocalPart(vec![
|
||||||
domain: "americancentury.com".into(),
|
LocalPartToken::Word(Word::Quoted(QuotedString(vec![
|
||||||
|
&b"mark_kopinski/intl/acim/americancentury"[..],
|
||||||
|
])))
|
||||||
|
]),
|
||||||
|
domain: Domain::Atoms(vec![&b"americancentury"[..], &b"com"[..]]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
#[derive(Debug, PartialEq, Default)]
|
|
||||||
pub struct Text<'a> {
|
|
||||||
parts: Vec<&'a [u8]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Text<'a> {
|
|
||||||
pub fn push(&mut self, e: &'a [u8]) {
|
|
||||||
self.parts.push(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_string(&self) -> String {
|
|
||||||
let enc = encoding_rs::UTF_8;
|
|
||||||
let size = self.parts.iter().fold(0, |acc, v| acc + v.len());
|
|
||||||
|
|
||||||
self.parts.iter().fold(
|
|
||||||
String::with_capacity(size),
|
|
||||||
|mut acc, v| {
|
|
||||||
let (content, _) = enc.decode_without_bom_handling(v);
|
|
||||||
acc.push_str(content.as_ref());
|
|
||||||
acc
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::text::ascii;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_text() {
|
|
||||||
let mut text = Text::default();
|
|
||||||
text.push(b"hello");
|
|
||||||
text.push(&[ascii::SP]);
|
|
||||||
text.push(b"world");
|
|
||||||
assert_eq!(
|
|
||||||
text.to_string(),
|
|
||||||
"hello world".to_string(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,11 +9,10 @@ use nom::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::text::{
|
use crate::text::{
|
||||||
quoted::quoted_string,
|
quoted::{QuotedString, quoted_string},
|
||||||
whitespace::{fws, is_obs_no_ws_ctl},
|
whitespace::{fws, is_obs_no_ws_ctl},
|
||||||
words::{atom, is_vchar},
|
words::{atom, is_vchar},
|
||||||
encoding::{self, encoded_word},
|
encoding::{self, encoded_word},
|
||||||
buffer,
|
|
||||||
ascii,
|
ascii,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ impl<'a> TryFrom<&'a lazy::PhraseList<'a>> for PhraseList {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Word<'a> {
|
pub enum Word<'a> {
|
||||||
Quoted(buffer::Text<'a>),
|
Quoted(QuotedString<'a>),
|
||||||
Encoded(encoding::EncodedWord<'a>),
|
Encoded(encoding::EncodedWord<'a>),
|
||||||
Atom(&'a [u8]),
|
Atom(&'a [u8]),
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,4 +4,3 @@ pub mod misc_token;
|
||||||
pub mod quoted;
|
pub mod quoted;
|
||||||
pub mod whitespace;
|
pub mod whitespace;
|
||||||
pub mod words;
|
pub mod words;
|
||||||
pub mod buffer;
|
|
||||||
|
|
|
@ -9,7 +9,29 @@ use nom::{
|
||||||
|
|
||||||
use crate::text::whitespace::{cfws, fws, is_obs_no_ws_ctl};
|
use crate::text::whitespace::{cfws, fws, is_obs_no_ws_ctl};
|
||||||
use crate::text::ascii;
|
use crate::text::ascii;
|
||||||
use crate::text::buffer;
|
|
||||||
|
#[derive(Debug, PartialEq, Default)]
|
||||||
|
pub struct QuotedString<'a>(pub Vec<&'a [u8]>);
|
||||||
|
|
||||||
|
impl<'a> QuotedString<'a> {
|
||||||
|
pub fn push(&mut self, e: &'a [u8]) {
|
||||||
|
self.0.push(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string(&self) -> String {
|
||||||
|
let enc = encoding_rs::UTF_8;
|
||||||
|
let size = self.0.iter().fold(0, |acc, v| acc + v.len());
|
||||||
|
|
||||||
|
self.0.iter().fold(
|
||||||
|
String::with_capacity(size),
|
||||||
|
|mut acc, v| {
|
||||||
|
let (content, _) = enc.decode_without_bom_handling(v);
|
||||||
|
acc.push_str(content.as_ref());
|
||||||
|
acc
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Quoted pair
|
/// Quoted pair
|
||||||
///
|
///
|
||||||
|
@ -55,7 +77,7 @@ fn qcontent(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
/// DQUOTE *([FWS] qcontent) [FWS] DQUOTE
|
/// DQUOTE *([FWS] qcontent) [FWS] DQUOTE
|
||||||
/// [CFWS]
|
/// [CFWS]
|
||||||
/// ```
|
/// ```
|
||||||
pub fn quoted_string(input: &[u8]) -> IResult<&[u8], buffer::Text> {
|
pub fn quoted_string(input: &[u8]) -> IResult<&[u8], QuotedString> {
|
||||||
let (input, _) = opt(cfws)(input)?;
|
let (input, _) = opt(cfws)(input)?;
|
||||||
let (input, _) = tag("\"")(input)?;
|
let (input, _) = tag("\"")(input)?;
|
||||||
let (input, content) = many0(pair(opt(fws), qcontent))(input)?;
|
let (input, content) = many0(pair(opt(fws), qcontent))(input)?;
|
||||||
|
@ -63,7 +85,7 @@ pub fn quoted_string(input: &[u8]) -> IResult<&[u8], buffer::Text> {
|
||||||
// Rebuild string
|
// Rebuild string
|
||||||
let mut qstring = content
|
let mut qstring = content
|
||||||
.iter()
|
.iter()
|
||||||
.fold(buffer::Text::default(), |mut acc, (maybe_wsp, c)| {
|
.fold(QuotedString::default(), |mut acc, (maybe_wsp, c)| {
|
||||||
if let Some(_) = maybe_wsp {
|
if let Some(_) = maybe_wsp {
|
||||||
acc.push(&[ascii::SP]);
|
acc.push(&[ascii::SP]);
|
||||||
}
|
}
|
||||||
|
@ -86,23 +108,25 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quoted_string() {
|
fn test_quoted_string_parser() {
|
||||||
let mut text = buffer::Text::default();
|
|
||||||
text.push(b"hello");
|
|
||||||
text.push(&[ascii::DQUOTE]);
|
|
||||||
text.push(b"world");
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
quoted_string(b" \"hello\\\"world\" "),
|
quoted_string(b" \"hello\\\"world\" ").unwrap().1,
|
||||||
Ok((&b""[..], text))
|
QuotedString(vec![b"hello", &[ascii::DQUOTE], b"world"])
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut text = buffer::Text::default();
|
|
||||||
text.push(b"hello");
|
|
||||||
text.push(&[ascii::SP]);
|
|
||||||
text.push(b"world");
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
quoted_string(b"\"hello\r\n world\""),
|
quoted_string(b"\"hello\r\n world\""),
|
||||||
Ok((&b""[..], text))
|
Ok((&b""[..], QuotedString(vec![b"hello", &[ascii::SP], b"world"]))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::text::ascii;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_quoted_string_object() {
|
||||||
|
assert_eq!(
|
||||||
|
QuotedString(vec![b"hello", &[ascii::SP], b"world"]).to_string(),
|
||||||
|
"hello world".to_string(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue