1 //! HTML formatting module
3 //! This module contains a large number of `fmt::Display` implementations for
4 //! various types in `rustdoc::clean`. These implementations all currently
5 //! assume that HTML output is desired, although it may be possible to redesign
6 //! them in the future to instead emit any format desired.
12 use rustc_data_structures
::fx
::FxHashSet
;
14 use rustc_middle
::ty
::TyCtxt
;
15 use rustc_span
::def_id
::{DefId, CRATE_DEF_INDEX}
;
16 use rustc_target
::spec
::abi
::Abi
;
18 use crate::clean
::{self, utils::find_nearest_parent_module, PrimitiveType}
;
19 use crate::formats
::cache
::Cache
;
20 use crate::formats
::item_type
::ItemType
;
21 use crate::html
::escape
::Escape
;
22 use crate::html
::render
::cache
::ExternalLocation
;
23 use crate::html
::render
::CURRENT_DEPTH
;
26 fn print(self, buffer
: &mut Buffer
);
31 F
: FnOnce(&mut Buffer
),
33 fn print(self, buffer
: &mut Buffer
) {
38 impl Print
for String
{
39 fn print(self, buffer
: &mut Buffer
) {
40 buffer
.write_str(&self);
44 impl Print
for &'_
str {
45 fn print(self, buffer
: &mut Buffer
) {
46 buffer
.write_str(self);
50 #[derive(Debug, Clone)]
57 crate fn empty_from(v
: &Buffer
) -> Buffer
{
58 Buffer { for_html: v.for_html, buffer: String::new() }
61 crate fn html() -> Buffer
{
62 Buffer { for_html: true, buffer: String::new() }
65 crate fn new() -> Buffer
{
66 Buffer { for_html: false, buffer: String::new() }
69 crate fn is_empty(&self) -> bool
{
70 self.buffer
.is_empty()
73 crate fn into_inner(self) -> String
{
77 crate fn insert_str(&mut self, idx
: usize, s
: &str) {
78 self.buffer
.insert_str(idx
, s
);
81 crate fn push_str(&mut self, s
: &str) {
82 self.buffer
.push_str(s
);
85 // Intended for consumption by write! and writeln! (std::fmt) but without
86 // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
88 crate fn write_str(&mut self, s
: &str) {
89 self.buffer
.push_str(s
);
92 // Intended for consumption by write! and writeln! (std::fmt) but without
93 // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
95 crate fn write_fmt(&mut self, v
: fmt
::Arguments
<'_
>) {
97 self.buffer
.write_fmt(v
).unwrap();
100 crate fn to_display
<T
: Print
>(mut self, t
: T
) -> String
{
105 crate fn is_for_html(&self) -> bool
{
110 /// Wrapper struct for properly emitting a function or method declaration.
111 crate struct Function
<'a
> {
112 /// The declaration to emit.
113 crate decl
: &'a clean
::FnDecl
,
114 /// The length of the function header and name. In other words, the number of characters in the
115 /// function declaration up to but not including the parentheses.
117 /// Used to determine line-wrapping.
118 crate header_len
: usize,
119 /// The number of spaces to indent each successive line with, if line-wrapping is necessary.
121 /// Whether the function is async or not.
122 crate asyncness
: hir
::IsAsync
,
125 /// Wrapper struct for emitting a where-clause from Generics.
126 crate struct WhereClause
<'a
> {
127 /// The Generics from which to emit a where-clause.
128 crate gens
: &'a clean
::Generics
,
129 /// The number of spaces to indent each line with.
131 /// Whether the where-clause needs to add a comma and newline after the last bound.
132 crate end_newline
: bool
,
135 fn comma_sep
<T
: fmt
::Display
>(items
: impl Iterator
<Item
= T
>) -> impl fmt
::Display
{
136 display_fn(move |f
| {
137 for (i
, item
) in items
.enumerate() {
141 fmt
::Display
::fmt(&item
, f
)?
;
147 crate fn print_generic_bounds
<'a
>(
148 bounds
: &'a
[clean
::GenericBound
],
150 ) -> impl fmt
::Display
+ 'a
{
151 display_fn(move |f
| {
152 let mut bounds_dup
= FxHashSet
::default();
155 bounds
.iter().filter(|b
| bounds_dup
.insert(b
.print(cache
).to_string())).enumerate()
160 fmt
::Display
::fmt(&bound
.print(cache
), f
)?
;
166 impl clean
::GenericParamDef
{
167 crate fn print
<'a
>(&'a
self, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
168 display_fn(move |f
| match self.kind
{
169 clean
::GenericParamDefKind
::Lifetime
=> write
!(f
, "{}", self.name
),
170 clean
::GenericParamDefKind
::Type { ref bounds, ref default, .. }
=> {
171 f
.write_str(&*self.name
.as_str())?
;
173 if !bounds
.is_empty() {
175 write
!(f
, ": {:#}", print_generic_bounds(bounds
, cache
))?
;
177 write
!(f
, ": {}", print_generic_bounds(bounds
, cache
))?
;
181 if let Some(ref ty
) = default {
183 write
!(f
, " = {:#}", ty
.print(cache
))?
;
185 write
!(f
, " = {}", ty
.print(cache
))?
;
191 clean
::GenericParamDefKind
::Const { ref ty, .. }
=> {
193 write
!(f
, "const {}: {:#}", self.name
, ty
.print(cache
))
195 write
!(f
, "const {}: {}", self.name
, ty
.print(cache
))
202 impl clean
::Generics
{
203 crate fn print
<'a
>(&'a
self, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
204 display_fn(move |f
| {
206 self.params
.iter().filter(|p
| !p
.is_synthetic_type_param()).collect
::<Vec
<_
>>();
207 if real_params
.is_empty() {
211 write
!(f
, "<{:#}>", comma_sep(real_params
.iter().map(|g
| g
.print(cache
))))
213 write
!(f
, "<{}>", comma_sep(real_params
.iter().map(|g
| g
.print(cache
))))
219 impl<'a
> WhereClause
<'a
> {
220 crate fn print
<'b
>(&'b
self, cache
: &'b Cache
) -> impl fmt
::Display
+ 'b
{
221 display_fn(move |f
| {
222 let &WhereClause { gens, indent, end_newline }
= self;
223 if gens
.where_predicates
.is_empty() {
226 let mut clause
= String
::new();
228 clause
.push_str(" where");
231 clause
.push_str(" <span class=\"where fmt-newline\">where");
233 clause
.push_str(" <span class=\"where\">where");
236 for (i
, pred
) in gens
.where_predicates
.iter().enumerate() {
240 clause
.push_str("<br>");
244 clean
::WherePredicate
::BoundPredicate { ty, bounds }
=> {
247 clause
.push_str(&format
!(
250 print_generic_bounds(bounds
, cache
)
253 clause
.push_str(&format
!(
256 print_generic_bounds(bounds
, cache
)
260 clean
::WherePredicate
::RegionPredicate { lifetime, bounds }
=> {
261 clause
.push_str(&format
!(
266 .map(|b
| b
.print(cache
).to_string())
271 clean
::WherePredicate
::EqPredicate { lhs, rhs }
=> {
273 clause
.push_str(&format
!(
279 clause
.push_str(&format
!(
288 if i
< gens
.where_predicates
.len() - 1 || end_newline
{
294 // add a space so stripping <br> tags and breaking spaces still renders properly
298 clause
.push_str(" ");
303 clause
.push_str("</span>");
304 let padding
= " ".repeat(indent
+ 4);
305 clause
= clause
.replace("<br>", &format
!("<br>{}", padding
));
306 clause
.insert_str(0, &" ".repeat(indent
.saturating_sub(1)));
308 clause
.insert_str(0, "<br>");
311 write
!(f
, "{}", clause
)
316 impl clean
::Lifetime
{
317 crate fn print(&self) -> impl fmt
::Display
+ '_
{
322 impl clean
::Constant
{
323 crate fn print(&self) -> impl fmt
::Display
+ '_
{
324 display_fn(move |f
| {
326 f
.write_str(&self.expr
)
328 write
!(f
, "{}", Escape(&self.expr
))
334 impl clean
::PolyTrait
{
335 fn print
<'a
>(&'a
self, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
336 display_fn(move |f
| {
337 if !self.generic_params
.is_empty() {
342 comma_sep(self.generic_params
.iter().map(|g
| g
.print(cache
)))
348 comma_sep(self.generic_params
.iter().map(|g
| g
.print(cache
)))
353 write
!(f
, "{:#}", self.trait_
.print(cache
))
355 write
!(f
, "{}", self.trait_
.print(cache
))
361 impl clean
::GenericBound
{
362 crate fn print
<'a
>(&'a
self, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
363 display_fn(move |f
| match self {
364 clean
::GenericBound
::Outlives(lt
) => write
!(f
, "{}", lt
.print()),
365 clean
::GenericBound
::TraitBound(ty
, modifier
) => {
366 let modifier_str
= match modifier
{
367 hir
::TraitBoundModifier
::None
=> "",
368 hir
::TraitBoundModifier
::Maybe
=> "?",
369 hir
::TraitBoundModifier
::MaybeConst
=> "?const",
372 write
!(f
, "{}{:#}", modifier_str
, ty
.print(cache
))
374 write
!(f
, "{}{}", modifier_str
, ty
.print(cache
))
381 impl clean
::GenericArgs
{
382 fn print
<'a
>(&'a
self, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
383 display_fn(move |f
| {
385 clean
::GenericArgs
::AngleBracketed { args, bindings }
=> {
386 if !args
.is_empty() || !bindings
.is_empty() {
390 f
.write_str("<")?
;
392 let mut comma
= false;
399 write
!(f
, "{:#}", arg
.print(cache
))?
;
401 write
!(f
, "{}", arg
.print(cache
))?
;
404 for binding
in bindings
{
410 write
!(f
, "{:#}", binding
.print(cache
))?
;
412 write
!(f
, "{}", binding
.print(cache
))?
;
418 f
.write_str(">")?
;
422 clean
::GenericArgs
::Parenthesized { inputs, output }
=> {
424 let mut comma
= false;
431 write
!(f
, "{:#}", ty
.print(cache
))?
;
433 write
!(f
, "{}", ty
.print(cache
))?
;
437 if let Some(ref ty
) = *output
{
439 write
!(f
, " -> {:#}", ty
.print(cache
))?
;
441 write
!(f
, " -> {}", ty
.print(cache
))?
;
451 impl clean
::PathSegment
{
452 crate fn print
<'a
>(&'a
self, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
453 display_fn(move |f
| {
455 write
!(f
, "{}{:#}", self.name
, self.args
.print(cache
))
457 write
!(f
, "{}{}", self.name
, self.args
.print(cache
))
464 crate fn print
<'a
>(&'a
self, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
465 display_fn(move |f
| {
470 for (i
, seg
) in self.segments
.iter().enumerate() {
475 write
!(f
, "{:#}", seg
.print(cache
))?
;
477 write
!(f
, "{}", seg
.print(cache
))?
;
485 crate fn href(did
: DefId
, cache
: &Cache
) -> Option
<(String
, ItemType
, Vec
<String
>)> {
486 if !did
.is_local() && !cache
.access_levels
.is_public(did
) && !cache
.document_private
{
490 let depth
= CURRENT_DEPTH
.with(|l
| l
.get());
491 let (fqp
, shortty
, mut url
) = match cache
.paths
.get(&did
) {
492 Some(&(ref fqp
, shortty
)) => (fqp
, shortty
, "../".repeat(depth
)),
494 let &(ref fqp
, shortty
) = cache
.external_paths
.get(&did
)?
;
498 match cache
.extern_locations
[&did
.krate
] {
499 (.., ExternalLocation
::Remote(ref s
)) => s
.to_string(),
500 (.., ExternalLocation
::Local
) => "../".repeat(depth
),
501 (.., ExternalLocation
::Unknown
) => return None
,
506 for component
in &fqp
[..fqp
.len() - 1] {
507 url
.push_str(component
);
511 ItemType
::Module
=> {
512 url
.push_str(fqp
.last().unwrap());
513 url
.push_str("/index.html");
516 url
.push_str(shortty
.as_str());
518 url
.push_str(fqp
.last().unwrap());
519 url
.push_str(".html");
522 Some((url
, shortty
, fqp
.to_vec()))
525 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
526 /// rendering function with the necessary arguments for linking to a local path.
528 w
: &mut fmt
::Formatter
<'_
>,
535 let last
= path
.segments
.last().unwrap();
538 for seg
in &path
.segments
[..path
.segments
.len() - 1] {
539 write
!(w
, "{}::", seg
.name
)?
;
543 write
!(w
, "{}{:#}", &last
.name
, last
.args
.print(cache
))?
;
545 let path
= if use_absolute
{
546 if let Some((_
, _
, fqp
)) = href(did
, cache
) {
549 fqp
[..fqp
.len() - 1].join("::"),
550 anchor(did
, fqp
.last().unwrap(), cache
)
553 last
.name
.to_string()
556 anchor(did
, &*last
.name
.as_str(), cache
).to_string()
558 write
!(w
, "{}{}", path
, last
.args
.print(cache
))?
;
564 f
: &mut fmt
::Formatter
<'_
>,
565 prim
: clean
::PrimitiveType
,
569 let mut needs_termination
= false;
571 match m
.primitive_locations
.get(&prim
) {
572 Some(&def_id
) if def_id
.is_local() => {
573 let len
= CURRENT_DEPTH
.with(|s
| s
.get());
574 let len
= if len
== 0 { 0 }
else { len - 1 }
;
577 "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
581 needs_termination
= true;
584 let loc
= match m
.extern_locations
[&def_id
.krate
] {
585 (ref cname
, _
, ExternalLocation
::Remote(ref s
)) => Some((cname
, s
.to_string())),
586 (ref cname
, _
, ExternalLocation
::Local
) => {
587 let len
= CURRENT_DEPTH
.with(|s
| s
.get());
588 Some((cname
, "../".repeat(len
)))
590 (.., ExternalLocation
::Unknown
) => None
,
592 if let Some((cname
, root
)) = loc
{
595 "<a class=\"primitive\" href=\"{}{}/primitive.{}.html\">",
600 needs_termination
= true;
606 write
!(f
, "{}", name
)?
;
607 if needs_termination
{
613 /// Helper to render type parameters
615 param_names
: &'a Option
<Vec
<clean
::GenericBound
>>,
617 ) -> impl fmt
::Display
+ 'a
{
618 display_fn(move |f
| match *param_names
{
619 Some(ref params
) => {
620 for param
in params
{
622 fmt
::Display
::fmt(¶m
.print(cache
), f
)?
;
630 crate fn anchor
<'a
>(did
: DefId
, text
: &'a
str, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
631 display_fn(move |f
| {
632 if let Some((url
, short_ty
, fqp
)) = href(did
, cache
) {
635 r
#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
643 write
!(f
, "{}", text
)
650 f
: &mut fmt
::Formatter
<'_
>,
654 debug
!("fmt_type(t = {:?})", t
);
657 clean
::Generic(name
) => write
!(f
, "{}", name
),
658 clean
::ResolvedPath { did, ref param_names, ref path, is_generic }
=> {
659 if param_names
.is_some() {
660 f
.write_str("dyn ")?
;
662 // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
663 resolved_path(f
, did
, path
, is_generic
, use_absolute
, cache
)?
;
664 fmt
::Display
::fmt(&tybounds(param_names
, cache
), f
)
666 clean
::Infer
=> write
!(f
, "_"),
667 clean
::Primitive(prim
) => primitive_link(f
, prim
, prim
.as_str(), cache
),
668 clean
::BareFunction(ref decl
) => {
673 decl
.print_hrtb_with_space(cache
),
674 decl
.unsafety
.print_with_space(),
675 print_abi_with_space(decl
.abi
),
676 decl
.decl
.print(cache
)
682 decl
.print_hrtb_with_space(cache
),
683 decl
.unsafety
.print_with_space(),
684 print_abi_with_space(decl
.abi
)
686 primitive_link(f
, PrimitiveType
::Fn
, "fn", cache
)?
;
687 write
!(f
, "{}", decl
.decl
.print(cache
))
690 clean
::Tuple(ref typs
) => {
692 &[] => primitive_link(f
, PrimitiveType
::Unit
, "()", cache
),
694 primitive_link(f
, PrimitiveType
::Tuple
, "(", cache
)?
;
695 // Carry `f.alternate()` into this display w/o branching manually.
696 fmt
::Display
::fmt(&one
.print(cache
), f
)?
;
697 primitive_link(f
, PrimitiveType
::Tuple
, ",)", cache
)
700 primitive_link(f
, PrimitiveType
::Tuple
, "(", cache
)?
;
701 for (i
, item
) in many
.iter().enumerate() {
705 fmt
::Display
::fmt(&item
.print(cache
), f
)?
;
707 primitive_link(f
, PrimitiveType
::Tuple
, ")", cache
)
711 clean
::Slice(ref t
) => {
712 primitive_link(f
, PrimitiveType
::Slice
, "[", cache
)?
;
713 fmt
::Display
::fmt(&t
.print(cache
), f
)?
;
714 primitive_link(f
, PrimitiveType
::Slice
, "]", cache
)
716 clean
::Array(ref t
, ref n
) => {
717 primitive_link(f
, PrimitiveType
::Array
, "[", cache
)?
;
718 fmt
::Display
::fmt(&t
.print(cache
), f
)?
;
720 primitive_link(f
, PrimitiveType
::Array
, &format
!("; {}]", n
), cache
)
722 primitive_link(f
, PrimitiveType
::Array
, &format
!("; {}]", Escape(n
)), cache
)
725 clean
::Never
=> primitive_link(f
, PrimitiveType
::Never
, "!", cache
),
726 clean
::RawPointer(m
, ref t
) => {
728 hir
::Mutability
::Mut
=> "mut",
729 hir
::Mutability
::Not
=> "const",
732 clean
::Generic(_
) | clean
::ResolvedPath { is_generic: true, .. }
=> {
736 clean
::PrimitiveType
::RawPointer
,
737 &format
!("*{} {:#}", m
, t
.print(cache
)),
743 clean
::PrimitiveType
::RawPointer
,
744 &format
!("*{} {}", m
, t
.print(cache
)),
752 clean
::PrimitiveType
::RawPointer
,
756 fmt
::Display
::fmt(&t
.print(cache
), f
)
760 clean
::BorrowedRef { lifetime: ref l, mutability, type_: ref ty }
=> {
762 Some(l
) => format
!("{} ", l
.print()),
765 let m
= mutability
.print_with_space();
766 let amp
= if f
.alternate() { "&".to_string() }
else { "&".to_string() }
;
768 clean
::Slice(ref bt
) => {
769 // `BorrowedRef{ ... Slice(T) }` is `&[T]`
771 clean
::Generic(_
) => {
775 PrimitiveType
::Slice
,
776 &format
!("{}{}{}[{:#}]", amp
, lt
, m
, bt
.print(cache
)),
782 PrimitiveType
::Slice
,
783 &format
!("{}{}{}[{}]", amp
, lt
, m
, bt
.print(cache
)),
791 PrimitiveType
::Slice
,
792 &format
!("{}{}{}[", amp
, lt
, m
),
796 write
!(f
, "{:#}", bt
.print(cache
))?
;
798 write
!(f
, "{}", bt
.print(cache
))?
;
800 primitive_link(f
, PrimitiveType
::Slice
, "]", cache
)
804 clean
::ResolvedPath { param_names: Some(ref v), .. }
if !v
.is_empty() => {
805 write
!(f
, "{}{}{}(", amp
, lt
, m
)?
;
806 fmt_type(&ty
, f
, use_absolute
, cache
)?
;
809 clean
::Generic(..) => {
812 PrimitiveType
::Reference
,
813 &format
!("{}{}{}", amp
, lt
, m
),
816 fmt_type(&ty
, f
, use_absolute
, cache
)
819 write
!(f
, "{}{}{}", amp
, lt
, m
)?
;
820 fmt_type(&ty
, f
, use_absolute
, cache
)
824 clean
::ImplTrait(ref bounds
) => {
826 write
!(f
, "impl {:#}", print_generic_bounds(bounds
, cache
))
828 write
!(f
, "impl {}", print_generic_bounds(bounds
, cache
))
831 clean
::QPath { ref name, ref self_type, ref trait_ }
=> {
832 let should_show_cast
= match *trait_
{
833 box clean
::ResolvedPath { ref path, .. }
=> {
834 !path
.segments
.is_empty() && !self_type
.is_self_type()
839 if should_show_cast
{
840 write
!(f
, "<{:#} as {:#}>::", self_type
.print(cache
), trait_
.print(cache
))?
842 write
!(f
, "{:#}::", self_type
.print(cache
))?
845 if should_show_cast
{
846 write
!(f
, "<{} as {}>::", self_type
.print(cache
), trait_
.print(cache
))?
848 write
!(f
, "{}::", self_type
.print(cache
))?
852 // It's pretty unsightly to look at `<A as B>::C` in output, and
853 // we've got hyperlinking on our side, so try to avoid longer
854 // notation as much as possible by making `C` a hyperlink to trait
855 // `B` to disambiguate.
857 // FIXME: this is still a lossy conversion and there should probably
858 // be a better way of representing this in general? Most of
859 // the ugliness comes from inlining across crates where
860 // everything comes in as a fully resolved QPath (hard to
862 box clean
::ResolvedPath { did, ref param_names, .. }
=> {
863 match href(did
, cache
) {
864 Some((ref url
, _
, ref path
)) if !f
.alternate() => {
867 "<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
868 title=\"type {path}::{name}\">{name}</a>",
870 shortty
= ItemType
::AssocType
,
872 path
= path
.join("::")
875 _
=> write
!(f
, "{}", name
)?
,
878 // FIXME: `param_names` are not rendered, and this seems bad?
882 _
=> write
!(f
, "{}", name
),
889 crate fn print
<'b
, 'a
: 'b
>(&'a
self, cache
: &'b Cache
) -> impl fmt
::Display
+ 'b
{
890 display_fn(move |f
| fmt_type(self, f
, false, cache
))
895 crate fn print
<'a
>(&'a
self, cache
: &'a Cache
, use_absolute
: bool
) -> impl fmt
::Display
+ 'a
{
896 display_fn(move |f
| {
898 write
!(f
, "impl{:#} ", self.generics
.print(cache
))?
;
900 write
!(f
, "impl{} ", self.generics
.print(cache
))?
;
903 if let Some(ref ty
) = self.trait_
{
904 if self.negative_polarity
{
907 fmt
::Display
::fmt(&ty
.print(cache
), f
)?
;
911 if let Some(ref ty
) = self.blanket_impl
{
912 fmt_type(ty
, f
, use_absolute
, cache
)?
;
914 fmt_type(&self.for_
, f
, use_absolute
, cache
)?
;
917 let where_clause
= WhereClause { gens: &self.generics, indent: 0, end_newline: true }
;
918 fmt
::Display
::fmt(&where_clause
.print(cache
), f
)?
;
924 impl clean
::Arguments
{
925 crate fn print
<'a
>(&'a
self, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
926 display_fn(move |f
| {
927 for (i
, input
) in self.values
.iter().enumerate() {
928 if !input
.name
.is_empty() {
929 write
!(f
, "{}: ", input
.name
)?
;
932 write
!(f
, "{:#}", input
.type_
.print(cache
))?
;
934 write
!(f
, "{}", input
.type_
.print(cache
))?
;
936 if i
+ 1 < self.values
.len() {
945 impl clean
::FnRetTy
{
946 crate fn print
<'a
>(&'a
self, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
947 display_fn(move |f
| match self {
948 clean
::Return(clean
::Tuple(tys
)) if tys
.is_empty() => Ok(()),
949 clean
::Return(ty
) if f
.alternate() => write
!(f
, " -> {:#}", ty
.print(cache
)),
950 clean
::Return(ty
) => write
!(f
, " -> {}", ty
.print(cache
)),
951 clean
::DefaultReturn
=> Ok(()),
956 impl clean
::BareFunctionDecl
{
957 fn print_hrtb_with_space
<'a
>(&'a
self, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
958 display_fn(move |f
| {
959 if !self.generic_params
.is_empty() {
960 write
!(f
, "for<{}> ", comma_sep(self.generic_params
.iter().map(|g
| g
.print(cache
))))
969 crate fn print
<'a
>(&'a
self, cache
: &'a Cache
) -> impl fmt
::Display
+ 'a
{
970 display_fn(move |f
| {
971 let ellipsis
= if self.c_variadic { ", ..." }
else { "" }
;
975 "({args:#}{ellipsis}){arrow:#}",
976 args
= self.inputs
.print(cache
),
978 arrow
= self.output
.print(cache
)
983 "({args}{ellipsis}){arrow}",
984 args
= self.inputs
.print(cache
),
986 arrow
= self.output
.print(cache
)
994 crate fn print
<'b
, 'a
: 'b
>(&'a
self, cache
: &'b Cache
) -> impl fmt
::Display
+ 'b
{
995 display_fn(move |f
| {
996 let &Function { decl, header_len, indent, asyncness }
= self;
997 let amp
= if f
.alternate() { "&" }
else { "&" }
;
998 let mut args
= String
::new();
999 let mut args_plain
= String
::new();
1000 for (i
, input
) in decl
.inputs
.values
.iter().enumerate() {
1002 args
.push_str("<br>");
1005 if let Some(selfty
) = input
.to_self() {
1007 clean
::SelfValue
=> {
1008 args
.push_str("self");
1009 args_plain
.push_str("self");
1011 clean
::SelfBorrowed(Some(ref lt
), mtbl
) => {
1012 args
.push_str(&format
!(
1016 mtbl
.print_with_space()
1018 args_plain
.push_str(&format
!(
1021 mtbl
.print_with_space()
1024 clean
::SelfBorrowed(None
, mtbl
) => {
1025 args
.push_str(&format
!("{}{}self", amp
, mtbl
.print_with_space()));
1026 args_plain
.push_str(&format
!("&{}self", mtbl
.print_with_space()));
1028 clean
::SelfExplicit(ref typ
) => {
1030 args
.push_str(&format
!("self: {:#}", typ
.print(cache
)));
1032 args
.push_str(&format
!("self: {}", typ
.print(cache
)));
1034 args_plain
.push_str(&format
!("self: {:#}", typ
.print(cache
)));
1039 args
.push_str(" <br>");
1040 args_plain
.push(' '
);
1042 if !input
.name
.is_empty() {
1043 args
.push_str(&format
!("{}: ", input
.name
));
1044 args_plain
.push_str(&format
!("{}: ", input
.name
));
1048 args
.push_str(&format
!("{:#}", input
.type_
.print(cache
)));
1050 args
.push_str(&input
.type_
.print(cache
).to_string());
1052 args_plain
.push_str(&format
!("{:#}", input
.type_
.print(cache
)));
1054 if i
+ 1 < decl
.inputs
.values
.len() {
1056 args_plain
.push('
,'
);
1060 let mut args_plain
= format
!("({})", args_plain
);
1062 if decl
.c_variadic
{
1063 args
.push_str(",<br> ...");
1064 args_plain
.push_str(", ...");
1067 let output
= if let hir
::IsAsync
::Async
= asyncness
{
1068 Cow
::Owned(decl
.sugared_async_return_type())
1070 Cow
::Borrowed(&decl
.output
)
1073 let arrow_plain
= format
!("{:#}", &output
.print(cache
));
1074 let arrow
= if f
.alternate() {
1075 format
!("{:#}", &output
.print(cache
))
1077 output
.print(cache
).to_string()
1080 let declaration_len
= header_len
+ args_plain
.len() + arrow_plain
.len();
1081 let output
= if declaration_len
> 80 {
1082 let full_pad
= format
!("<br>{}", " ".repeat(indent
+ 4));
1083 let close_pad
= format
!("<br>{}", " ".repeat(indent
));
1085 "({args}{close}){arrow}",
1086 args
= args
.replace("<br>", &full_pad
),
1091 format
!("({args}){arrow}", args
= args
.replace("<br>", ""), arrow
= arrow
)
1095 write
!(f
, "{}", output
.replace("<br>", "\n"))
1097 write
!(f
, "{}", output
)
1103 impl clean
::Visibility
{
1104 crate fn print_with_space
<'tcx
>(
1109 ) -> impl fmt
::Display
+ 'tcx
{
1110 use rustc_span
::symbol
::kw
;
1112 let to_print
= match self {
1113 clean
::Public
=> "pub ".to_owned(),
1114 clean
::Inherited
=> String
::new(),
1115 clean
::Visibility
::Restricted(vis_did
) => {
1116 // FIXME(camelid): This may not work correctly if `item_did` is a module.
1117 // However, rustdoc currently never displays a module's
1118 // visibility, so it shouldn't matter.
1119 let parent_module
= find_nearest_parent_module(tcx
, item_did
);
1121 if vis_did
.index
== CRATE_DEF_INDEX
{
1122 "pub(crate) ".to_owned()
1123 } else if parent_module
== Some(vis_did
) {
1124 // `pub(in foo)` where `foo` is the parent module
1125 // is the same as no visibility modifier
1127 } else if parent_module
1128 .map(|parent
| find_nearest_parent_module(tcx
, parent
))
1132 "pub(super) ".to_owned()
1134 let path
= tcx
.def_path(vis_did
);
1135 debug
!("path={:?}", path
);
1137 path
.data
[0].data
.get_opt_name().expect("modules are always named");
1138 // modified from `resolved_path()` to work with `DefPathData`
1139 let last_name
= path
.data
.last().unwrap().data
.get_opt_name().unwrap();
1140 let anchor
= anchor(vis_did
, &last_name
.as_str(), cache
).to_string();
1142 let mut s
= "pub(".to_owned();
1143 if path
.data
.len() != 1
1144 || (first_name
!= kw
::SelfLower
&& first_name
!= kw
::Super
)
1148 for seg
in &path
.data
[..path
.data
.len() - 1] {
1149 s
.push_str(&format
!("{}::", seg
.data
.get_opt_name().unwrap()));
1151 s
.push_str(&format
!("{}) ", anchor
));
1156 display_fn(move |f
| f
.write_str(&to_print
))
1160 crate trait PrintWithSpace
{
1161 fn print_with_space(&self) -> &str;
1164 impl PrintWithSpace
for hir
::Unsafety
{
1165 fn print_with_space(&self) -> &str {
1167 hir
::Unsafety
::Unsafe
=> "unsafe ",
1168 hir
::Unsafety
::Normal
=> "",
1173 impl PrintWithSpace
for hir
::Constness
{
1174 fn print_with_space(&self) -> &str {
1176 hir
::Constness
::Const
=> "const ",
1177 hir
::Constness
::NotConst
=> "",
1182 impl PrintWithSpace
for hir
::IsAsync
{
1183 fn print_with_space(&self) -> &str {
1185 hir
::IsAsync
::Async
=> "async ",
1186 hir
::IsAsync
::NotAsync
=> "",
1191 impl PrintWithSpace
for hir
::Mutability
{
1192 fn print_with_space(&self) -> &str {
1194 hir
::Mutability
::Not
=> "",
1195 hir
::Mutability
::Mut
=> "mut ",
1200 impl clean
::Import
{
1201 crate fn print
<'b
, 'a
: 'b
>(&'a
self, cache
: &'b Cache
) -> impl fmt
::Display
+ 'b
{
1202 display_fn(move |f
| match self.kind
{
1203 clean
::ImportKind
::Simple(name
) => {
1204 if name
== self.source
.path
.last() {
1205 write
!(f
, "use {};", self.source
.print(cache
))
1207 write
!(f
, "use {} as {};", self.source
.print(cache
), name
)
1210 clean
::ImportKind
::Glob
=> {
1211 if self.source
.path
.segments
.is_empty() {
1214 write
!(f
, "use {}::*;", self.source
.print(cache
))
1221 impl clean
::ImportSource
{
1222 crate fn print
<'b
, 'a
: 'b
>(&'a
self, cache
: &'b Cache
) -> impl fmt
::Display
+ 'b
{
1223 display_fn(move |f
| match self.did
{
1224 Some(did
) => resolved_path(f
, did
, &self.path
, true, false, cache
),
1226 for seg
in &self.path
.segments
[..self.path
.segments
.len() - 1] {
1227 write
!(f
, "{}::", seg
.name
)?
;
1229 let name
= self.path
.last_name();
1230 if let hir
::def
::Res
::PrimTy(p
) = self.path
.res
{
1231 primitive_link(f
, PrimitiveType
::from(p
), &*name
, cache
)?
;
1233 write
!(f
, "{}", name
)?
;
1241 impl clean
::TypeBinding
{
1242 crate fn print
<'b
, 'a
: 'b
>(&'a
self, cache
: &'b Cache
) -> impl fmt
::Display
+ 'b
{
1243 display_fn(move |f
| {
1244 f
.write_str(&*self.name
.as_str())?
;
1246 clean
::TypeBindingKind
::Equality { ref ty }
=> {
1248 write
!(f
, " = {:#}", ty
.print(cache
))?
;
1250 write
!(f
, " = {}", ty
.print(cache
))?
;
1253 clean
::TypeBindingKind
::Constraint { ref bounds }
=> {
1254 if !bounds
.is_empty() {
1256 write
!(f
, ": {:#}", print_generic_bounds(bounds
, cache
))?
;
1258 write
!(f
, ": {}", print_generic_bounds(bounds
, cache
))?
;
1268 crate fn print_abi_with_space(abi
: Abi
) -> impl fmt
::Display
{
1269 display_fn(move |f
| {
1270 let quot
= if f
.alternate() { "\"" }
else { """ }
;
1272 Abi
::Rust
=> Ok(()),
1273 abi
=> write
!(f
, "extern {0}{1}{0} ", quot
, abi
.name()),
1278 crate fn print_default_space
<'a
>(v
: bool
) -> &'a
str {
1279 if v { "default " }
else { "" }
1282 impl clean
::GenericArg
{
1283 crate fn print
<'b
, 'a
: 'b
>(&'a
self, cache
: &'b Cache
) -> impl fmt
::Display
+ 'b
{
1284 display_fn(move |f
| match self {
1285 clean
::GenericArg
::Lifetime(lt
) => fmt
::Display
::fmt(<
.print(), f
),
1286 clean
::GenericArg
::Type(ty
) => fmt
::Display
::fmt(&ty
.print(cache
), f
),
1287 clean
::GenericArg
::Const(ct
) => fmt
::Display
::fmt(&ct
.print(), f
),
1292 crate fn display_fn(f
: impl FnOnce(&mut fmt
::Formatter
<'_
>) -> fmt
::Result
) -> impl fmt
::Display
{
1293 struct WithFormatter
<F
>(Cell
<Option
<F
>>);
1295 impl<F
> fmt
::Display
for WithFormatter
<F
>
1297 F
: FnOnce(&mut fmt
::Formatter
<'_
>) -> fmt
::Result
,
1299 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1300 (self.0.take()).unwrap()(f
)
1304 WithFormatter(Cell
::new(Some(f
)))