Skip to content

Commit 40d9dcb

Browse files
committed
formatted padding with clojure
1 parent d3f16d2 commit 40d9dcb

File tree

2 files changed

+104
-99
lines changed

2 files changed

+104
-99
lines changed

library/core/src/fmt/mod.rs

Lines changed: 94 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,19 +1777,12 @@ impl<'a> Formatter<'a> {
17771777
// Helper methods used for padding and processing formatting arguments that
17781778
// all formatting traits can use.
17791779

1780-
/// Performs the correct padding for an integer which has already been
1781-
/// emitted into a str. The str should *not* contain the sign for the
1782-
/// integer, that will be added by this method.
1783-
///
1784-
/// # Arguments
1785-
///
1786-
/// * is_nonnegative - whether the original integer was either positive or zero.
1787-
/// * prefix - if the '#' character (Alternate) is provided, this
1788-
/// is the prefix to put in front of the number.
1789-
/// * buf - the byte array that the number has been formatted into
1790-
///
1791-
/// This function will correctly account for the flags provided as well as
1792-
/// the minimum width. It will not take precision into account.
1780+
/// Write a formatted integer to the Formatter. The `digits` string should
1781+
/// hold the representation of the absolute value, without sign. Whether a
1782+
/// sign ("+" or "-") is written depends both on format paramaters and on
1783+
/// `is_nonnegative`. The `prefix` (e.g., "0x") is written when alternate.
1784+
/// Padding may be included when width is Some. The precision is ignored
1785+
/// for integers.
17931786
///
17941787
/// # Examples
17951788
///
@@ -1822,8 +1815,8 @@ impl<'a> Formatter<'a> {
18221815
/// assert_eq!(format!("{:0>#8}", Foo::new(-1)), "00-Foo 1");
18231816
/// ```
18241817
#[stable(feature = "rust1", since = "1.0.0")]
1825-
pub fn pad_integral(&mut self, is_nonnegative: bool, prefix: &str, buf: &str) -> Result {
1826-
let mut width = buf.len();
1818+
pub fn pad_integral(&mut self, is_nonnegative: bool, prefix: &str, digits: &str) -> Result {
1819+
let mut width = digits.len();
18271820

18281821
let mut sign = None;
18291822
if !is_nonnegative {
@@ -1855,27 +1848,70 @@ impl<'a> Formatter<'a> {
18551848
if width >= usize::from(min) {
18561849
// We're over the minimum width, so then we can just write the bytes.
18571850
write_prefix(self, sign, prefix)?;
1858-
self.buf.write_str(buf)
1851+
self.buf.write_str(digits)
18591852
} else if self.sign_aware_zero_pad() {
18601853
// The sign and prefix goes before the padding if the fill character
18611854
// is zero
18621855
let old_options = self.options;
18631856
self.options.fill('0').align(Some(Alignment::Right));
18641857
write_prefix(self, sign, prefix)?;
18651858
let post_padding = self.padding(min - width as u16, Alignment::Right)?;
1866-
self.buf.write_str(buf)?;
1859+
self.buf.write_str(digits)?;
18671860
post_padding.write(self)?;
18681861
self.options = old_options;
18691862
Ok(())
18701863
} else {
18711864
// Otherwise, the sign and prefix goes after the padding
18721865
let post_padding = self.padding(min - width as u16, Alignment::Right)?;
18731866
write_prefix(self, sign, prefix)?;
1874-
self.buf.write_str(buf)?;
1867+
self.buf.write_str(digits)?;
18751868
post_padding.write(self)
18761869
}
18771870
}
18781871

1872+
/// Write a formatted number to the Formatter with a closure. The Fn should
1873+
/// write the representation of the absolute value, excluding `sign` (e.g.,
1874+
/// "+" or "-"). The implementation should follow [precision] when present.
1875+
/// The output of `write_abs` must match exactly the `write_len` amount of
1876+
/// `char`s in size. Padding may be written when [width] applies.
1877+
fn pad_number<F>(&mut self, sign: &str, write_len: usize, write_abs: F) -> Result
1878+
where
1879+
F: Fn(&mut Self) -> Result,
1880+
{
1881+
let out_len = write_len + sign.len();
1882+
// Pad when the width is higher than the output length.
1883+
let pad = self.width().unwrap_or(0).saturating_sub(out_len);
1884+
1885+
if pad == 0 || self.sign_aware_zero_pad() {
1886+
self.write_str(sign)?;
1887+
self.write_zeroes(pad)?;
1888+
return write_abs(self);
1889+
}
1890+
1891+
// Numbers align to the right by default.
1892+
let align = self.align().unwrap_or(Alignment::Right);
1893+
let (pad_before, pad_after) = match align {
1894+
Alignment::Left => (0, pad),
1895+
Alignment::Right => (pad, 0),
1896+
Alignment::Center => {
1897+
let split = pad / 2; // may round down
1898+
(split, pad - split)
1899+
}
1900+
};
1901+
1902+
// Write output with padding.
1903+
let fill = self.fill();
1904+
for _ in 0..pad_before {
1905+
self.write_char(fill)?;
1906+
}
1907+
self.write_str(sign)?;
1908+
write_abs(self)?;
1909+
for _ in 0..pad_after {
1910+
self.write_char(fill)?;
1911+
}
1912+
Ok(())
1913+
}
1914+
18791915
/// Takes a string slice and emits it to the internal buffer after applying
18801916
/// the relevant formatting flags specified.
18811917
///
@@ -1978,50 +2014,6 @@ impl<'a> Formatter<'a> {
19782014
///
19792015
/// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8.
19802016
unsafe fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
1981-
if self.options.width == 0 {
1982-
// this is the common case and we take a shortcut
1983-
// SAFETY: Per the precondition.
1984-
unsafe { self.write_formatted_parts(formatted) }
1985-
} else {
1986-
// for the sign-aware zero padding, we render the sign first and
1987-
// behave as if we had no sign from the beginning.
1988-
let mut formatted = formatted.clone();
1989-
let mut width = self.options.width;
1990-
let old_options = self.options;
1991-
if self.sign_aware_zero_pad() {
1992-
// a sign always goes first
1993-
let sign = formatted.sign;
1994-
self.buf.write_str(sign)?;
1995-
1996-
// remove the sign from the formatted parts
1997-
formatted.sign = "";
1998-
width = width.saturating_sub(sign.len() as u16);
1999-
self.options.fill('0').align(Some(Alignment::Right));
2000-
}
2001-
2002-
// remaining parts go through the ordinary padding process.
2003-
let len = formatted.len();
2004-
let ret = if usize::from(width) <= len {
2005-
// no padding
2006-
// SAFETY: Per the precondition.
2007-
unsafe { self.write_formatted_parts(&formatted) }
2008-
} else {
2009-
let post_padding = self.padding(width - len as u16, Alignment::Right)?;
2010-
// SAFETY: Per the precondition.
2011-
unsafe {
2012-
self.write_formatted_parts(&formatted)?;
2013-
}
2014-
post_padding.write(self)
2015-
};
2016-
self.options = old_options;
2017-
ret
2018-
}
2019-
}
2020-
2021-
/// # Safety
2022-
///
2023-
/// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8.
2024-
unsafe fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
20252017
unsafe fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result {
20262018
// SAFETY: This is used for `numfmt::Part::Num` and `numfmt::Part::Copy`.
20272019
// It's safe to use for `numfmt::Part::Num` since every char `c` is between
@@ -2030,39 +2022,51 @@ impl<'a> Formatter<'a> {
20302022
buf.write_str(unsafe { str::from_utf8_unchecked(s) })
20312023
}
20322024

2033-
if !formatted.sign.is_empty() {
2034-
self.buf.write_str(formatted.sign)?;
2035-
}
2036-
for part in formatted.parts {
2037-
match *part {
2038-
numfmt::Part::Zero(mut nzeroes) => {
2039-
const ZEROES: &str = // 64 zeroes
2040-
"0000000000000000000000000000000000000000000000000000000000000000";
2041-
while nzeroes > ZEROES.len() {
2042-
self.buf.write_str(ZEROES)?;
2043-
nzeroes -= ZEROES.len();
2025+
let sign = formatted.sign;
2026+
let out_len = formatted.len() - sign.len();
2027+
self.pad_number(sign, out_len, |f: &mut Self| {
2028+
for part in formatted.parts {
2029+
match *part {
2030+
numfmt::Part::Zero(nzeroes) => {
2031+
f.write_zeroes(nzeroes)?;
20442032
}
2045-
if nzeroes > 0 {
2046-
self.buf.write_str(&ZEROES[..nzeroes])?;
2047-
}
2048-
}
2049-
numfmt::Part::Num(mut v) => {
2050-
let mut s = [0; 5];
2051-
let len = part.len();
2052-
for c in s[..len].iter_mut().rev() {
2053-
*c = b'0' + (v % 10) as u8;
2054-
v /= 10;
2033+
numfmt::Part::Num(mut v) => {
2034+
let mut s = [0; 5];
2035+
let len = part.len();
2036+
for c in s[..len].iter_mut().rev() {
2037+
*c = b'0' + (v % 10) as u8;
2038+
v /= 10;
2039+
}
2040+
// SAFETY: Per the precondition.
2041+
unsafe {
2042+
write_bytes(f.buf, &s[..len])?;
2043+
}
20552044
}
20562045
// SAFETY: Per the precondition.
2057-
unsafe {
2058-
write_bytes(self.buf, &s[..len])?;
2059-
}
2046+
numfmt::Part::Copy(buf) => unsafe {
2047+
write_bytes(f.buf, buf)?;
2048+
},
20602049
}
2061-
// SAFETY: Per the precondition.
2062-
numfmt::Part::Copy(buf) => unsafe {
2063-
write_bytes(self.buf, buf)?;
2064-
},
20652050
}
2051+
Ok(())
2052+
})
2053+
}
2054+
2055+
/// Write n ASCII digits (U+0030) to the Formatter.
2056+
pub(crate) fn write_zeroes(&mut self, n: usize) -> Result {
2057+
#[cfg(feature = "optimize_for_size")]
2058+
{
2059+
for _ in 0..n {
2060+
self.write_char('0')?;
2061+
}
2062+
}
2063+
#[cfg(not(feature = "optimize_for_size"))]
2064+
{
2065+
const ZEROES: &str = "0000000000000000000000000000000000000000000000000000000000000000";
2066+
for _ in 0..(n / 64) {
2067+
self.write_str(ZEROES)?;
2068+
}
2069+
self.write_str(&ZEROES[..(n % 64)])?;
20662070
}
20672071
Ok(())
20682072
}

library/core/src/fmt/num.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
33
use crate::fmt::NumBuffer;
44
use crate::mem::MaybeUninit;
5-
use crate::num::fmt as numfmt;
65
use crate::{fmt, str};
76

87
/// Formatting of integers with a non-decimal radix.
@@ -531,21 +530,23 @@ macro_rules! impl_Exp {
531530
let as_str = unsafe { str::from_utf8_unchecked(text) };
532531
f.pad_integral(is_nonnegative, "", as_str)
533532
} else {
534-
let parts = &[
535-
numfmt::Part::Copy(&text[..coef_len]),
536-
numfmt::Part::Zero(more_prec),
537-
numfmt::Part::Copy(&text[coef_len..]),
538-
];
539533
let sign = if !is_nonnegative {
540534
"-"
541535
} else if f.sign_plus() {
542536
"+"
543537
} else {
544538
""
545539
};
546-
// SAFETY: Text is set with ASCII exclusively: either a decimal,
547-
// or a LETTER_E, or a dot. ASCII implies valid UTF-8.
548-
unsafe { f.pad_formatted_parts(&numfmt::Formatted { sign, parts }) }
540+
f.pad_number(sign, text.len() + more_prec, |w| {
541+
// SAFETY: Text is set with ASCII exclusively.
542+
let (coef_str, scale_str) = unsafe{(
543+
str::from_utf8_unchecked(&text[..coef_len]),
544+
str::from_utf8_unchecked(&text[coef_len..]),
545+
)};
546+
w.write_str(coef_str)?;
547+
w.write_zeroes(more_prec)?;
548+
w.write_str(scale_str)
549+
})
549550
}
550551
}
551552

0 commit comments

Comments
 (0)