Specialize OsString::push for strings

When concatenating two WTF-8 strings, surrogate pairs at the boundaries
need to be joined. However, since UTF-8 strings cannot contain surrogate
halves, this check can be skipped when one string is UTF-8. Specialize
`OsString::push` to use a more efficient concatenation in this case.

Unfortunately, a specialization for `T: AsRef<str>` conflicts with
`T: AsRef<OsStr>`, so stamp out string types with a macro.
This commit is contained in:
Thalia Archibald 2025-02-27 23:38:19 -08:00
parent 2874876243
commit a8d78fec52
3 changed files with 34 additions and 1 deletions

View File

@ -257,7 +257,30 @@ impl OsString {
#[inline]
#[rustc_confusables("append", "put")]
pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
self.inner.push_slice(&s.as_ref().inner)
trait SpecPushTo {
fn spec_push_to(&self, buf: &mut OsString);
}
impl<T: AsRef<OsStr>> SpecPushTo for T {
#[inline]
default fn spec_push_to(&self, buf: &mut OsString) {
buf.inner.push_slice(&self.as_ref().inner);
}
}
// Use a more efficient implementation when the string is UTF-8.
macro spec_str($T:ty) {
impl SpecPushTo for $T {
#[inline]
fn spec_push_to(&self, buf: &mut OsString) {
buf.inner.push_str(self);
}
}
}
spec_str!(str);
spec_str!(String);
s.spec_push_to(self)
}
/// Creates a new `OsString` with at least the given capacity.

View File

@ -139,6 +139,11 @@ impl Buf {
self.inner.extend_from_slice(&s.inner)
}
#[inline]
pub fn push_str(&mut self, s: &str) {
self.inner.extend_from_slice(s.as_bytes());
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.inner.reserve(additional)

View File

@ -116,6 +116,11 @@ impl Buf {
self.inner.push_wtf8(&s.inner)
}
#[inline]
pub fn push_str(&mut self, s: &str) {
self.inner.push_str(s);
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.inner.reserve(additional)