Skip to content

Commit 91cf0c3

Browse files
committed
Auto merge of #142667 - yotamofek:pr/rustdoc/more-write-shared-perf, r=<try>
Avoid a few more allocations in `write_shared.rs` Inspired by #141421 , avoids a few `Vec`, `PathBuf` and `String` allocations in `write_shared.rs`. I don't think these will show up on benchmarks, but are still worthwhile IMHO. Also includes a few small cleanups. r? nnethercote - if you'd like :)
2 parents 1bb3352 + 56fe2f6 commit 91cf0c3

File tree

2 files changed

+34
-42
lines changed

2 files changed

+34
-42
lines changed

src/librustdoc/html/render/sorted_template.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::borrow::Cow;
12
use std::collections::BTreeSet;
23
use std::fmt::{self, Write as _};
34
use std::marker::PhantomData;
@@ -12,8 +13,8 @@ use serde::{Deserialize, Serialize};
1213
#[derive(Debug, Clone)]
1314
pub(crate) struct SortedTemplate<F> {
1415
format: PhantomData<F>,
15-
before: String,
16-
after: String,
16+
before: Cow<'static, str>,
17+
after: Cow<'static, str>,
1718
fragments: BTreeSet<String>,
1819
}
1920

@@ -38,14 +39,20 @@ impl<F> SortedTemplate<F> {
3839
if split.next().is_some() {
3940
return Err(Error("delimiter should appear at most once"));
4041
}
41-
Ok(Self::from_before_after(before, after))
42+
Ok(Self::from_before_after(before.to_string(), after.to_string()))
4243
}
4344

4445
/// Template will insert fragments between `before` and `after`
45-
pub(crate) fn from_before_after<S: ToString, T: ToString>(before: S, after: T) -> Self {
46-
let before = before.to_string();
47-
let after = after.to_string();
48-
Self { format: PhantomData, before, after, fragments: Default::default() }
46+
pub(crate) fn from_before_after(
47+
before: impl Into<Cow<'static, str>>,
48+
after: impl Into<Cow<'static, str>>,
49+
) -> Self {
50+
Self {
51+
format: PhantomData,
52+
before: before.into(),
53+
after: after.into(),
54+
fragments: Default::default(),
55+
}
4956
}
5057
}
5158

@@ -102,8 +109,8 @@ impl<F: FileFormat> FromStr for SortedTemplate<F> {
102109
}
103110
Ok(Self {
104111
format: PhantomData,
105-
before: before.to_string(),
106-
after: s.to_string(),
112+
before: before.to_string().into(),
113+
after: s.to_string().into(),
107114
fragments,
108115
})
109116
}

src/librustdoc/html/render/write_shared.rs

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//! --resource-suffix flag and are emitted when --emit-type is empty (default)
1414
//! or contains "invocation-specific".
1515
16+
use std::borrow::Cow;
1617
use std::cell::RefCell;
1718
use std::ffi::OsString;
1819
use std::fs::File;
@@ -284,7 +285,7 @@ enum CrateInfoVersion {
284285
#[derive(Serialize, Deserialize, Debug, Clone)]
285286
#[serde(transparent)]
286287
struct PartsAndLocations<P> {
287-
parts: Vec<(PathBuf, P)>,
288+
parts: Vec<(Cow<'static, Path>, P)>,
288289
}
289290

290291
impl<P> Default for PartsAndLocations<P> {
@@ -294,12 +295,12 @@ impl<P> Default for PartsAndLocations<P> {
294295
}
295296

296297
impl<T, U> PartsAndLocations<Part<T, U>> {
297-
fn push(&mut self, path: PathBuf, item: U) {
298-
self.parts.push((path, Part { _artifact: PhantomData, item }));
298+
fn push(&mut self, path: impl Into<Cow<'static, Path>>, item: U) {
299+
self.parts.push((path.into(), Part { _artifact: PhantomData, item }));
299300
}
300301

301302
/// Singleton part, one file
302-
fn with(path: PathBuf, part: U) -> Self {
303+
fn with(path: impl Into<Cow<'static, Path>>, part: U) -> Self {
303304
let mut ret = Self::default();
304305
ret.push(path, part);
305306
ret
@@ -439,24 +440,20 @@ impl CratesIndexPart {
439440
let content =
440441
format!("<h1>List of all crates</h1><ul class=\"all-items\">{DELIMITER}</ul>");
441442
let template = layout::render(layout, &page, "", content, style_files);
442-
match SortedTemplate::from_template(&template, DELIMITER) {
443-
Ok(template) => template,
444-
Err(e) => panic!(
445-
"Object Replacement Character (U+FFFC) should not appear in the --index-page: {e}"
446-
),
447-
}
443+
SortedTemplate::from_template(&template, DELIMITER)
444+
.expect("Object Replacement Character (U+FFFC) should not appear in the --index-page")
448445
}
449446

450447
/// Might return parts that are duplicate with ones in prexisting index.html
451448
fn get(crate_name: &str, external_crates: &[String]) -> Result<PartsAndLocations<Self>, Error> {
452449
let mut ret = PartsAndLocations::default();
453-
let path = PathBuf::from("index.html");
450+
let path = Path::new("index.html");
454451
for crate_name in external_crates.iter().map(|s| s.as_str()).chain(once(crate_name)) {
455452
let part = format!(
456453
"<li><a href=\"{trailing_slash}index.html\">{crate_name}</a></li>",
457454
trailing_slash = ensure_trailing_slash(crate_name),
458455
);
459-
ret.push(path.clone(), part);
456+
ret.push(path, part);
460457
}
461458
Ok(ret)
462459
}
@@ -600,7 +597,6 @@ impl TypeAliasPart {
600597
cx,
601598
};
602599
DocVisitor::visit_crate(&mut type_impl_collector, krate);
603-
let cx = type_impl_collector.cx;
604600
let aliased_types = type_impl_collector.aliased_types;
605601
for aliased_type in aliased_types.values() {
606602
let impls = aliased_type.impl_.values().filter_map(
@@ -612,7 +608,7 @@ impl TypeAliasPart {
612608
for &(type_alias_fqp, type_alias_item) in type_aliases {
613609
cx.id_map.borrow_mut().clear();
614610
cx.deref_id_map.borrow_mut().clear();
615-
let type_alias_fqp = (*type_alias_fqp).iter().join("::");
611+
let type_alias_fqp = type_alias_fqp.iter().join("::");
616612
if let Some(ret) = &mut ret {
617613
ret.aliases.push(type_alias_fqp);
618614
} else {
@@ -737,7 +733,7 @@ impl TraitAliasPart {
737733
},
738734
};
739735

740-
let implementors = imps
736+
let mut implementors = imps
741737
.iter()
742738
.filter_map(|imp| {
743739
// If the trait and implementation are in the same crate, then
@@ -759,12 +755,12 @@ impl TraitAliasPart {
759755
})
760756
}
761757
})
762-
.collect::<Vec<_>>();
758+
.peekable();
763759

764760
// Only create a js file if we have impls to add to it. If the trait is
765761
// documented locally though we always create the file to avoid dead
766762
// links.
767-
if implementors.is_empty() && !cache.paths.contains_key(&did) {
763+
if implementors.peek().is_none() && !cache.paths.contains_key(&did) {
768764
continue;
769765
}
770766

@@ -775,11 +771,7 @@ impl TraitAliasPart {
775771
path.push(format!("{remote_item_type}.{}.js", remote_path[remote_path.len() - 1]));
776772

777773
let part = OrderedJson::array_sorted(
778-
implementors
779-
.iter()
780-
.map(OrderedJson::serialize)
781-
.collect::<Result<Vec<_>, _>>()
782-
.unwrap(),
774+
implementors.map(|implementor| OrderedJson::serialize(implementor).unwrap()),
783775
);
784776
path_parts.push(path, OrderedJson::array_unsorted([crate_name_json, &part]));
785777
}
@@ -874,9 +866,8 @@ impl<'item> DocVisitor<'item> for TypeImplCollector<'_, '_, 'item> {
874866
let impl_ = cache
875867
.impls
876868
.get(&target_did)
877-
.map(|v| &v[..])
878-
.unwrap_or_default()
879-
.iter()
869+
.into_iter()
870+
.flatten()
880871
.map(|impl_| {
881872
(impl_.impl_item.item_id, AliasedTypeImpl { impl_, type_aliases: Vec::new() })
882873
})
@@ -891,14 +882,8 @@ impl<'item> DocVisitor<'item> for TypeImplCollector<'_, '_, 'item> {
891882
// Exclude impls that are directly on this type. They're already in the HTML.
892883
// Some inlining scenarios can cause there to be two versions of the same
893884
// impl: one on the type alias and one on the underlying target type.
894-
let mut seen_impls: FxHashSet<ItemId> = cache
895-
.impls
896-
.get(&self_did)
897-
.map(|s| &s[..])
898-
.unwrap_or_default()
899-
.iter()
900-
.map(|i| i.impl_item.item_id)
901-
.collect();
885+
let mut seen_impls: FxHashSet<ItemId> =
886+
cache.impls.get(&self_did).into_iter().flatten().map(|i| i.impl_item.item_id).collect();
902887
for (impl_item_id, aliased_type_impl) in &mut aliased_type.impl_ {
903888
// Only include this impl if it actually unifies with this alias.
904889
// Synthetic impls are not included; those are also included in the HTML.

0 commit comments

Comments
 (0)