diff options
| author | Lakelezz <[email protected]> | 2017-12-24 12:27:25 +0100 |
|---|---|---|
| committer | alex <[email protected]> | 2017-12-24 12:27:25 +0100 |
| commit | 9aad1aa375168d6131cb6f68d6998b2af6fb00a3 (patch) | |
| tree | 6332f3ad7b38fb798421d2d73a48b966ca84673d | |
| parent | Update model to include new voice regions (#240) (diff) | |
| download | serenity-9aad1aa375168d6131cb6f68d6998b2af6fb00a3.tar.xz serenity-9aad1aa375168d6131cb6f68d6998b2af6fb00a3.zip | |
Fix `multiple_quoted` (#241)
| -rw-r--r-- | src/framework/standard/args.rs | 100 | ||||
| -rw-r--r-- | tests/test_args.rs | 41 |
2 files changed, 78 insertions, 63 deletions
diff --git a/src/framework/standard/args.rs b/src/framework/standard/args.rs index 7633bf8..33ec9fe 100644 --- a/src/framework/standard/args.rs +++ b/src/framework/standard/args.rs @@ -10,12 +10,6 @@ pub enum Error<E: StdError> { /// A parsing operation failed; the error in it can be of any returned from the `FromStr` /// trait. Parse(E), - /// Occurs if e.g. `multiple_quoted` is used but the input starts with not the expected - /// value. - /// It contains how many bytes have to be removed until the first `"` appears. - InvalidStart(usize), - /// If the string contains no quote. - NoQuote, } impl<E: StdError> From<E> for Error<E> { @@ -31,8 +25,6 @@ impl<E: StdError> StdError for Error<E> { match *self { Eos => "end-of-string", Parse(ref e) => e.description(), - InvalidStart(_) => "Invalid Start", - NoQuote => "No quote exists", } } @@ -53,8 +45,6 @@ impl<E: StdError> fmt::Display for Error<E> { match *self { Eos => write!(f, "end of string"), Parse(ref e) => fmt::Display::fmt(&e, f), - InvalidStart(pos) => write!(f, "Invalid Start, {} bytes until first `\"`.", pos), - NoQuote => write!(f, "No quote exists"), } } } @@ -68,31 +58,32 @@ fn second_quote_occurence(s: &str) -> Option<usize> { fn parse_quotes<T: FromStr>(s: &mut String, delimiters: &[String]) -> Result<T, T::Err> where T::Err: StdError { - // Fall back to `parse` if there're no quotes at the start. - if !s.starts_with('"') { - if let Some(pos) = s.find('"') { - return Err(Error::InvalidStart(pos)); - } else { - return Err(Error::NoQuote); - } - } + // Fall back to `parse` if there're no quotes at the start + // or if there is no closing one as well. + if let Some(mut pos) = second_quote_occurence(s) { - let mut pos = second_quote_occurence(s).unwrap_or_else(|| s.len()); - let res = (&s[1..pos]).parse::<T>().map_err(Error::Parse); + if s.starts_with('"') { + let res = (&s[1..pos]).parse::<T>().map_err(Error::Parse); + pos += '"'.len_utf8(); - pos += '"'.len_utf8(); + for delimiter in delimiters { + + if s[pos..].starts_with(delimiter) { + pos += delimiter.len(); + break; + } + } - for delimiter in delimiters { + s.drain(..pos); - if s[pos..].starts_with(delimiter) { - pos += delimiter.len(); - break; + res + } else { + return parse::<T>(s, delimiters) } - } - s.drain(..pos); - - res + } else { + return parse::<T>(s, delimiters) + } } @@ -281,20 +272,13 @@ impl Args { } else if let Some(len_quoted) = self.len_quoted { len_quoted } else { - let mut message = self.message.clone(); - let count = message.chars().filter(|&c| c == '"').count() / 2; - let mut len_counter = 0; - - for _ in 0..count { + let countable_self = self.clone(); - if parse_quotes::<String>(&mut message, &self.delimiters).is_ok() { - len_counter += 1; - } else { - return len_counter; - } + if let Ok(ref vec) = countable_self.multiple_quoted::<String>() { + vec.iter().count() + } else { + 0 } - - len_counter } } @@ -410,15 +394,7 @@ impl Args { /// [`multiple`]: #method.multiple pub fn multiple_quoted<T: FromStr>(mut self) -> Result<Vec<T>, T::Err> where T::Err: StdError { - let mut res = Vec::new(); - - let count = self.message.chars().filter(|&c| c == '"').count() / 2; - - for _ in 0..count { - res.push(parse_quotes::<T>(&mut self.message, &self.delimiters)?); - } - - Ok(res) + IterQuoted::<T>::new(&mut self).collect() } /// Empty outs the internal vector while parsing (if necessary) and returning them. @@ -619,3 +595,27 @@ impl<'a, T: FromStr> Iterator for Iter<'a, T> where T::Err: StdError { } } } + +// Same as `Iter`, but considers quotes. +pub struct IterQuoted<'a, T: FromStr> where T::Err: StdError { + args: &'a mut Args, + _marker: PhantomData<T>, +} + +impl<'a, T: FromStr> IterQuoted<'a, T> where T::Err: StdError { + fn new(args: &'a mut Args) -> Self { + IterQuoted { args, _marker: PhantomData } + } +} + +impl<'a, T: FromStr> Iterator for IterQuoted<'a, T> where T::Err: StdError { + type Item = Result<T, T::Err>; + + fn next(&mut self) -> Option<Self::Item> { + if self.args.is_empty() { + None + } else { + Some(self.args.single_quoted::<T>()) + } + } +} diff --git a/tests/test_args.rs b/tests/test_args.rs index ab3cab2..ab49271 100644 --- a/tests/test_args.rs +++ b/tests/test_args.rs @@ -82,14 +82,14 @@ fn full_on_args() { fn multiple_quoted_strings_one_delimiter() { let args = Args::new(r#""1, 2" "a" "3" 4 "5"#, &[" ".to_string()]); - assert_eq!(args.multiple_quoted::<String>().unwrap(), ["1, 2", "a", "3"]); + assert_eq!(args.multiple_quoted::<String>().unwrap(), ["1, 2", "a", "3", "4", "\"5"]); } #[test] fn multiple_quoted_strings_with_multiple_delimiter() { let args = Args::new(r#""1, 2" "a","3"4 "5"#, &[" ".to_string(), ",".to_string()]); - assert_eq!(args.multiple_quoted::<String>().unwrap(), ["1, 2", "a", "3"]); + assert_eq!(args.multiple_quoted::<String>().unwrap(), ["1, 2", "a", "3", "4", "\"5"]); } #[test] @@ -103,28 +103,43 @@ fn multiple_quoted_strings_with_multiple_delimiters() { fn multiple_quoted_i32() { let args = Args::new(r#""1" "2" 3"#, &[" ".to_string()]); - assert_eq!(args.multiple_quoted::<i32>().unwrap(), [1, 2]); + assert_eq!(args.multiple_quoted::<i32>().unwrap(), [1, 2, 3]); } #[test] -fn multiple_quoted_missing_quote() { - let args = Args::new(r#"hello, my name is cake" "2"#, &[",".to_string(), " ".to_string()]); +fn multiple_quoted_quote_appears_without_delimiter_in_front() { + let args = Args::new(r#"hello, my name is cake" 2"#, &[",".to_string(), " ".to_string()]); - assert_matches!(args.multiple_quoted::<String>().unwrap_err(), ArgError::InvalidStart(22)); + assert_eq!(args.multiple_quoted::<String>().unwrap(), ["hello", "", "my", "name", "is", "cake\"", "2"]); } #[test] +fn multiple_quoted_single_quote() { + let args = Args::new(r#"hello "2 b"#, &[",".to_string(), " ".to_string()]); + + assert_eq!(args.multiple_quoted::<String>().unwrap(), ["hello", "\"2", "b"]); +} + +#[test] +fn multiple_quoted_one_quote_pair() { + let args = Args::new(r#"hello "2 b""#, &[",".to_string(), " ".to_string()]); + + assert_eq!(args.multiple_quoted::<String>().unwrap(), ["hello", "2 b"]); +} + + +#[test] fn delimiter_before_multiple_quoted() { let args = Args::new(r#","hello, my name is cake" "2""#, &[",".to_string(), " ".to_string()]); - assert_matches!(args.multiple_quoted::<String>().unwrap_err(), ArgError::InvalidStart(1)); + assert_eq!(args.multiple_quoted::<String>().unwrap(), ["", "hello, my name is cake", "2"]); } #[test] fn no_quote() { let args = Args::new("hello, my name is cake", &[",".to_string(), " ".to_string()]); - assert_matches!(args.single_quoted_n::<String>().unwrap_err(), ArgError::NoQuote); + assert_eq!(args.single_quoted_n::<String>().unwrap(), "hello"); } #[test] @@ -331,10 +346,10 @@ fn single_after_failed_single() { } #[test] -fn len_after_failed_single_quoted() { +fn len_quoted_after_failed_single_quoted() { let mut args = Args::new("b a", &[" ".to_string()]); - assert_eq!(args.len_quoted(), 0); - assert_matches!(args.single_quoted::<i32>().unwrap_err(), ArgError::NoQuote); - assert_eq!(args.len_quoted(), 0); -}
\ No newline at end of file + assert_eq!(args.len_quoted(), 2); + assert_matches!(args.single_quoted::<i32>().unwrap_err(), ArgError::Parse(_)); + assert_eq!(args.len_quoted(), 1); +} |