don't parse mail body until it's requested

Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
embed
Manos Pitsidianakis 2017-09-14 18:29:23 +03:00
parent 4119a4285d
commit a07f92a8a4
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
6 changed files with 51 additions and 32 deletions

View File

@ -29,5 +29,5 @@ optional = false
version = "5.86.0"
[profile.release]
lto = true
#debug = true
#lto = true
debug = true

View File

@ -2,11 +2,14 @@
extern crate melib;
use melib::mailbox::email::Mail;
use melib::mailbox::backends::BackendOpGenerator;
use melib::mailbox::backends::maildir::MaildirOp;
extern crate test;
use self::test::Bencher;
#[bench]
fn mail_parse(b: &mut Bencher) {
b.iter(|| Mail::from("test/attachment_test") );
b.iter(|| Mail::from(Box::new(BackendOpGenerator::new(Box::new(move || {
Box::new(MaildirOp::new("test/attachment_test".to_string()))})))) );
}

View File

@ -22,6 +22,7 @@
use mailbox::email::Mail;
use error::{MeliError, Result};
use mailbox::backends::{MailBackend, BackendOp, BackendOpGenerator};
use mailbox::email::parser;
extern crate crossbeam;
use std::path::PathBuf;
@ -48,7 +49,7 @@ impl Clone for MaildirOp {
}
impl MaildirOp {
fn new(path: String) -> Self {
pub fn new(path: String) -> Self {
MaildirOp {
path: path,
slice: None,
@ -66,7 +67,6 @@ impl BackendOp for MaildirOp {
}
Ok(unsafe { self.slice.as_ref().unwrap().as_slice() })
}
/*
fn fetch_headers(&mut self) -> Result<&[u8]> {
let raw = self.as_bytes()?;
let result = parser::headers_raw(raw).to_full_result()?;
@ -76,7 +76,7 @@ impl BackendOp for MaildirOp {
let raw = self.as_bytes()?;
let result = parser::headers_raw(raw).to_full_result()?;
Ok(result)
}*/
}
}

View File

@ -37,8 +37,8 @@ pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send {
fn as_bytes(&mut self) -> Result<&[u8]>;
//fn delete(&self) -> ();
//fn copy(&self
//fn fetch_headers(&mut self) -> Result<&[u8]>;
//fn fetch_body(&mut self) -> Result<&[u8]>;
fn fetch_headers(&mut self) -> Result<&[u8]>;
fn fetch_body(&mut self) -> Result<&[u8]>;
}
/* BackendOpGenerator is a wrapper for a closure that returns a BackendOp object */

View File

@ -108,6 +108,7 @@ pub struct Mail
references: Option<References>,
datetime: Option<chrono::DateTime<chrono::FixedOffset>>,
timestamp: i64,
thread: usize,
operation_token: Arc<Box<BackendOpGenerator>>,
@ -117,10 +118,7 @@ pub struct Mail
impl Mail
{
pub fn get_date(&self) -> i64 {
match self.datetime {
Some(v) => v.timestamp(),
None => 0,
}
self.timestamp
}
pub fn get_datetime(&self) -> chrono::DateTime<chrono::FixedOffset> {
self.datetime.unwrap_or_else(|| { chrono::FixedOffset::west(0).ymd(1970, 1, 1).and_hms(0, 0, 0)})
@ -140,8 +138,29 @@ impl Mail
None => "",
}
}
pub fn get_body(&self) -> &Attachment {
self.body.as_ref().unwrap()
pub fn get_body(&self) -> Attachment {
let mut operation = self.operation_token.generate();
let file = operation.as_bytes();
let (headers, body) = match parser::mail(file.unwrap()).to_full_result() {
Ok(v) => v,
Err(_) => {
let operation = self.operation_token.generate();
eprintln!("error in parsing mail\n{}", operation.description());
panic!();
},
};
let mut builder = AttachmentBuilder::new(body);
for (name, value) in headers {
if value.len() == 1 && value.is_empty() {
continue;
}
if name.eq_ignore_ascii_case("content-transfer-encoding") {
builder.content_transfer_encoding(value);
} else if name.eq_ignore_ascii_case("content-type") {
builder.content_type(value);
}
}
builder.build()
}
pub fn get_subject(&self) -> &str {
match self.subject {
@ -253,6 +272,12 @@ impl Mail
}
pub fn set_datetime(&mut self, new_val: Option<chrono::DateTime<chrono::FixedOffset>>) -> () {
self.datetime = new_val;
if let Some(v) = self.datetime {
self.timestamp = v.timestamp();
if self.timestamp == 1485962960 {
eprintln!("it's {:?}", self);
}
}
}
pub fn new(token: Box<BackendOpGenerator>) -> Self {
Mail {
@ -266,6 +291,7 @@ impl Mail
references: None,
datetime: None,
timestamp: 0,
thread: 0,
@ -275,23 +301,21 @@ impl Mail
}
pub fn from(operation_token: Box<BackendOpGenerator>) -> Option<Mail> {
let mut operation = operation_token.generate();
let file = operation.as_bytes();
if file.is_err() {
return None;
}
let (headers, body) = match parser::mail(file.unwrap()).to_full_result() {
Ok(v) => v,
Err(_) => {
let headers = match parser::headers(operation.fetch_headers().unwrap()).to_full_result() {
Ok(v) => {
v
},
_ => {
let operation = operation_token.generate();
eprintln!("error in parsing mail\n{}", operation.description());
return None;
}
},
};
let mut mail = Mail::new(operation_token);
let mut in_reply_to = None;
let mut datetime = None;
let mut builder = AttachmentBuilder::new(body);
for (name, value) in headers {
if value.len() == 1 && value.is_empty() {
continue;
@ -325,14 +349,11 @@ impl Mail
} else if name.eq_ignore_ascii_case("references") {
{
let parse_result = parser::references(value.as_bytes());
eprintln!("{:?}", value);
if parse_result.is_done() {
for v in parse_result.to_full_result().unwrap() {
eprintln!("pushing {:?}", v);
mail.push_references(v);
}
}
eprintln!("\n\n");
}
mail.set_references(value.to_string());
} else if name.eq_ignore_ascii_case("in-reply-to") {
@ -341,16 +362,11 @@ impl Mail
} else if name.eq_ignore_ascii_case("date") {
mail.set_date(value.to_string());
datetime = Some(value.to_string());
} else if name.eq_ignore_ascii_case("content-transfer-encoding") {
builder.content_transfer_encoding(value);
} else if name.eq_ignore_ascii_case("content-type") {
builder.content_type(value);
}
}
if let Some(ref mut x) = in_reply_to {
mail.push_references(x);
}
mail.set_body(builder.build());
if let Some(ref mut d) = datetime {
mail.set_datetime(parser::date(d));
}

View File

@ -107,7 +107,7 @@ named!(name<&str>,
named!(header<(&str, &str)>,
separated_pair!(complete!(name), ws!(tag!(":")), complete!(header_value)));
/* Parse all headers -> Vec<(&str, Vec<&str>)> */
named!(headers<std::vec::Vec<(&str, &str)>>,
named!(pub headers<std::vec::Vec<(&str, &str)>>,
many1!(complete!(header)));
named!(pub headers_raw<&[u8]>,