Skip to content

Commit d3310c7

Browse files
committed
Introduce "wrapper" helpers to rustdoc
1 parent e8417e5 commit d3310c7

File tree

4 files changed

+247
-236
lines changed

4 files changed

+247
-236
lines changed

src/librustdoc/clean/cfg.rs

Lines changed: 28 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
// FIXME: Once the portability lint RFC is implemented (see tracking issue #41619),
44
// switch to use those structures instead.
55

6-
use std::fmt::{self, Write};
7-
use std::{mem, ops};
6+
use std::{fmt, mem, ops};
87

8+
use itertools::Either;
99
use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
1010
use rustc_data_structures::fx::FxHashSet;
1111
use rustc_session::parse::ParseSess;
1212
use rustc_span::Span;
1313
use rustc_span::symbol::{Symbol, sym};
1414

15-
use crate::display::Joined as _;
15+
use crate::display::{Joined as _, MaybeDisplay, Parentheses, Wrappers as _};
1616
use crate::html::escape::Escape;
1717

1818
#[cfg(test)]
@@ -376,27 +376,20 @@ impl Format {
376376
Format::LongPlain => false,
377377
}
378378
}
379+
380+
fn escape(self, s: &str) -> impl fmt::Display {
381+
if self.is_html() { Either::Left(Escape(s)) } else { Either::Right(s) }
382+
}
379383
}
380384

381385
/// Pretty-print wrapper for a `Cfg`. Also indicates what form of rendering should be used.
382386
struct Display<'a>(&'a Cfg, Format);
383387

384-
fn write_with_opt_paren<T: fmt::Display>(
385-
fmt: &mut fmt::Formatter<'_>,
386-
has_paren: bool,
387-
obj: T,
388-
) -> fmt::Result {
389-
if has_paren {
390-
fmt.write_char('(')?;
391-
}
392-
obj.fmt(fmt)?;
393-
if has_paren {
394-
fmt.write_char(')')?;
388+
impl Display<'_> {
389+
fn code_wrappers(&self) -> (&'static str, &'static str) {
390+
if self.1.is_html() { ("<code>", "</code>") } else { ("`", "`") }
395391
}
396-
Ok(())
397-
}
398392

399-
impl Display<'_> {
400393
fn display_sub_cfgs(
401394
&self,
402395
fmt: &mut fmt::Formatter<'_>,
@@ -427,20 +420,17 @@ impl Display<'_> {
427420
sub_cfgs
428421
.iter()
429422
.map(|sub_cfg| {
430-
fmt::from_fn(move |fmt| {
431-
if let Cfg::Cfg(_, Some(feat)) = sub_cfg
432-
&& short_longhand
433-
{
434-
if self.1.is_html() {
435-
write!(fmt, "<code>{feat}</code>")?;
436-
} else {
437-
write!(fmt, "`{feat}`")?;
438-
}
439-
} else {
440-
write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
441-
}
442-
Ok(())
443-
})
423+
if let Cfg::Cfg(_, Some(feat)) = sub_cfg
424+
&& short_longhand
425+
{
426+
Either::Left(self.code_wrappers().wrap(feat))
427+
} else {
428+
Either::Right(
429+
(!sub_cfg.is_all())
430+
.then_some(Parentheses)
431+
.wrap(Display(sub_cfg, self.1)),
432+
)
433+
}
444434
})
445435
.joined(separator, f)
446436
})
@@ -461,9 +451,7 @@ impl fmt::Display for Display<'_> {
461451
sub_cfgs
462452
.iter()
463453
.map(|sub_cfg| {
464-
fmt::from_fn(|fmt| {
465-
write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))
466-
})
454+
(!sub_cfg.is_all()).then_some(Parentheses).wrap(Display(sub_cfg, self.1))
467455
})
468456
.joined(separator, fmt)
469457
}
@@ -568,21 +556,13 @@ impl fmt::Display for Display<'_> {
568556
};
569557
if !human_readable.is_empty() {
570558
fmt.write_str(human_readable)
571-
} else if let Some(v) = value {
572-
if self.1.is_html() {
573-
write!(
574-
fmt,
575-
r#"<code>{}="{}"</code>"#,
576-
Escape(name.as_str()),
577-
Escape(v.as_str())
578-
)
579-
} else {
580-
write!(fmt, r#"`{name}="{v}"`"#)
581-
}
582-
} else if self.1.is_html() {
583-
write!(fmt, "<code>{}</code>", Escape(name.as_str()))
584559
} else {
585-
write!(fmt, "`{name}`")
560+
let value = value
561+
.map(|v| fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str()))))
562+
.maybe_display();
563+
self.code_wrappers()
564+
.wrap(format_args!("{}{value}", self.1.escape(name.as_str())))
565+
.fmt(fmt)
586566
}
587567
}
588568
}

src/librustdoc/display.rs

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Various utilities for working with [`fmt::Display`] implementations.
22
3-
use std::fmt::{self, Display, Formatter};
3+
use std::fmt::{self, Display, Formatter, Write as _};
44

55
pub(crate) trait Joined: IntoIterator {
66
/// Takes an iterator over elements that implement [`Display`], and format them into `f`, separated by `sep`.
@@ -45,3 +45,93 @@ impl<T: Display> MaybeDisplay for Option<T> {
4545
})
4646
}
4747
}
48+
49+
pub(crate) trait Wrappers: Sized {
50+
fn prefix(&self) -> impl Display;
51+
fn suffix(&self) -> impl Display;
52+
53+
fn wrap<T: Display>(self, wrapped: T) -> impl Display {
54+
fmt::from_fn(move |f| {
55+
self.prefix().fmt(f)?;
56+
wrapped.fmt(f)?;
57+
self.suffix().fmt(f)?;
58+
Ok(())
59+
})
60+
}
61+
62+
fn wrap_fn(self, fmt: impl Fn(&mut Formatter<'_>) -> fmt::Result) -> impl Display {
63+
self.wrap(fmt::from_fn(fmt))
64+
}
65+
}
66+
67+
impl<W: Wrappers> Wrappers for Option<W> {
68+
fn prefix(&self) -> impl Display {
69+
self.as_ref().map(W::prefix).maybe_display()
70+
}
71+
72+
fn suffix(&self) -> impl Display {
73+
self.as_ref().map(W::suffix).maybe_display()
74+
}
75+
}
76+
77+
pub(crate) trait Wrapped: Display + Sized {
78+
fn wrapped(self, wrappers: impl Wrappers) -> impl Display {
79+
wrappers.wrap(self)
80+
}
81+
}
82+
83+
impl<T> Wrapped for T where T: Display + Sized {}
84+
85+
impl<Prefix: Display, Suffix: Display> Wrappers for (Prefix, Suffix) {
86+
fn prefix(&self) -> impl Display {
87+
&self.0
88+
}
89+
90+
fn suffix(&self) -> impl Display {
91+
&self.1
92+
}
93+
}
94+
95+
macro_rules! impl_wrappers {
96+
($vis:vis struct $name:ident($prefix:literal, $suffix:literal)) => {
97+
#[derive(Clone, Copy)]
98+
$vis struct $name;
99+
100+
impl Wrappers for $name {
101+
fn prefix(&self) -> impl Display {
102+
$prefix
103+
}
104+
105+
fn suffix(&self) -> impl Display {
106+
$suffix
107+
}
108+
}
109+
}
110+
}
111+
112+
impl_wrappers!(pub(crate) struct Parentheses('(', ')'));
113+
impl_wrappers!(pub(crate) struct SquareBrackets('[', ']'));
114+
115+
pub(crate) struct AngleBrackets;
116+
117+
impl Wrappers for AngleBrackets {
118+
fn prefix(&self) -> impl Display {
119+
fmt::from_fn(|f| if f.alternate() { f.write_char('<') } else { f.write_str("&lt;") })
120+
}
121+
122+
fn suffix(&self) -> impl Display {
123+
fmt::from_fn(|f| if f.alternate() { f.write_char('>') } else { f.write_str("&gt;") })
124+
}
125+
}
126+
127+
pub(crate) trait InheritOpts: Display + Sized {
128+
fn inherit_opts(self, f: &Formatter<'_>) -> impl Display + use<Self> {
129+
let options = f.options();
130+
fmt::from_fn(move |f| {
131+
let mut f = f.with_options(options);
132+
self.fmt(&mut f)
133+
})
134+
}
135+
}
136+
137+
impl<T: Display + Sized> InheritOpts for T {}

0 commit comments

Comments
 (0)