Skip to content

Commit a688929

Browse files
committed
Auto merge of #136748 - yotamofek:pr/rustdoc-remove-buffer, r=<try>
Nuke `Buffer` abstraction from `librustdoc` 💣 In #136656 I found out that the `for_html` field in the `Buffer` struct was never read, and pondered if `Buffer` had any utility at all. `@GuillaumeGomez` said he agrees that it can be just removed. So this PR is me removing it. So, r? `@GuillaumeGomez` But... this got *a lot* bigger than I had planned. A lot of functions had a `&mut Buffer` arg, but instead of replacing it with a `buf: impl fmt::Write` arg, I decided to change those functions to return an opaque `impl fmt::Display` instead. If this PR turns out to be contentious I can try to make a PR that just removes the `Buffer` struct and tries to make less invasive changes, but personally I do like some of the cleanups that this PR allows. Let's see what others think! I think it'll be better to review this without whitespace (If this gets positive reactions, I'll need to rebase and maybe try to separate this into logical commits, but not sure if that's very practical) While most of the PR is "cosmetic", I did make some small changes, mostly trying to make some of the formatting lazier, and do less allocations. So a perf run will be nice :) ### Pros and cons of returning `impl fmt::Display` instead of taking a `impl fmt::Write` #### Cons: - Named lifetimes: function signatures got a lot more verbose because the RPIT opaque type needs to be explicitly bound by the lifetimes of the refs in the arguments - Having to use `fmt::from_fn` causes another level of indentation - Immutable closures, can't move out of non-`Copy` items (wasn't much of a problem in practice) #### Pros: - Less arguments, no un-Rusty "out" argument - Nicer composability, allows the returned type to be directly used in format strings ### Interchangeability A function receiving a `impl fmt::Write` can be turned into a function returning a `impl fmt::Display` by using `fmt::from_fn`.
2 parents 43ca9d1 + be7a1ce commit a688929

File tree

12 files changed

+2875
-2806
lines changed

12 files changed

+2875
-2806
lines changed

src/librustdoc/html/format.rs

+54-164
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
//! some of them support an alternate format that emits text, but that should
88
//! not be used external to this module.
99
10-
use std::borrow::Cow;
1110
use std::cmp::Ordering;
1211
use std::fmt::{self, Display, Write};
1312
use std::iter::{self, once};
@@ -37,115 +36,6 @@ use crate::html::render::Context;
3736
use crate::joined::Joined as _;
3837
use crate::passes::collect_intra_doc_links::UrlFragment;
3938

40-
pub(crate) trait Print {
41-
fn print(self, buffer: &mut Buffer);
42-
}
43-
44-
impl<F> Print for F
45-
where
46-
F: FnOnce(&mut Buffer),
47-
{
48-
fn print(self, buffer: &mut Buffer) {
49-
(self)(buffer)
50-
}
51-
}
52-
53-
impl Print for String {
54-
fn print(self, buffer: &mut Buffer) {
55-
buffer.write_str(&self);
56-
}
57-
}
58-
59-
impl Print for &'_ str {
60-
fn print(self, buffer: &mut Buffer) {
61-
buffer.write_str(self);
62-
}
63-
}
64-
65-
#[derive(Debug, Clone)]
66-
pub(crate) struct Buffer {
67-
for_html: bool,
68-
buffer: String,
69-
}
70-
71-
impl core::fmt::Write for Buffer {
72-
#[inline]
73-
fn write_str(&mut self, s: &str) -> fmt::Result {
74-
self.buffer.write_str(s)
75-
}
76-
77-
#[inline]
78-
fn write_char(&mut self, c: char) -> fmt::Result {
79-
self.buffer.write_char(c)
80-
}
81-
82-
#[inline]
83-
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
84-
self.buffer.write_fmt(args)
85-
}
86-
}
87-
88-
impl Buffer {
89-
pub(crate) fn empty_from(v: &Buffer) -> Buffer {
90-
Buffer { for_html: v.for_html, buffer: String::new() }
91-
}
92-
93-
pub(crate) fn html() -> Buffer {
94-
Buffer { for_html: true, buffer: String::new() }
95-
}
96-
97-
pub(crate) fn new() -> Buffer {
98-
Buffer { for_html: false, buffer: String::new() }
99-
}
100-
101-
pub(crate) fn is_empty(&self) -> bool {
102-
self.buffer.is_empty()
103-
}
104-
105-
pub(crate) fn into_inner(self) -> String {
106-
self.buffer
107-
}
108-
109-
pub(crate) fn push(&mut self, c: char) {
110-
self.buffer.push(c);
111-
}
112-
113-
pub(crate) fn push_str(&mut self, s: &str) {
114-
self.buffer.push_str(s);
115-
}
116-
117-
pub(crate) fn push_buffer(&mut self, other: Buffer) {
118-
self.buffer.push_str(&other.buffer);
119-
}
120-
121-
// Intended for consumption by write! and writeln! (std::fmt) but without
122-
// the fmt::Result return type imposed by fmt::Write (and avoiding the trait
123-
// import).
124-
pub(crate) fn write_str(&mut self, s: &str) {
125-
self.buffer.push_str(s);
126-
}
127-
128-
// Intended for consumption by write! and writeln! (std::fmt) but without
129-
// the fmt::Result return type imposed by fmt::Write (and avoiding the trait
130-
// import).
131-
pub(crate) fn write_fmt(&mut self, v: fmt::Arguments<'_>) {
132-
self.buffer.write_fmt(v).unwrap();
133-
}
134-
135-
pub(crate) fn to_display<T: Print>(mut self, t: T) -> String {
136-
t.print(&mut self);
137-
self.into_inner()
138-
}
139-
140-
pub(crate) fn reserve(&mut self, additional: usize) {
141-
self.buffer.reserve(additional)
142-
}
143-
144-
pub(crate) fn len(&self) -> usize {
145-
self.buffer.len()
146-
}
147-
}
148-
14939
pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
15040
bounds: &'a [clean::GenericBound],
15141
cx: &'a Context<'tcx>,
@@ -772,27 +662,29 @@ pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Cont
772662
else {
773663
return String::new();
774664
};
775-
let mut buf = Buffer::new();
776665
let fqp = if *shortty == ItemType::Primitive {
777666
// primitives are documented in a crate, but not actually part of it
778667
&fqp[fqp.len() - 1..]
779668
} else {
780669
fqp
781670
};
782-
if let &Some(UrlFragment::Item(id)) = fragment {
783-
write!(buf, "{} ", cx.tcx().def_descr(id));
784-
for component in fqp {
785-
write!(buf, "{component}::");
786-
}
787-
write!(buf, "{}", cx.tcx().item_name(id));
788-
} else if !fqp.is_empty() {
789-
let mut fqp_it = fqp.iter();
790-
write!(buf, "{shortty} {}", fqp_it.next().unwrap());
791-
for component in fqp_it {
792-
write!(buf, "::{component}");
671+
fmt::from_fn(|f| {
672+
if let &Some(UrlFragment::Item(id)) = fragment {
673+
write!(f, "{} ", cx.tcx().def_descr(id))?;
674+
for component in fqp {
675+
write!(f, "{component}::")?;
676+
}
677+
write!(f, "{}", cx.tcx().item_name(id))?;
678+
} else if !fqp.is_empty() {
679+
let mut fqp_it = fqp.iter();
680+
write!(f, "{shortty} {}", fqp_it.next().unwrap())?;
681+
for component in fqp_it {
682+
write!(f, "::{component}")?;
683+
}
793684
}
794-
}
795-
buf.into_inner()
685+
Ok(())
686+
})
687+
.to_string()
796688
}
797689

798690
/// Used to render a [`clean::Path`].
@@ -954,7 +846,7 @@ pub(crate) fn anchor<'a: 'cx, 'cx>(
954846
text = EscapeBodyText(text.as_str()),
955847
)
956848
} else {
957-
f.write_str(text.as_str())
849+
write!(f, "{text}")
958850
}
959851
})
960852
}
@@ -1533,53 +1425,51 @@ impl clean::FnDecl {
15331425
}
15341426

15351427
pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
1536-
item: &clean::Item,
1428+
item: &'a clean::Item,
15371429
cx: &'a Context<'tcx>,
15381430
) -> impl Display + 'a + Captures<'tcx> {
1539-
use std::fmt::Write as _;
1540-
let vis: Cow<'static, str> = match item.visibility(cx.tcx()) {
1541-
None => "".into(),
1542-
Some(ty::Visibility::Public) => "pub ".into(),
1543-
Some(ty::Visibility::Restricted(vis_did)) => {
1544-
// FIXME(camelid): This may not work correctly if `item_did` is a module.
1545-
// However, rustdoc currently never displays a module's
1546-
// visibility, so it shouldn't matter.
1547-
let parent_module = find_nearest_parent_module(cx.tcx(), item.item_id.expect_def_id());
1548-
1549-
if vis_did.is_crate_root() {
1550-
"pub(crate) ".into()
1551-
} else if parent_module == Some(vis_did) {
1552-
// `pub(in foo)` where `foo` is the parent module
1553-
// is the same as no visibility modifier
1554-
"".into()
1555-
} else if parent_module.and_then(|parent| find_nearest_parent_module(cx.tcx(), parent))
1556-
== Some(vis_did)
1557-
{
1558-
"pub(super) ".into()
1559-
} else {
1560-
let path = cx.tcx().def_path(vis_did);
1561-
debug!("path={path:?}");
1562-
// modified from `resolved_path()` to work with `DefPathData`
1563-
let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
1564-
let anchor = anchor(vis_did, last_name, cx);
1565-
1566-
let mut s = "pub(in ".to_owned();
1567-
for seg in &path.data[..path.data.len() - 1] {
1568-
let _ = write!(s, "{}::", seg.data.get_opt_name().unwrap());
1569-
}
1570-
let _ = write!(s, "{anchor}) ");
1571-
s.into()
1572-
}
1573-
}
1574-
};
1575-
15761431
let is_doc_hidden = item.is_doc_hidden();
15771432
fmt::from_fn(move |f| {
15781433
if is_doc_hidden {
15791434
f.write_str("#[doc(hidden)] ")?;
15801435
}
15811436

1582-
f.write_str(&vis)
1437+
match item.visibility(cx.tcx()) {
1438+
None => Ok(()),
1439+
Some(ty::Visibility::Public) => f.write_str("pub "),
1440+
Some(ty::Visibility::Restricted(vis_did)) => {
1441+
// FIXME(camelid): This may not work correctly if `item_did` is a module.
1442+
// However, rustdoc currently never displays a module's
1443+
// visibility, so it shouldn't matter.
1444+
let parent_module =
1445+
find_nearest_parent_module(cx.tcx(), item.item_id.expect_def_id());
1446+
1447+
if vis_did.is_crate_root() {
1448+
f.write_str("pub(crate) ")
1449+
} else if parent_module == Some(vis_did) {
1450+
// `pub(in foo)` where `foo` is the parent module
1451+
// is the same as no visibility modifier
1452+
Ok(())
1453+
} else if parent_module
1454+
.and_then(|parent| find_nearest_parent_module(cx.tcx(), parent))
1455+
== Some(vis_did)
1456+
{
1457+
f.write_str("pub(super) ")
1458+
} else {
1459+
let path = cx.tcx().def_path(vis_did);
1460+
debug!("path={path:?}");
1461+
// modified from `resolved_path()` to work with `DefPathData`
1462+
let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
1463+
let anchor = anchor(vis_did, last_name, cx);
1464+
1465+
f.write_str("pub(in ")?;
1466+
for seg in &path.data[..path.data.len() - 1] {
1467+
write!(f, "{}::", seg.data.get_opt_name().unwrap())?;
1468+
}
1469+
write!(f, "{anchor}) ")
1470+
}
1471+
}
1472+
}
15831473
})
15841474
}
15851475

0 commit comments

Comments
 (0)