Avoid Box in href_relative_parts.

This reverts part of #91948, going back to returning a
`UrlPartsBuilder`. It makes the code simpler, and also avoids some
allocations.
This commit is contained in:
Nicholas Nethercote 2025-05-23 05:21:42 +10:00
parent 283db70ace
commit 581fd271f6
3 changed files with 20 additions and 25 deletions

View file

@ -510,7 +510,7 @@ fn url_parts(
builder.extend(module_fqp.iter().copied());
Ok(builder)
}
ExternalLocation::Local => Ok(href_relative_parts(module_fqp, relative_to).collect()),
ExternalLocation::Local => Ok(href_relative_parts(module_fqp, relative_to)),
ExternalLocation::Unknown => Err(HrefError::DocumentationNotBuilt),
}
}
@ -587,7 +587,7 @@ pub(crate) fn href_with_root_path(
Some(&(ref fqp, shortty)) => (fqp, shortty, {
let module_fqp = to_module_fqp(shortty, fqp.as_slice());
debug!(?fqp, ?shortty, ?module_fqp);
href_relative_parts(module_fqp, relative_to).collect()
href_relative_parts(module_fqp, relative_to)
}),
None => {
// Associated items are handled differently with "jump to def". The anchor is generated
@ -619,34 +619,30 @@ pub(crate) fn href(
/// Both paths should only be modules.
/// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will
/// both need `../iter/trait.Iterator.html` to get at the iterator trait.
pub(crate) fn href_relative_parts<'fqp>(
fqp: &'fqp [Symbol],
relative_to_fqp: &[Symbol],
) -> Box<dyn Iterator<Item = Symbol> + 'fqp> {
pub(crate) fn href_relative_parts(fqp: &[Symbol], relative_to_fqp: &[Symbol]) -> UrlPartsBuilder {
for (i, (f, r)) in fqp.iter().zip(relative_to_fqp.iter()).enumerate() {
// e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1)
if f != r {
let dissimilar_part_count = relative_to_fqp.len() - i;
let fqp_module = &fqp[i..];
return Box::new(
iter::repeat_n(sym::dotdot, dissimilar_part_count)
.chain(fqp_module.iter().copied()),
);
return iter::repeat_n(sym::dotdot, dissimilar_part_count)
.chain(fqp_module.iter().copied())
.collect();
}
}
match relative_to_fqp.len().cmp(&fqp.len()) {
Ordering::Less => {
// e.g. linking to std::sync::atomic from std::sync
Box::new(fqp[relative_to_fqp.len()..fqp.len()].iter().copied())
fqp[relative_to_fqp.len()..fqp.len()].iter().copied().collect()
}
Ordering::Greater => {
// e.g. linking to std::sync from std::sync::atomic
let dissimilar_part_count = relative_to_fqp.len() - fqp.len();
Box::new(iter::repeat_n(sym::dotdot, dissimilar_part_count))
iter::repeat_n(sym::dotdot, dissimilar_part_count).collect()
}
Ordering::Equal => {
// linking to the same module
Box::new(iter::empty())
UrlPartsBuilder::new()
}
}
}

View file

@ -1,51 +1,51 @@
use rustc_span::{Symbol, sym};
use rustc_span::{Symbol, create_default_session_globals_then, sym};
use crate::html::format::href_relative_parts;
fn assert_relative_path(expected: &[Symbol], relative_to_fqp: &[Symbol], fqp: &[Symbol]) {
// No `create_default_session_globals_then` call is needed here because all
// the symbols used are static, and no `Symbol::intern` calls occur.
assert_eq!(expected, href_relative_parts(&fqp, &relative_to_fqp).collect::<Vec<_>>());
fn assert_relative_path(expected: &str, relative_to_fqp: &[Symbol], fqp: &[Symbol]) {
create_default_session_globals_then(|| {
assert_eq!(expected, href_relative_parts(&fqp, &relative_to_fqp).finish());
});
}
#[test]
fn href_relative_parts_basic() {
let relative_to_fqp = &[sym::std, sym::vec];
let fqp = &[sym::std, sym::iter];
assert_relative_path(&[sym::dotdot, sym::iter], relative_to_fqp, fqp);
assert_relative_path("../iter", relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_parent_module() {
let relative_to_fqp = &[sym::std, sym::vec];
let fqp = &[sym::std];
assert_relative_path(&[sym::dotdot], relative_to_fqp, fqp);
assert_relative_path("..", relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_different_crate() {
let relative_to_fqp = &[sym::std, sym::vec];
let fqp = &[sym::core, sym::iter];
assert_relative_path(&[sym::dotdot, sym::dotdot, sym::core, sym::iter], relative_to_fqp, fqp);
assert_relative_path("../../core/iter", relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_same_module() {
let relative_to_fqp = &[sym::std, sym::vec];
let fqp = &[sym::std, sym::vec];
assert_relative_path(&[], relative_to_fqp, fqp);
assert_relative_path("", relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_child_module() {
let relative_to_fqp = &[sym::std];
let fqp = &[sym::std, sym::vec];
assert_relative_path(&[sym::vec], relative_to_fqp, fqp);
assert_relative_path("vec", relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_root() {
let relative_to_fqp = &[];
let fqp = &[sym::std];
assert_relative_path(&[sym::std], relative_to_fqp, fqp);
assert_relative_path("std", relative_to_fqp, fqp);
}

View file

@ -14,7 +14,6 @@ pub(crate) struct UrlPartsBuilder {
impl UrlPartsBuilder {
/// Create an empty buffer.
#[allow(dead_code)]
pub(crate) fn new() -> Self {
Self { buf: String::new() }
}