Skip to content

Commit 6873b9f

Browse files
committed
Auto merge of #28357 - semmaz:libfmt-macros, r=alexcrichton
This changes libfmt_macros `CharIndices` iterator into `Peekable` so it can be used without `.clone()`. Also changed some `loop match` and `match` to `while let` and `if let` respectively (mostly for readability).
2 parents 483600e + 15d5c08 commit 6873b9f

File tree

1 file changed

+79
-112
lines changed

1 file changed

+79
-112
lines changed

src/libfmt_macros/lib.rs

Lines changed: 79 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub use self::Count::*;
3737

3838
use std::str;
3939
use std::string;
40+
use std::iter;
4041

4142
/// A piece is a portion of the format string which represents the next part
4243
/// to emit. These are emitted as a stream by the `Parser` class.
@@ -141,7 +142,7 @@ pub enum Count<'a> {
141142
/// necessary there's probably lots of room for improvement performance-wise.
142143
pub struct Parser<'a> {
143144
input: &'a str,
144-
cur: str::CharIndices<'a>,
145+
cur: iter::Peekable<str::CharIndices<'a>>,
145146
/// Error messages accumulated during parsing
146147
pub errors: Vec<string::String>,
147148
}
@@ -150,28 +151,31 @@ impl<'a> Iterator for Parser<'a> {
150151
type Item = Piece<'a>;
151152

152153
fn next(&mut self) -> Option<Piece<'a>> {
153-
match self.cur.clone().next() {
154-
Some((pos, '{')) => {
155-
self.cur.next();
156-
if self.consume('{') {
157-
Some(String(self.string(pos + 1)))
158-
} else {
159-
let ret = Some(NextArgument(self.argument()));
160-
self.must_consume('}');
161-
ret
154+
if let Some(&(pos, c)) = self.cur.peek() {
155+
match c {
156+
'{' => {
157+
self.cur.next();
158+
if self.consume('{') {
159+
Some(String(self.string(pos + 1)))
160+
} else {
161+
let ret = Some(NextArgument(self.argument()));
162+
self.must_consume('}');
163+
ret
164+
}
162165
}
163-
}
164-
Some((pos, '}')) => {
165-
self.cur.next();
166-
if self.consume('}') {
167-
Some(String(self.string(pos + 1)))
168-
} else {
169-
self.err("unmatched `}` found");
170-
None
166+
'}' => {
167+
self.cur.next();
168+
if self.consume('}') {
169+
Some(String(self.string(pos + 1)))
170+
} else {
171+
self.err("unmatched `}` found");
172+
None
173+
}
171174
}
175+
_ => Some(String(self.string(pos))),
172176
}
173-
Some((pos, _)) => { Some(String(self.string(pos))) }
174-
None => None
177+
} else {
178+
None
175179
}
176180
}
177181
}
@@ -181,7 +185,7 @@ impl<'a> Parser<'a> {
181185
pub fn new(s: &'a str) -> Parser<'a> {
182186
Parser {
183187
input: s,
184-
cur: s.char_indices(),
188+
cur: s.char_indices().peekable(),
185189
errors: vec!(),
186190
}
187191
}
@@ -197,61 +201,47 @@ impl<'a> Parser<'a> {
197201
/// the current position, then the current iterator isn't moved and false is
198202
/// returned, otherwise the character is consumed and true is returned.
199203
fn consume(&mut self, c: char) -> bool {
200-
match self.cur.clone().next() {
201-
Some((_, maybe)) if c == maybe => {
202-
self.cur.next();
203-
true
204-
}
205-
Some(..) | None => false,
204+
if let Some(&(_, maybe)) = self.cur.peek() {
205+
if c == maybe { self.cur.next(); true } else { false }
206+
} else {
207+
false
206208
}
207209
}
208210

209211
/// Forces consumption of the specified character. If the character is not
210212
/// found, an error is emitted.
211213
fn must_consume(&mut self, c: char) {
212214
self.ws();
213-
match self.cur.clone().next() {
214-
Some((_, maybe)) if c == maybe => {
215+
if let Some(&(_, maybe)) = self.cur.peek() {
216+
if c == maybe {
215217
self.cur.next();
218+
} else {
219+
self.err(&format!("expected `{:?}`, found `{:?}`", c, maybe));
216220
}
217-
Some((_, other)) => {
218-
self.err(&format!("expected `{:?}`, found `{:?}`", c,
219-
other));
220-
}
221-
None => {
222-
self.err(&format!("expected `{:?}` but string was terminated",
223-
c));
224-
}
221+
} else {
222+
self.err(&format!("expected `{:?}` but string was terminated", c));
225223
}
226224
}
227225

228226
/// Consumes all whitespace characters until the first non-whitespace
229227
/// character
230228
fn ws(&mut self) {
231-
loop {
232-
match self.cur.clone().next() {
233-
Some((_, c)) if c.is_whitespace() => { self.cur.next(); }
234-
Some(..) | None => { return }
235-
}
229+
while let Some(&(_, c)) = self.cur.peek() {
230+
if c.is_whitespace() { self.cur.next(); } else { break }
236231
}
237232
}
238233

239234
/// Parses all of a string which is to be considered a "raw literal" in a
240235
/// format string. This is everything outside of the braces.
241236
fn string(&mut self, start: usize) -> &'a str {
242-
loop {
243-
// we may not consume the character, so clone the iterator
244-
match self.cur.clone().next() {
245-
Some((pos, '}')) | Some((pos, '{')) => {
246-
return &self.input[start..pos];
247-
}
248-
Some(..) => { self.cur.next(); }
249-
None => {
250-
self.cur.next();
251-
return &self.input[start..self.input.len()];
252-
}
237+
// we may not consume the character, peek the iterator
238+
while let Some(&(pos, c)) = self.cur.peek() {
239+
match c {
240+
'{' | '}' => { return &self.input[start..pos]; }
241+
_ => { self.cur.next(); }
253242
}
254243
}
244+
&self.input[start..self.input.len()]
255245
}
256246

257247
/// Parses an Argument structure, or what's contained within braces inside
@@ -266,15 +256,14 @@ impl<'a> Parser<'a> {
266256
/// Parses a positional argument for a format. This could either be an
267257
/// integer index of an argument, a named argument, or a blank string.
268258
fn position(&mut self) -> Position<'a> {
269-
match self.integer() {
270-
Some(i) => { ArgumentIs(i) }
271-
None => {
272-
match self.cur.clone().next() {
273-
Some((_, c)) if c.is_alphabetic() => {
274-
ArgumentNamed(self.word())
275-
}
276-
_ => ArgumentNext
259+
if let Some(i) = self.integer() {
260+
ArgumentIs(i)
261+
} else {
262+
match self.cur.peek() {
263+
Some(&(_, c)) if c.is_alphabetic() => {
264+
ArgumentNamed(self.word())
277265
}
266+
_ => ArgumentNext
278267
}
279268
}
280269
}
@@ -293,17 +282,14 @@ impl<'a> Parser<'a> {
293282
if !self.consume(':') { return spec }
294283

295284
// fill character
296-
match self.cur.clone().next() {
297-
Some((_, c)) => {
298-
match self.cur.clone().skip(1).next() {
299-
Some((_, '>')) | Some((_, '<')) | Some((_, '^')) => {
300-
spec.fill = Some(c);
301-
self.cur.next();
302-
}
303-
Some(..) | None => {}
285+
if let Some(&(_, c)) = self.cur.peek() {
286+
match self.cur.clone().skip(1).next() {
287+
Some((_, '>')) | Some((_, '<')) | Some((_, '^')) => {
288+
spec.fill = Some(c);
289+
self.cur.next();
304290
}
291+
_ => {}
305292
}
306-
None => {}
307293
}
308294
// Alignment
309295
if self.consume('<') {
@@ -360,29 +346,20 @@ impl<'a> Parser<'a> {
360346
/// for 'CountIsNextParam' because that is only used in precision, not
361347
/// width.
362348
fn count(&mut self) -> Count<'a> {
363-
match self.integer() {
364-
Some(i) => {
349+
if let Some(i) = self.integer() {
350+
if self.consume('$') { CountIsParam(i) } else { CountIs(i) }
351+
} else {
352+
let tmp = self.cur.clone();
353+
let word = self.word();
354+
if word.is_empty() {
355+
self.cur = tmp;
356+
CountImplied
357+
} else {
365358
if self.consume('$') {
366-
CountIsParam(i)
359+
CountIsName(word)
367360
} else {
368-
CountIs(i)
369-
}
370-
}
371-
None => {
372-
let tmp = self.cur.clone();
373-
match self.word() {
374-
word if !word.is_empty() => {
375-
if self.consume('$') {
376-
CountIsName(word)
377-
} else {
378-
self.cur = tmp;
379-
CountImplied
380-
}
381-
}
382-
_ => {
383-
self.cur = tmp;
384-
CountImplied
385-
}
361+
self.cur = tmp;
362+
CountImplied
386363
}
387364
}
388365
}
@@ -392,32 +369,26 @@ impl<'a> Parser<'a> {
392369
/// be an alphabetic character followed by any number of alphanumeric
393370
/// characters.
394371
fn word(&mut self) -> &'a str {
395-
let start = match self.cur.clone().next() {
396-
Some((pos, c)) if c.is_xid_start() => {
397-
self.cur.next();
398-
pos
399-
}
400-
Some(..) | None => { return &self.input[..0]; }
372+
let start = match self.cur.peek() {
373+
Some(&(pos, c)) if c.is_xid_start() => { self.cur.next(); pos }
374+
_ => { return &self.input[..0]; }
401375
};
402-
let end;
403-
loop {
404-
match self.cur.clone().next() {
405-
Some((_, c)) if c.is_xid_continue() => {
406-
self.cur.next();
407-
}
408-
Some((pos, _)) => { end = pos; break }
409-
None => { end = self.input.len(); break }
376+
while let Some(&(pos, c)) = self.cur.peek() {
377+
if c.is_xid_continue() {
378+
self.cur.next();
379+
} else {
380+
return &self.input[start..pos];
410381
}
411382
}
412-
&self.input[start..end]
383+
&self.input[start..self.input.len()]
413384
}
414385

415386
/// Optionally parses an integer at the current position. This doesn't deal
416387
/// with overflow at all, it's just accumulating digits.
417388
fn integer(&mut self) -> Option<usize> {
418389
let mut cur = 0;
419390
let mut found = false;
420-
while let Some((_, c)) = self.cur.clone().next() {
391+
while let Some(&(_, c)) = self.cur.peek() {
421392
if let Some(i) = c.to_digit(10) {
422393
cur = cur * 10 + i as usize;
423394
found = true;
@@ -426,11 +397,7 @@ impl<'a> Parser<'a> {
426397
break
427398
}
428399
}
429-
if found {
430-
Some(cur)
431-
} else {
432-
None
433-
}
400+
if found { Some(cur) } else { None }
434401
}
435402
}
436403

0 commit comments

Comments
 (0)