Skip to content

Commit bc6a5b1

Browse files
authored
Retain mbox IO errors (#91)
* Simplify * Clear line buffer explicitly * Move line clearing outside logic branching * Switch if-else branch order * Delete needless branching, other branch early-returns, so this is equivalent * fmt * Inline return statement * Equivalence transform of logic branches * Equivalence transform of logic branches * Hoist if across if let * Delete else block * Make explicit that !is_from holds implicitly for these branches * Switch if let {...}; if {...} into if {...}; if let {...} * Pull out common if check * Merge common if clauses * Introduce early continue * Fixed clippy warnings * Remove collecting into Vec * Dont throw away IO error
1 parent 20fa3db commit bc6a5b1

File tree

1 file changed

+32
-45
lines changed

1 file changed

+32
-45
lines changed

src/mailbox/mbox.rs

+32-45
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ use std::io::{BufRead, BufReader, Read};
1414

1515
/// Parses an Mbox mailbox from a `Read` stream, returning each message as a
1616
/// `Vec<u8>`.
17-
/// supports >From quoting as defined in the [QMail mbox specification](http://qmail.org/qmail-manual-html/man5/mbox.html).
17+
///
18+
/// Supports >From quoting as defined in the [QMail mbox specification](http://qmail.org/qmail-manual-html/man5/mbox.html).
1819
pub struct MessageIterator<T: Read> {
1920
reader: BufReader<T>,
2021
message: Option<Message>,
@@ -28,9 +29,6 @@ pub struct Message {
2829
contents: Vec<u8>,
2930
}
3031

31-
#[derive(Debug)]
32-
pub struct ParseError {}
33-
3432
impl<T> MessageIterator<T>
3533
where
3634
T: Read,
@@ -47,61 +45,50 @@ impl<T> Iterator for MessageIterator<T>
4745
where
4846
T: Read,
4947
{
50-
type Item = Result<Message, ParseError>;
48+
type Item = std::io::Result<Message>;
5149

5250
fn next(&mut self) -> Option<Self::Item> {
5351
let mut message_line = Vec::with_capacity(80);
5452

5553
loop {
5654
match self.reader.read_until(b'\n', &mut message_line) {
57-
Ok(bytes_read) => {
58-
if bytes_read == 0 {
59-
break;
60-
}
61-
}
62-
Err(_) => {
63-
return Some(Err(ParseError {}));
64-
}
55+
Ok(0) => return self.message.take().map(Ok),
56+
Ok(_) => {}
57+
Err(e) => return Some(Err(e)),
6558
}
6659

67-
let is_from = message_line
68-
.get(..5)
69-
.map(|line| line == b"From ")
70-
.unwrap_or(false);
60+
let is_from = message_line.starts_with(b"From ");
7161

72-
if let Some(message) = &mut self.message {
73-
if !is_from {
74-
if message_line[0] != b'>' {
75-
message.contents.append(&mut message_line);
76-
} else if message_line
77-
.iter()
78-
.skip_while(|&&ch| ch == b'>')
79-
.take(5)
80-
.copied()
81-
.collect::<Vec<u8>>()
82-
== b"From "
83-
{
84-
message.contents.extend_from_slice(&message_line[1..]);
85-
message_line.clear();
86-
} else {
87-
message.contents.append(&mut message_line);
88-
}
89-
} else {
90-
let message = self.message.take().map(Ok);
91-
self.message =
92-
Message::new(std::str::from_utf8(&message_line).unwrap_or("")).into();
62+
if is_from {
63+
let message = self.message.take().map(Ok);
64+
self.message =
65+
Message::new(std::str::from_utf8(&message_line).unwrap_or("")).into();
66+
if message.is_some() {
9367
return message;
9468
}
95-
} else {
96-
if is_from {
97-
self.message =
98-
Message::new(std::str::from_utf8(&message_line).unwrap_or("")).into();
99-
}
10069
message_line.clear();
70+
continue;
10171
}
102-
}
10372

104-
self.message.take().map(Ok)
73+
if let Some(message) = &mut self.message {
74+
if message_line[0] != b'>' {
75+
message.contents.extend_from_slice(&message_line);
76+
message_line.clear();
77+
continue;
78+
}
79+
// can become split_once once slice_split_once becomes stable
80+
let i = message_line
81+
.iter()
82+
.position(|&ch| ch != b'>')
83+
.unwrap_or(message_line.len());
84+
if message_line[i..].starts_with(b"From ") {
85+
message.contents.extend_from_slice(&message_line[1..]);
86+
} else {
87+
message.contents.extend_from_slice(&message_line);
88+
}
89+
}
90+
message_line.clear();
91+
}
10592
}
10693
}
10794

0 commit comments

Comments
 (0)