Skip to content

Commit 464aedc

Browse files
committed
Auto merge of rust-lang#137762 - thaliaarchi:io-optional-methods/write-fmt, r=<try>
Reserve before `write_fmt` for owned buffers `fmt::Arguments::estimated_capacity()` is currently only used by `fmt::format()` to reserve the initial string capacity. Also use it in `fmt::Write::write_fmt` for `String` and `OsString`; and `io::Write::write_fmt` for `Vec<u8>`, `VecDeque<u8>`, `Cursor<&mut Vec<u8>>`, and `Cursor<Vec<u8>>`. This may be worth checking perf.
2 parents a4a11ac + a1c03f3 commit 464aedc

File tree

5 files changed

+61
-2
lines changed

5 files changed

+61
-2
lines changed

library/alloc/src/string.rs

+9
Original file line numberDiff line numberDiff line change
@@ -3172,6 +3172,15 @@ impl fmt::Write for String {
31723172
self.push(c);
31733173
Ok(())
31743174
}
3175+
3176+
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
3177+
if let Some(s) = args.as_statically_known_str() {
3178+
self.write_str(s)
3179+
} else {
3180+
self.reserve(args.estimated_capacity());
3181+
fmt::write(self, args)
3182+
}
3183+
}
31753184
}
31763185

31773186
/// An iterator over the [`char`]s of a string.

library/core/src/fmt/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,9 @@ impl<'a> Arguments<'a> {
636636
/// when using `format!`. Note: this is neither the lower nor upper bound.
637637
#[inline]
638638
pub fn estimated_capacity(&self) -> usize {
639+
// Since the format args are constructed from a single string literal in
640+
// `format_args!`, the total length of the pieces is under `isize::MAX`
641+
// and this sum cannot overflow.
639642
let pieces_length: usize = self.pieces.iter().map(|x| x.len()).sum();
640643

641644
if self.args.is_empty() {
@@ -649,7 +652,8 @@ impl<'a> Arguments<'a> {
649652
// There are some arguments, so any additional push
650653
// will reallocate the string. To avoid that,
651654
// we're "pre-doubling" the capacity here.
652-
pieces_length.checked_mul(2).unwrap_or(0)
655+
// It cannot overflow, because the maximum length is `isize::MAX`.
656+
pieces_length * 2
653657
}
654658
}
655659
}

library/std/src/ffi/os_str.rs

+10
Original file line numberDiff line numberDiff line change
@@ -799,10 +799,20 @@ impl Hash for OsString {
799799

800800
#[stable(feature = "os_string_fmt_write", since = "1.64.0")]
801801
impl fmt::Write for OsString {
802+
#[inline]
802803
fn write_str(&mut self, s: &str) -> fmt::Result {
803804
self.push(s);
804805
Ok(())
805806
}
807+
808+
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
809+
if let Some(s) = args.as_statically_known_str() {
810+
self.write_str(s)
811+
} else {
812+
self.reserve(args.estimated_capacity());
813+
fmt::write(self, args)
814+
}
815+
}
806816
}
807817

808818
impl OsStr {

library/std/src/io/cursor.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
mod tests;
33

44
use crate::alloc::Allocator;
5-
use crate::cmp;
65
use crate::io::prelude::*;
76
use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
7+
use crate::{cmp, fmt};
88

99
/// A `Cursor` wraps an in-memory buffer and provides it with a
1010
/// [`Seek`] implementation.
@@ -647,6 +647,15 @@ where
647647
Ok(())
648648
}
649649

650+
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
651+
if let Some(s) = args.as_statically_known_str() {
652+
self.write_all(s.as_bytes())
653+
} else {
654+
self.inner.reserve(args.estimated_capacity());
655+
io::default_write_fmt(self, args)
656+
}
657+
}
658+
650659
#[inline]
651660
fn flush(&mut self) -> io::Result<()> {
652661
Ok(())
@@ -681,6 +690,15 @@ where
681690
Ok(())
682691
}
683692

693+
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
694+
if let Some(s) = args.as_statically_known_str() {
695+
self.write_all(s.as_bytes())
696+
} else {
697+
self.inner.reserve(args.estimated_capacity());
698+
io::default_write_fmt(self, args)
699+
}
700+
}
701+
684702
#[inline]
685703
fn flush(&mut self) -> io::Result<()> {
686704
Ok(())

library/std/src/io/impls.rs

+18
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,15 @@ impl<A: Allocator> Write for Vec<u8, A> {
511511
Ok(())
512512
}
513513

514+
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
515+
if let Some(s) = args.as_statically_known_str() {
516+
self.write_all(s.as_bytes())
517+
} else {
518+
self.reserve(args.estimated_capacity());
519+
io::default_write_fmt(self, args)
520+
}
521+
}
522+
514523
#[inline]
515524
fn flush(&mut self) -> io::Result<()> {
516525
Ok(())
@@ -662,6 +671,15 @@ impl<A: Allocator> Write for VecDeque<u8, A> {
662671
Ok(())
663672
}
664673

674+
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
675+
if let Some(s) = args.as_statically_known_str() {
676+
self.write_all(s.as_bytes())
677+
} else {
678+
self.reserve(args.estimated_capacity());
679+
io::default_write_fmt(self, args)
680+
}
681+
}
682+
665683
#[inline]
666684
fn flush(&mut self) -> io::Result<()> {
667685
Ok(())

0 commit comments

Comments
 (0)