@@ -1693,49 +1693,41 @@ impl<'a> Formatter<'a> {
16931693 /// ```
16941694 #[stable(feature = "rust1", since = "1.0.0")]
16951695 pub fn pad(&mut self, s: &str) -> Result {
1696- // Make sure there's a fast path up front
1696+ // Make sure there's a fast path up front.
16971697 if self.options.width.is_none() && self.options.precision.is_none() {
16981698 return self.buf.write_str(s);
16991699 }
1700- // The `precision` field can be interpreted as a `max-width` for the
1700+
1701+ // The `precision` field can be interpreted as a maximum width for the
17011702 // string being formatted.
1702- let s = if let Some(max) = self.options.precision {
1703- // If our string is longer that the precision, then we must have
1704- // truncation. However other flags like `fill`, `width` and `align`
1705- // must act as always.
1706- if let Some((i, _)) = s.char_indices().nth(max) {
1707- // LLVM here can't prove that `..i` won't panic `&s[..i]`, but
1708- // we know that it can't panic. Use `get` + `unwrap_or` to avoid
1709- // `unsafe` and otherwise don't emit any panic-related code
1710- // here.
1711- s.get(..i).unwrap_or(s)
1712- } else {
1713- &s
1714- }
1703+ let (s, char_count) = if let Some(max_char_count) = self.options.precision {
1704+ let mut iter = s.char_indices();
1705+ let remaining = match iter.advance_by(max_char_count) {
1706+ Ok(()) => 0,
1707+ Err(remaining) => remaining.get(),
1708+ };
1709+ // SAFETY: The offset of `.char_indices()` is guaranteed to be
1710+ // in-bounds and between character boundaries.
1711+ let truncated = unsafe { s.get_unchecked(..iter.offset()) };
1712+ (truncated, max_char_count - remaining)
17151713 } else {
1716- &s
1714+ // Use the optimized char counting algorithm for the full string.
1715+ (s, s.chars().count())
17171716 };
1718- // The `width` field is more of a `min-width` parameter at this point.
1719- match self.options.width {
1720- // If we're under the maximum length, and there's no minimum length
1721- // requirements, then we can just emit the string
1722- None => self.buf.write_str(s),
1723- Some(width) => {
1724- let chars_count = s.chars().count();
1725- // If we're under the maximum width, check if we're over the minimum
1726- // width, if so it's as easy as just emitting the string.
1727- if chars_count >= width {
1728- self.buf.write_str(s)
1729- }
1730- // If we're under both the maximum and the minimum width, then fill
1731- // up the minimum width with the specified string + some alignment.
1732- else {
1733- let align = Alignment::Left;
1734- let post_padding = self.padding(width - chars_count, align)?;
1735- self.buf.write_str(s)?;
1736- post_padding.write(self)
1737- }
1738- }
1717+
1718+ // The `width` field is more of a minimum width parameter at this point.
1719+ if let Some(width) = self.options.width
1720+ && char_count < width
1721+ {
1722+ // If we're under the minimum width, then fill up the minimum width
1723+ // with the specified string + some alignment.
1724+ let post_padding = self.padding(width - char_count, Alignment::Left)?;
1725+ self.buf.write_str(s)?;
1726+ post_padding.write(self)
1727+ } else {
1728+ // If we're over the minimum width or there is no minimum width, we
1729+ // can just emit the string.
1730+ self.buf.write_str(s)
17391731 }
17401732 }
17411733
0 commit comments