diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 31743b0e35b24..fea85c5fb02d3 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1112,6 +1112,22 @@ impl String { self.vec.extend_from_slice(string.as_bytes()) } + #[unstable(feature = "string_push_str_slice", issue = "none")] + #[inline] + pub fn push_str_slice(&mut self, slice: &[&str]) { + let additional = slice.iter().map(|x| x.len()).sum(); + self.reserve(additional); + let (ptr, len, cap) = core::mem::take(self).into_raw_parts(); + unsafe { + let mut dst = ptr.add(len); + for new in slice { + core::ptr::copy_nonoverlapping(new.as_ptr(), dst, new.len()); + dst = dst.add(new.len()); + } + *self = String::from_raw_parts(ptr, len + additional, cap); + } + } + /// Copies elements from `src` range to the end of the string. /// /// # Panics diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 6bb8f2043f4bb..ad246ce9aebdd 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -2257,8 +2257,7 @@ pub(crate) fn compare_names(left: &str, right: &str) -> Ordering { pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String { let mut s = join_path_syms(&cx.current); - s.push_str("::"); - s.push_str(item.name.unwrap().as_str()); + crate::push_str_slice(&mut s, &["::", item.name.unwrap().as_str()]); s } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e88180c3033b2..ec2ed69c0890c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -18,6 +18,7 @@ #![feature(rustc_private)] #![feature(test)] #![feature(trim_prefix_suffix)] +#![feature(vec_into_raw_parts)] #![warn(rustc::internal)] // tidy-alphabetical-end @@ -983,3 +984,19 @@ fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) { tcxt.dcx().err(format!("cannot emit feature usage metrics: {error}")); } } + +#[inline] +fn push_str_slice(s: &mut String, slice: &[&str]) { + use std::ptr::copy_nonoverlapping; + let additional = slice.iter().map(|x| x.len()).sum(); + s.reserve(additional); + let (ptr, len, cap) = std::mem::take(s).into_raw_parts(); + unsafe { + let mut dst = ptr.add(len); + for new in slice { + copy_nonoverlapping(new.as_ptr(), dst, new.len()); + dst = dst.add(new.len()); + } + *s = String::from_raw_parts(ptr, len + additional, cap); + } +} diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index d09949e6868d6..410d7e94fdd12 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -223,8 +223,10 @@ impl UrlFragment { DefKind::Field => { let parent_id = tcx.parent(def_id); if tcx.def_kind(parent_id) == DefKind::Variant { - s.push_str("variant."); - s.push_str(tcx.item_name(parent_id).as_str()); + crate::push_str_slice( + s, + &["variant.", tcx.item_name(parent_id).as_str()], + ); ".field." } else { "structfield." @@ -232,8 +234,7 @@ impl UrlFragment { } kind => bug!("unexpected associated item kind: {kind:?}"), }; - s.push_str(kind); - s.push_str(tcx.item_name(def_id).as_str()); + crate::push_str_slice(s, &[kind, tcx.item_name(def_id).as_str()]); } UrlFragment::UserWritten(raw) => s.push_str(raw), }