2019-06-05 17:52:47 +02:00
|
|
|
use std::str;
|
|
|
|
|
2020-12-01 02:21:56 +01:00
|
|
|
use actix_web::web::BytesMut;
|
2019-06-05 17:52:47 +02:00
|
|
|
|
|
|
|
enum State {
|
|
|
|
YieldStr,
|
|
|
|
YieldQuote,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Quoted<'a> {
|
|
|
|
inner: ::std::iter::Peekable<str::Split<'a, char>>,
|
|
|
|
state: State,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Quoted<'a> {
|
2020-01-14 05:31:20 +01:00
|
|
|
pub fn new(s: &'a str) -> Quoted<'_> {
|
2019-06-05 17:52:47 +02:00
|
|
|
Quoted {
|
|
|
|
inner: s.split('"').peekable(),
|
|
|
|
state: State::YieldStr,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Iterator for Quoted<'a> {
|
|
|
|
type Item = &'a str;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
match self.state {
|
2019-06-07 23:20:55 +02:00
|
|
|
State::YieldStr => match self.inner.next() {
|
|
|
|
Some(s) => {
|
|
|
|
self.state = State::YieldQuote;
|
|
|
|
Some(s)
|
2019-06-05 17:52:47 +02:00
|
|
|
}
|
2019-06-07 23:20:55 +02:00
|
|
|
None => None,
|
2019-06-05 17:52:47 +02:00
|
|
|
},
|
2019-06-07 23:20:55 +02:00
|
|
|
State::YieldQuote => match self.inner.peek() {
|
|
|
|
Some(_) => {
|
|
|
|
self.state = State::YieldStr;
|
|
|
|
Some("\\\"")
|
2019-06-05 17:52:47 +02:00
|
|
|
}
|
2019-06-07 23:20:55 +02:00
|
|
|
None => None,
|
|
|
|
},
|
2019-06-05 17:52:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Tries to quote the quotes in the passed `value`
|
|
|
|
pub fn put_quoted(buf: &mut BytesMut, value: &str) {
|
|
|
|
for part in Quoted::new(value) {
|
|
|
|
buf.extend_from_slice(part.as_bytes());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use std::str;
|
|
|
|
|
2020-12-01 02:21:56 +01:00
|
|
|
use actix_web::web::BytesMut;
|
2019-06-05 17:52:47 +02:00
|
|
|
|
|
|
|
use super::put_quoted;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_quote_str() {
|
|
|
|
let input = "a \"quoted\" string";
|
|
|
|
let mut output = BytesMut::new();
|
|
|
|
put_quoted(&mut output, input);
|
|
|
|
let result = str::from_utf8(&output).unwrap();
|
|
|
|
|
|
|
|
assert_eq!(result, "a \\\"quoted\\\" string");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_without_quotes() {
|
|
|
|
let input = "non-quoted string";
|
|
|
|
let mut output = BytesMut::new();
|
|
|
|
put_quoted(&mut output, input);
|
|
|
|
let result = str::from_utf8(&output).unwrap();
|
|
|
|
|
|
|
|
assert_eq!(result, "non-quoted string");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_starts_with_quote() {
|
|
|
|
let input = "\"first-quoted string";
|
|
|
|
let mut output = BytesMut::new();
|
|
|
|
put_quoted(&mut output, input);
|
|
|
|
let result = str::from_utf8(&output).unwrap();
|
|
|
|
|
|
|
|
assert_eq!(result, "\\\"first-quoted string");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ends_with_quote() {
|
|
|
|
let input = "last-quoted string\"";
|
|
|
|
let mut output = BytesMut::new();
|
|
|
|
put_quoted(&mut output, input);
|
|
|
|
let result = str::from_utf8(&output).unwrap();
|
|
|
|
|
|
|
|
assert_eq!(result, "last-quoted string\\\"");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_double_quote() {
|
|
|
|
let input = "quote\"\"string";
|
|
|
|
let mut output = BytesMut::new();
|
|
|
|
put_quoted(&mut output, input);
|
|
|
|
let result = str::from_utf8(&output).unwrap();
|
|
|
|
|
|
|
|
assert_eq!(result, "quote\\\"\\\"string");
|
2019-05-15 16:38:55 +02:00
|
|
|
}
|
|
|
|
}
|