diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 32a5bd906fcd7..9c02ccb08acd8 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -37,6 +37,7 @@ pub use self::Count::*; use std::str; use std::string; +use std::iter; /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. @@ -141,7 +142,7 @@ pub enum Count<'a> { /// necessary there's probably lots of room for improvement performance-wise. pub struct Parser<'a> { input: &'a str, - cur: str::CharIndices<'a>, + cur: iter::Peekable>, /// Error messages accumulated during parsing pub errors: Vec, } @@ -150,28 +151,31 @@ impl<'a> Iterator for Parser<'a> { type Item = Piece<'a>; fn next(&mut self) -> Option> { - match self.cur.clone().next() { - Some((pos, '{')) => { - self.cur.next(); - if self.consume('{') { - Some(String(self.string(pos + 1))) - } else { - let ret = Some(NextArgument(self.argument())); - self.must_consume('}'); - ret + if let Some(&(pos, c)) = self.cur.peek() { + match c { + '{' => { + self.cur.next(); + if self.consume('{') { + Some(String(self.string(pos + 1))) + } else { + let ret = Some(NextArgument(self.argument())); + self.must_consume('}'); + ret + } } - } - Some((pos, '}')) => { - self.cur.next(); - if self.consume('}') { - Some(String(self.string(pos + 1))) - } else { - self.err("unmatched `}` found"); - None + '}' => { + self.cur.next(); + if self.consume('}') { + Some(String(self.string(pos + 1))) + } else { + self.err("unmatched `}` found"); + None + } } + _ => Some(String(self.string(pos))), } - Some((pos, _)) => { Some(String(self.string(pos))) } - None => None + } else { + None } } } @@ -181,7 +185,7 @@ impl<'a> Parser<'a> { pub fn new(s: &'a str) -> Parser<'a> { Parser { input: s, - cur: s.char_indices(), + cur: s.char_indices().peekable(), errors: vec!(), } } @@ -197,12 +201,10 @@ impl<'a> Parser<'a> { /// the current position, then the current iterator isn't moved and false is /// returned, otherwise the character is consumed and true is returned. fn consume(&mut self, c: char) -> bool { - match self.cur.clone().next() { - Some((_, maybe)) if c == maybe => { - self.cur.next(); - true - } - Some(..) | None => false, + if let Some(&(_, maybe)) = self.cur.peek() { + if c == maybe { self.cur.next(); true } else { false } + } else { + false } } @@ -210,48 +212,36 @@ impl<'a> Parser<'a> { /// found, an error is emitted. fn must_consume(&mut self, c: char) { self.ws(); - match self.cur.clone().next() { - Some((_, maybe)) if c == maybe => { + if let Some(&(_, maybe)) = self.cur.peek() { + if c == maybe { self.cur.next(); + } else { + self.err(&format!("expected `{:?}`, found `{:?}`", c, maybe)); } - Some((_, other)) => { - self.err(&format!("expected `{:?}`, found `{:?}`", c, - other)); - } - None => { - self.err(&format!("expected `{:?}` but string was terminated", - c)); - } + } else { + self.err(&format!("expected `{:?}` but string was terminated", c)); } } /// Consumes all whitespace characters until the first non-whitespace /// character fn ws(&mut self) { - loop { - match self.cur.clone().next() { - Some((_, c)) if c.is_whitespace() => { self.cur.next(); } - Some(..) | None => { return } - } + while let Some(&(_, c)) = self.cur.peek() { + if c.is_whitespace() { self.cur.next(); } else { break } } } /// Parses all of a string which is to be considered a "raw literal" in a /// format string. This is everything outside of the braces. fn string(&mut self, start: usize) -> &'a str { - loop { - // we may not consume the character, so clone the iterator - match self.cur.clone().next() { - Some((pos, '}')) | Some((pos, '{')) => { - return &self.input[start..pos]; - } - Some(..) => { self.cur.next(); } - None => { - self.cur.next(); - return &self.input[start..self.input.len()]; - } + // we may not consume the character, peek the iterator + while let Some(&(pos, c)) = self.cur.peek() { + match c { + '{' | '}' => { return &self.input[start..pos]; } + _ => { self.cur.next(); } } } + &self.input[start..self.input.len()] } /// Parses an Argument structure, or what's contained within braces inside @@ -266,15 +256,14 @@ impl<'a> Parser<'a> { /// Parses a positional argument for a format. This could either be an /// integer index of an argument, a named argument, or a blank string. fn position(&mut self) -> Position<'a> { - match self.integer() { - Some(i) => { ArgumentIs(i) } - None => { - match self.cur.clone().next() { - Some((_, c)) if c.is_alphabetic() => { - ArgumentNamed(self.word()) - } - _ => ArgumentNext + if let Some(i) = self.integer() { + ArgumentIs(i) + } else { + match self.cur.peek() { + Some(&(_, c)) if c.is_alphabetic() => { + ArgumentNamed(self.word()) } + _ => ArgumentNext } } } @@ -293,17 +282,14 @@ impl<'a> Parser<'a> { if !self.consume(':') { return spec } // fill character - match self.cur.clone().next() { - Some((_, c)) => { - match self.cur.clone().skip(1).next() { - Some((_, '>')) | Some((_, '<')) | Some((_, '^')) => { - spec.fill = Some(c); - self.cur.next(); - } - Some(..) | None => {} + if let Some(&(_, c)) = self.cur.peek() { + match self.cur.clone().skip(1).next() { + Some((_, '>')) | Some((_, '<')) | Some((_, '^')) => { + spec.fill = Some(c); + self.cur.next(); } + _ => {} } - None => {} } // Alignment if self.consume('<') { @@ -360,29 +346,20 @@ impl<'a> Parser<'a> { /// for 'CountIsNextParam' because that is only used in precision, not /// width. fn count(&mut self) -> Count<'a> { - match self.integer() { - Some(i) => { + if let Some(i) = self.integer() { + if self.consume('$') { CountIsParam(i) } else { CountIs(i) } + } else { + let tmp = self.cur.clone(); + let word = self.word(); + if word.is_empty() { + self.cur = tmp; + CountImplied + } else { if self.consume('$') { - CountIsParam(i) + CountIsName(word) } else { - CountIs(i) - } - } - None => { - let tmp = self.cur.clone(); - match self.word() { - word if !word.is_empty() => { - if self.consume('$') { - CountIsName(word) - } else { - self.cur = tmp; - CountImplied - } - } - _ => { - self.cur = tmp; - CountImplied - } + self.cur = tmp; + CountImplied } } } @@ -392,24 +369,18 @@ impl<'a> Parser<'a> { /// be an alphabetic character followed by any number of alphanumeric /// characters. fn word(&mut self) -> &'a str { - let start = match self.cur.clone().next() { - Some((pos, c)) if c.is_xid_start() => { - self.cur.next(); - pos - } - Some(..) | None => { return &self.input[..0]; } + let start = match self.cur.peek() { + Some(&(pos, c)) if c.is_xid_start() => { self.cur.next(); pos } + _ => { return &self.input[..0]; } }; - let end; - loop { - match self.cur.clone().next() { - Some((_, c)) if c.is_xid_continue() => { - self.cur.next(); - } - Some((pos, _)) => { end = pos; break } - None => { end = self.input.len(); break } + while let Some(&(pos, c)) = self.cur.peek() { + if c.is_xid_continue() { + self.cur.next(); + } else { + return &self.input[start..pos]; } } - &self.input[start..end] + &self.input[start..self.input.len()] } /// Optionally parses an integer at the current position. This doesn't deal @@ -417,7 +388,7 @@ impl<'a> Parser<'a> { fn integer(&mut self) -> Option { let mut cur = 0; let mut found = false; - while let Some((_, c)) = self.cur.clone().next() { + while let Some(&(_, c)) = self.cur.peek() { if let Some(i) = c.to_digit(10) { cur = cur * 10 + i as usize; found = true; @@ -426,11 +397,7 @@ impl<'a> Parser<'a> { break } } - if found { - Some(cur) - } else { - None - } + if found { Some(cur) } else { None } } }