Skip to content

Commit edfd555

Browse files
Transition a few fmt::Display impls to functions
This introduces a WithFormatter abstraction that permits one-time fmt::Display on an arbitrary closure, created via `display_fn`. This allows us to prevent allocation while still using functions instead of structs, which are a bit unwieldy to thread arguments through as they can't easily call each other (and are generally a bit opaque). The eventual goal here is likely to move us off of the formatting infrastructure entirely in favor of something more structured, but this is a good step to move us in that direction as it makes, for example, passing a context describing current state to the formatting impl much easier.
1 parent dafdfee commit edfd555

File tree

2 files changed

+56
-52
lines changed

2 files changed

+56
-52
lines changed

src/librustdoc/html/format.rs

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//! them in the future to instead emit any format desired.
77
88
use std::borrow::Cow;
9+
use std::cell::Cell;
910
use std::fmt;
1011

1112
use rustc::hir::def_id::DefId;
@@ -38,8 +39,6 @@ pub struct AsyncSpace(pub hir::IsAsync);
3839
pub struct MutableSpace(pub clean::Mutability);
3940
/// Wrapper struct for emitting type parameter bounds.
4041
pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]);
41-
/// Wrapper struct for emitting a comma-separated list of items
42-
pub struct CommaSep<'a, T>(pub &'a [T]);
4342
pub struct AbiSpace(pub Abi);
4443
pub struct DefaultSpace(pub bool);
4544

@@ -68,11 +67,6 @@ pub struct WhereClause<'a>{
6867
pub end_newline: bool,
6968
}
7069

71-
pub struct HRef<'a> {
72-
did: DefId,
73-
text: &'a str,
74-
}
75-
7670
impl<'a> VisSpace<'a> {
7771
pub fn get(self) -> &'a Option<clean::Visibility> {
7872
let VisSpace(v) = self; v
@@ -91,14 +85,14 @@ impl ConstnessSpace {
9185
}
9286
}
9387

94-
impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> {
95-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96-
for (i, item) in self.0.iter().enumerate() {
88+
fn comma_sep<T: fmt::Display>(items: &[T]) -> impl fmt::Display + '_ {
89+
display_fn(move |f| {
90+
for (i, item) in items.iter().enumerate() {
9791
if i != 0 { write!(f, ", ")?; }
9892
fmt::Display::fmt(item, f)?;
9993
}
10094
Ok(())
101-
}
95+
})
10296
}
10397

10498
impl<'a> fmt::Display for GenericBounds<'a> {
@@ -165,9 +159,9 @@ impl fmt::Display for clean::Generics {
165159
return Ok(());
166160
}
167161
if f.alternate() {
168-
write!(f, "<{:#}>", CommaSep(&real_params))
162+
write!(f, "<{:#}>", comma_sep(&real_params))
169163
} else {
170-
write!(f, "&lt;{}&gt;", CommaSep(&real_params))
164+
write!(f, "&lt;{}&gt;", comma_sep(&real_params))
171165
}
172166
}
173167
}
@@ -265,9 +259,9 @@ impl fmt::Display for clean::PolyTrait {
265259
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266260
if !self.generic_params.is_empty() {
267261
if f.alternate() {
268-
write!(f, "for<{:#}> ", CommaSep(&self.generic_params))?;
262+
write!(f, "for<{:#}> ", comma_sep(&self.generic_params))?;
269263
} else {
270-
write!(f, "for&lt;{}&gt; ", CommaSep(&self.generic_params))?;
264+
write!(f, "for&lt;{}&gt; ", comma_sep(&self.generic_params))?;
271265
}
272266
}
273267
if f.alternate() {
@@ -452,16 +446,15 @@ fn resolved_path(w: &mut fmt::Formatter<'_>, did: DefId, path: &clean::Path,
452446
write!(w, "{}{:#}", &last.name, last.args)?;
453447
} else {
454448
let path = if use_absolute {
455-
match href(did) {
456-
Some((_, _, fqp)) => {
457-
format!("{}::{}",
458-
fqp[..fqp.len() - 1].join("::"),
459-
HRef::new(did, fqp.last().unwrap()))
460-
}
461-
None => HRef::new(did, &last.name).to_string(),
449+
if let Some((_, _, fqp)) = href(did) {
450+
format!("{}::{}",
451+
fqp[..fqp.len() - 1].join("::"),
452+
anchor(did, fqp.last().unwrap()))
453+
} else {
454+
last.name.to_string()
462455
}
463456
} else {
464-
HRef::new(did, &last.name).to_string()
457+
anchor(did, &last.name).to_string()
465458
};
466459
write!(w, "{}{}", path, last.args)?;
467460
}
@@ -513,35 +506,30 @@ fn primitive_link(f: &mut fmt::Formatter<'_>,
513506
}
514507

515508
/// Helper to render type parameters
516-
fn tybounds(w: &mut fmt::Formatter<'_>,
517-
param_names: &Option<Vec<clean::GenericBound>>) -> fmt::Result {
518-
match *param_names {
519-
Some(ref params) => {
520-
for param in params {
521-
write!(w, " + ")?;
522-
fmt::Display::fmt(param, w)?;
509+
fn tybounds(param_names: &Option<Vec<clean::GenericBound>>) -> impl fmt::Display + '_ {
510+
display_fn(move |f| {
511+
match *param_names {
512+
Some(ref params) => {
513+
for param in params {
514+
write!(f, " + ")?;
515+
fmt::Display::fmt(param, f)?;
516+
}
517+
Ok(())
523518
}
524-
Ok(())
519+
None => Ok(())
525520
}
526-
None => Ok(())
527-
}
528-
}
529-
530-
impl<'a> HRef<'a> {
531-
pub fn new(did: DefId, text: &'a str) -> HRef<'a> {
532-
HRef { did: did, text: text }
533-
}
521+
})
534522
}
535523

536-
impl<'a> fmt::Display for HRef<'a> {
537-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
538-
if let Some((url, short_ty, fqp)) = href(self.did) {
524+
pub fn anchor(did: DefId, text: &str) -> impl fmt::Display + '_ {
525+
display_fn(move |f| {
526+
if let Some((url, short_ty, fqp)) = href(did) {
539527
write!(f, r#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
540-
short_ty, url, short_ty, fqp.join("::"), self.text)
528+
short_ty, url, short_ty, fqp.join("::"), text)
541529
} else {
542-
write!(f, "{}", self.text)
530+
write!(f, "{}", text)
543531
}
544-
}
532+
})
545533
}
546534

547535
fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> fmt::Result {
@@ -555,7 +543,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
555543
}
556544
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
557545
resolved_path(f, did, path, is_generic, use_absolute)?;
558-
tybounds(f, param_names)
546+
fmt::Display::fmt(&tybounds(param_names), f)
559547
}
560548
clean::Infer => write!(f, "_"),
561549
clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
@@ -564,12 +552,12 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
564552
write!(f, "{}{:#}fn{:#}{:#}",
565553
UnsafetySpace(decl.unsafety),
566554
AbiSpace(decl.abi),
567-
CommaSep(&decl.generic_params),
555+
comma_sep(&decl.generic_params),
568556
decl.decl)
569557
} else {
570558
write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?;
571559
primitive_link(f, PrimitiveType::Fn, "fn")?;
572-
write!(f, "{}{}", CommaSep(&decl.generic_params), decl.decl)
560+
write!(f, "{}{}", comma_sep(&decl.generic_params), decl.decl)
573561
}
574562
}
575563
clean::Tuple(ref typs) => {
@@ -583,7 +571,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
583571
}
584572
many => {
585573
primitive_link(f, PrimitiveType::Tuple, "(")?;
586-
fmt::Display::fmt(&CommaSep(many), f)?;
574+
fmt::Display::fmt(&comma_sep(many), f)?;
587575
primitive_link(f, PrimitiveType::Tuple, ")")
588576
}
589577
}
@@ -1063,3 +1051,19 @@ impl fmt::Display for DefaultSpace {
10631051
}
10641052
}
10651053
}
1054+
1055+
crate fn display_fn(
1056+
f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
1057+
) -> impl fmt::Display {
1058+
WithFormatter(Cell::new(Some(f)))
1059+
}
1060+
1061+
struct WithFormatter<F>(Cell<Option<F>>);
1062+
1063+
impl<F> fmt::Display for WithFormatter<F>
1064+
where F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
1065+
{
1066+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1067+
(self.0.take()).unwrap()(f)
1068+
}
1069+
}

src/librustdoc/html/render.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2644,19 +2644,19 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context,
26442644

26452645
match myitem.inner {
26462646
clean::ExternCrateItem(ref name, ref src) => {
2647-
use crate::html::format::HRef;
2647+
use crate::html::format::anchor;
26482648

26492649
match *src {
26502650
Some(ref src) => {
26512651
write!(w, "<tr><td><code>{}extern crate {} as {};",
26522652
VisSpace(&myitem.visibility),
2653-
HRef::new(myitem.def_id, src),
2653+
anchor(myitem.def_id, src),
26542654
name)?
26552655
}
26562656
None => {
26572657
write!(w, "<tr><td><code>{}extern crate {};",
26582658
VisSpace(&myitem.visibility),
2659-
HRef::new(myitem.def_id, name))?
2659+
anchor(myitem.def_id, name))?
26602660
}
26612661
}
26622662
write!(w, "</code></td></tr>")?;

0 commit comments

Comments
 (0)