rustdoc/
display.rs

1//! Various utilities for working with [`fmt::Display`] implementations.
2
3use std::fmt::{self, Display, Formatter, FormattingOptions};
4
5pub(crate) trait Joined: IntoIterator {
6    /// Takes an iterator over elements that implement [`Display`], and format them into `f`, separated by `sep`.
7    ///
8    /// This is similar to [`Itertools::format`](itertools::Itertools::format), but instead of returning an implementation of `Display`,
9    /// it formats directly into a [`Formatter`].
10    ///
11    /// The performance of `joined` is slightly better than `format`, since it doesn't need to use a `Cell` to keep track of whether [`fmt`](Display::fmt)
12    /// was already called (`joined`'s API doesn't allow it be called more than once).
13    fn joined(&mut self, sep: impl Display, f: &mut Formatter<'_>) -> fmt::Result;
14}
15
16impl<I, T> Joined for I
17where
18    I: Iterator<Item = T>,
19    T: Display,
20{
21    fn joined(&mut self, sep: impl Display, f: &mut Formatter<'_>) -> fmt::Result {
22        let Some(first) = self.next() else { return Ok(()) };
23        first.fmt(f)?;
24        for item in self {
25            sep.fmt(f)?;
26            item.fmt(f)?;
27        }
28        Ok(())
29    }
30}
31
32pub(crate) trait MaybeDisplay {
33    /// For a given `Option<T: Display>`, returns a `Display` implementation that will display `t` if `Some(t)`, or nothing if `None`.
34    fn maybe_display(self) -> impl Display;
35}
36
37impl<T: Display> MaybeDisplay for Option<T> {
38    fn maybe_display(self) -> impl Display {
39        fmt::from_fn(move |f| {
40            if let Some(t) = self.as_ref() {
41                t.fmt(f)?;
42            }
43            Ok(())
44        })
45    }
46}
47
48#[derive(Clone, Copy)]
49pub(crate) struct Wrapped<T> {
50    prefix: T,
51    suffix: T,
52}
53
54pub(crate) enum AngleBracket {
55    Open,
56    Close,
57}
58
59impl Display for AngleBracket {
60    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
61        f.write_str(match (self, f.alternate()) {
62            (Self::Open, true) => "<",
63            (Self::Open, false) => "&lt;",
64            (Self::Close, true) => ">",
65            (Self::Close, false) => "&gt;",
66        })
67    }
68}
69
70impl Wrapped<AngleBracket> {
71    pub(crate) fn with_angle_brackets() -> Self {
72        Self { prefix: AngleBracket::Open, suffix: AngleBracket::Close }
73    }
74}
75
76impl Wrapped<char> {
77    pub(crate) fn with_parens() -> Self {
78        Self { prefix: '(', suffix: ')' }
79    }
80
81    pub(crate) fn with_square_brackets() -> Self {
82        Self { prefix: '[', suffix: ']' }
83    }
84}
85
86impl<T: Display> Wrapped<T> {
87    pub(crate) fn with(prefix: T, suffix: T) -> Self {
88        Self { prefix, suffix }
89    }
90
91    pub(crate) fn when(self, if_: bool) -> Wrapped<impl Display> {
92        Wrapped {
93            prefix: if_.then_some(self.prefix).maybe_display(),
94            suffix: if_.then_some(self.suffix).maybe_display(),
95        }
96    }
97
98    pub(crate) fn wrap_fn(
99        self,
100        content: impl Fn(&mut Formatter<'_>) -> fmt::Result,
101    ) -> impl Display {
102        fmt::from_fn(move |f| {
103            self.prefix.fmt(f)?;
104            content(f)?;
105            self.suffix.fmt(f)
106        })
107    }
108
109    pub(crate) fn wrap<C: Display>(self, content: C) -> impl Display {
110        self.wrap_fn(move |f| content.fmt(f))
111    }
112}
113
114#[derive(Clone, Copy)]
115pub(crate) struct WithOpts {
116    opts: FormattingOptions,
117}
118
119impl WithOpts {
120    pub(crate) fn from(f: &Formatter<'_>) -> Self {
121        Self { opts: f.options() }
122    }
123
124    pub(crate) fn display(self, t: impl Display) -> impl Display {
125        fmt::from_fn(move |f| {
126            let mut f = f.with_options(self.opts);
127            t.fmt(&mut f)
128        })
129    }
130}