cleanup CommaSeparatedIterator a bit more

This commit is contained in:
Robin Appelman 2021-07-29 17:22:01 +02:00
commit 4f7758b22e

View file

@ -76,11 +76,17 @@ pub fn get_forwarded_for() -> impl Filter<Extract = (Vec<IpAddr>,), Error = Infa
.unify() .unify()
} }
#[derive(Copy, Clone)]
enum CommaSeparatedIteratorState { enum CommaSeparatedIteratorState {
/// Start of string or after a ',' (including whitespace)
Default, Default,
/// Inside a double quote
Quoted, Quoted,
/// After escape character inside quote
QuotedPair, QuotedPair,
/// Non quoted part
Token, Token,
/// After closing double quote
PostAmbleForQuoted, PostAmbleForQuoted,
} }
@ -111,63 +117,52 @@ impl<'a> Iterator for CommaSeparatedIterator<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some((i, c)) = self.char_indices.next() { while let Some((i, c)) = self.char_indices.next() {
let (next, next_state) = match self.state { let (next, next_state) = match (self.state, c) {
CommaSeparatedIteratorState::Default => match c { (CommaSeparatedIteratorState::Default, '"') => {
'"' => { self.s = i;
self.s = i;
(None, CommaSeparatedIteratorState::Quoted)
}
' ' | '\t' => (None, CommaSeparatedIteratorState::Default),
',' => (
Some(Some(&self.target[i..i])),
CommaSeparatedIteratorState::Default,
),
_ => {
self.s = i;
(None, CommaSeparatedIteratorState::Token)
}
},
CommaSeparatedIteratorState::Quoted => match c {
'"' => (
Some(Some(&self.target[self.s..i + 1])),
CommaSeparatedIteratorState::PostAmbleForQuoted,
),
'\\' => (None, CommaSeparatedIteratorState::QuotedPair),
_ => (None, CommaSeparatedIteratorState::Quoted),
},
CommaSeparatedIteratorState::QuotedPair => {
(None, CommaSeparatedIteratorState::Quoted) (None, CommaSeparatedIteratorState::Quoted)
} }
CommaSeparatedIteratorState::Token => match c { (CommaSeparatedIteratorState::Default, ' ' | '\t') => {
',' => ( (None, CommaSeparatedIteratorState::Default)
Some(Some(&self.target[self.s..i])), }
CommaSeparatedIteratorState::Default, (CommaSeparatedIteratorState::Default, ',') => (
), Some(Some(&self.target[i..i])),
_ => (None, CommaSeparatedIteratorState::Token), CommaSeparatedIteratorState::Default,
}, ),
CommaSeparatedIteratorState::PostAmbleForQuoted => match c { (CommaSeparatedIteratorState::Default, _) => {
',' => (None, CommaSeparatedIteratorState::Default), self.s = i;
_ => (None, CommaSeparatedIteratorState::PostAmbleForQuoted), (None, CommaSeparatedIteratorState::Token)
}, }
(CommaSeparatedIteratorState::Quoted, '"') => (
Some(Some(&self.target[self.s..i + 1])),
CommaSeparatedIteratorState::PostAmbleForQuoted,
),
(CommaSeparatedIteratorState::Quoted, '\\') => {
(None, CommaSeparatedIteratorState::QuotedPair)
}
(CommaSeparatedIteratorState::QuotedPair, _) => {
(None, CommaSeparatedIteratorState::Quoted)
}
(CommaSeparatedIteratorState::Token, ',') => (
Some(Some(&self.target[self.s..i])),
CommaSeparatedIteratorState::Default,
),
(CommaSeparatedIteratorState::PostAmbleForQuoted, ',') => {
(None, CommaSeparatedIteratorState::Default)
}
(current_state, _) => (None, current_state),
}; };
match (next, next_state) { self.state = next_state;
(Some(next), next_state) => { if let Some(next) = next {
self.state = next_state; return next;
return next;
}
(None, next_state) => {
self.state = next_state;
}
} }
} }
match self.state { match self.state {
CommaSeparatedIteratorState::Default CommaSeparatedIteratorState::Default
| CommaSeparatedIteratorState::PostAmbleForQuoted => None, | CommaSeparatedIteratorState::PostAmbleForQuoted => None,
CommaSeparatedIteratorState::Quoted | CommaSeparatedIteratorState::QuotedPair => { CommaSeparatedIteratorState::Quoted
self.state = CommaSeparatedIteratorState::Default; | CommaSeparatedIteratorState::QuotedPair
Some(&self.target[self.s..]) | CommaSeparatedIteratorState::Token => {
}
CommaSeparatedIteratorState::Token => {
self.state = CommaSeparatedIteratorState::Default; self.state = CommaSeparatedIteratorState::Default;
Some(&self.target[self.s..]) Some(&self.target[self.s..])
} }
@ -253,7 +248,7 @@ mod tests {
"\"jkl\"", "\"jkl\"",
"\"mno\"", "\"mno\"",
"pqr", "pqr",
"\"abc, def\"" "\"abc, def\"",
], ],
CommaSeparatedIterator::new( CommaSeparatedIterator::new(
"abc,\"def\", \"ghi\",\t\"jkl\" , \"mno\",\tpqr, \"abc, def\"" "abc,\"def\", \"ghi\",\t\"jkl\" , \"mno\",\tpqr, \"abc, def\""