diff options
| author | Nick Fitzgerald <fitzgen@gmail.com> | 2019-02-07 15:01:30 +0100 |
|---|---|---|
| committer | Nick Fitzgerald <fitzgen@gmail.com> | 2019-02-07 15:01:30 +0100 |
| commit | e633f152397545c2fd80795fc928ec555656b2ab (patch) | |
| tree | c0b8820291c5d5732b2f1196350fa9783f856355 /src/libcore | |
| parent | ed2157a38f6ccdfe460f2f058f60a67daac6cc5a (diff) | |
| download | rust-e633f152397545c2fd80795fc928ec555656b2ab.tar.gz rust-e633f152397545c2fd80795fc928ec555656b2ab.zip | |
Un-monomorphize and inline formatting with padding
The generic `F` in `with_padding` was causing a bunch of stuff to get inlined that otherwise needn't be, blowing up code size.
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/fmt/mod.rs | 86 |
1 files changed, 57 insertions, 29 deletions
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index dd95e3b4a7c..605779046ef 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1036,6 +1036,32 @@ pub fn write(output: &mut dyn Write, args: Arguments) -> Result { Ok(()) } +/// Padding after the end of something. Returned by `Formatter::padding`. +#[must_use = "don't forget to write the post padding"] +struct PostPadding { + fill: [u8; 4], + fill_len: u32, + padding: usize, +} + +impl PostPadding { + /// Safety relies on `fill[..fill_len]` being a valid UTF-8 char. + unsafe fn new(fill: [u8; 4], fill_len: u32, padding: usize) -> PostPadding { + PostPadding { fill, fill_len, padding } + } + + /// Write this post padding. + fn write(self, buf: &mut dyn Write) -> Result { + let fill = unsafe { + str::from_utf8_unchecked(&self.fill.get_unchecked(..self.fill_len as usize)) + }; + for _ in 0..self.padding { + buf.write_str(fill)?; + } + Ok(()) + } +} + impl<'a> Formatter<'a> { fn wrap_buf<'b, 'c, F>(&'b mut self, wrap: F) -> Formatter<'c> where 'b: 'c, F: FnOnce(&'b mut (dyn Write+'b)) -> &'c mut (dyn Write+'c) @@ -1193,16 +1219,16 @@ impl<'a> Formatter<'a> { self.fill = '0'; self.align = rt::v1::Alignment::Right; write_prefix(self, sign, prefix)?; - self.with_padding(min - width, rt::v1::Alignment::Right, |f| { - f.buf.write_str(buf) - }) + let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; + self.buf.write_str(buf)?; + post_padding.write(self.buf) } // Otherwise, the sign and prefix goes after the padding Some(min) => { - self.with_padding(min - width, rt::v1::Alignment::Right, |f| { - write_prefix(f, sign, prefix)?; - f.buf.write_str(buf) - }) + let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; + write_prefix(self, sign, prefix)?; + self.buf.write_str(buf)?; + post_padding.write(self.buf) } } } @@ -1273,19 +1299,21 @@ impl<'a> Formatter<'a> { // up the minimum width with the specified string + some alignment. Some(width) => { let align = rt::v1::Alignment::Left; - self.with_padding(width - s.chars().count(), align, |me| { - me.buf.write_str(s) - }) + let post_padding = self.padding(width - s.chars().count(), align)?; + self.buf.write_str(s)?; + post_padding.write(self.buf) } } } - /// Runs a callback, emitting the correct padding either before or - /// afterwards depending on whether right or left alignment is requested. - fn with_padding<F>(&mut self, padding: usize, default: rt::v1::Alignment, - f: F) -> Result - where F: FnOnce(&mut Formatter) -> Result, - { + /// Write the pre-padding and return the unwritten post-padding. Callers are + /// responsible for ensuring post-padding is written after the thing that is + /// being padded. + fn padding( + &mut self, + padding: usize, + default: rt::v1::Alignment + ) -> result::Result<PostPadding, Error> { let align = match self.align { rt::v1::Alignment::Unknown => default, _ => self.align @@ -1299,19 +1327,19 @@ impl<'a> Formatter<'a> { }; let mut fill = [0; 4]; - let fill = self.fill.encode_utf8(&mut fill); - - for _ in 0..pre_pad { - self.buf.write_str(fill)?; - } + let fill_len = { + let fill = self.fill.encode_utf8(&mut fill); - f(self)?; + for _ in 0..pre_pad { + self.buf.write_str(fill)?; + } - for _ in 0..post_pad { - self.buf.write_str(fill)?; - } + fill.len() + }; - Ok(()) + Ok(unsafe { + PostPadding::new(fill, fill_len as u32, post_pad) + }) } /// Takes the formatted parts and applies the padding. @@ -1343,9 +1371,9 @@ impl<'a> Formatter<'a> { let ret = if width <= len { // no padding self.write_formatted_parts(&formatted) } else { - self.with_padding(width - len, align, |f| { - f.write_formatted_parts(&formatted) - }) + let post_padding = self.padding(width - len, align)?; + self.write_formatted_parts(&formatted)?; + post_padding.write(self.buf) }; self.fill = old_fill; self.align = old_align; |
