Skip to content

Commit e633f15

Browse files
committed
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.
1 parent ed2157a commit e633f15

File tree

1 file changed

+57
-29
lines changed

1 file changed

+57
-29
lines changed

src/libcore/fmt/mod.rs

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,32 @@ pub fn write(output: &mut dyn Write, args: Arguments) -> Result {
10361036
Ok(())
10371037
}
10381038

1039+
/// Padding after the end of something. Returned by `Formatter::padding`.
1040+
#[must_use = "don't forget to write the post padding"]
1041+
struct PostPadding {
1042+
fill: [u8; 4],
1043+
fill_len: u32,
1044+
padding: usize,
1045+
}
1046+
1047+
impl PostPadding {
1048+
/// Safety relies on `fill[..fill_len]` being a valid UTF-8 char.
1049+
unsafe fn new(fill: [u8; 4], fill_len: u32, padding: usize) -> PostPadding {
1050+
PostPadding { fill, fill_len, padding }
1051+
}
1052+
1053+
/// Write this post padding.
1054+
fn write(self, buf: &mut dyn Write) -> Result {
1055+
let fill = unsafe {
1056+
str::from_utf8_unchecked(&self.fill.get_unchecked(..self.fill_len as usize))
1057+
};
1058+
for _ in 0..self.padding {
1059+
buf.write_str(fill)?;
1060+
}
1061+
Ok(())
1062+
}
1063+
}
1064+
10391065
impl<'a> Formatter<'a> {
10401066
fn wrap_buf<'b, 'c, F>(&'b mut self, wrap: F) -> Formatter<'c>
10411067
where 'b: 'c, F: FnOnce(&'b mut (dyn Write+'b)) -> &'c mut (dyn Write+'c)
@@ -1193,16 +1219,16 @@ impl<'a> Formatter<'a> {
11931219
self.fill = '0';
11941220
self.align = rt::v1::Alignment::Right;
11951221
write_prefix(self, sign, prefix)?;
1196-
self.with_padding(min - width, rt::v1::Alignment::Right, |f| {
1197-
f.buf.write_str(buf)
1198-
})
1222+
let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
1223+
self.buf.write_str(buf)?;
1224+
post_padding.write(self.buf)
11991225
}
12001226
// Otherwise, the sign and prefix goes after the padding
12011227
Some(min) => {
1202-
self.with_padding(min - width, rt::v1::Alignment::Right, |f| {
1203-
write_prefix(f, sign, prefix)?;
1204-
f.buf.write_str(buf)
1205-
})
1228+
let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
1229+
write_prefix(self, sign, prefix)?;
1230+
self.buf.write_str(buf)?;
1231+
post_padding.write(self.buf)
12061232
}
12071233
}
12081234
}
@@ -1273,19 +1299,21 @@ impl<'a> Formatter<'a> {
12731299
// up the minimum width with the specified string + some alignment.
12741300
Some(width) => {
12751301
let align = rt::v1::Alignment::Left;
1276-
self.with_padding(width - s.chars().count(), align, |me| {
1277-
me.buf.write_str(s)
1278-
})
1302+
let post_padding = self.padding(width - s.chars().count(), align)?;
1303+
self.buf.write_str(s)?;
1304+
post_padding.write(self.buf)
12791305
}
12801306
}
12811307
}
12821308

1283-
/// Runs a callback, emitting the correct padding either before or
1284-
/// afterwards depending on whether right or left alignment is requested.
1285-
fn with_padding<F>(&mut self, padding: usize, default: rt::v1::Alignment,
1286-
f: F) -> Result
1287-
where F: FnOnce(&mut Formatter) -> Result,
1288-
{
1309+
/// Write the pre-padding and return the unwritten post-padding. Callers are
1310+
/// responsible for ensuring post-padding is written after the thing that is
1311+
/// being padded.
1312+
fn padding(
1313+
&mut self,
1314+
padding: usize,
1315+
default: rt::v1::Alignment
1316+
) -> result::Result<PostPadding, Error> {
12891317
let align = match self.align {
12901318
rt::v1::Alignment::Unknown => default,
12911319
_ => self.align
@@ -1299,19 +1327,19 @@ impl<'a> Formatter<'a> {
12991327
};
13001328

13011329
let mut fill = [0; 4];
1302-
let fill = self.fill.encode_utf8(&mut fill);
1303-
1304-
for _ in 0..pre_pad {
1305-
self.buf.write_str(fill)?;
1306-
}
1330+
let fill_len = {
1331+
let fill = self.fill.encode_utf8(&mut fill);
13071332

1308-
f(self)?;
1333+
for _ in 0..pre_pad {
1334+
self.buf.write_str(fill)?;
1335+
}
13091336

1310-
for _ in 0..post_pad {
1311-
self.buf.write_str(fill)?;
1312-
}
1337+
fill.len()
1338+
};
13131339

1314-
Ok(())
1340+
Ok(unsafe {
1341+
PostPadding::new(fill, fill_len as u32, post_pad)
1342+
})
13151343
}
13161344

13171345
/// Takes the formatted parts and applies the padding.
@@ -1343,9 +1371,9 @@ impl<'a> Formatter<'a> {
13431371
let ret = if width <= len { // no padding
13441372
self.write_formatted_parts(&formatted)
13451373
} else {
1346-
self.with_padding(width - len, align, |f| {
1347-
f.write_formatted_parts(&formatted)
1348-
})
1374+
let post_padding = self.padding(width - len, align)?;
1375+
self.write_formatted_parts(&formatted)?;
1376+
post_padding.write(self.buf)
13491377
};
13501378
self.fill = old_fill;
13511379
self.align = old_align;

0 commit comments

Comments
 (0)