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 from_display
<T
: std
::fmt
::Display
>(&mut self, t
: T
) {
107 write
!(self, "{}", t
);
109 write
!(self, "{:#}", t
);
113 crate fn is_for_html(&self) -> bool
{
118 /// Wrapper struct for properly emitting a function or method declaration.
119 crate struct Function
<'a
> {
120 /// The declaration to emit.
121 crate decl
: &'a clean
::FnDecl
,
122 /// The length of the function header and name. In other words, the number of characters in the
123 /// function declaration up to but not including the parentheses.
125 /// Used to determine line-wrapping.
126 crate header_len
: usize,
127 /// The number of spaces to indent each successive line with, if line-wrapping is necessary.
129 /// Whether the function is async or not.
130 crate asyncness
: hir
::IsAsync
,
133 /// Wrapper struct for emitting a where-clause from Generics.
134 crate struct WhereClause
<'a
> {
135 /// The Generics from which to emit a where-clause.
136 crate gens
: &'a clean
::Generics
,
137 /// The number of spaces to indent each line with.
139 /// Whether the where-clause needs to add a comma and newline after the last bound.
140 crate end_newline
: bool
,
143 fn comma_sep
<T
: fmt
::Display
>(items
: impl Iterator
<Item
= T
>) -> impl fmt
::Display
{
144 display_fn(move |f
| {
145 for (i
, item
) in items
.enumerate() {
149 fmt
::Display
::fmt(&item
, f
)?
;
155 crate fn print_generic_bounds(bounds
: &[clean
::GenericBound
]) -> impl fmt
::Display
+ '_
{
156 display_fn(move |f
| {
157 let mut bounds_dup
= FxHashSet
::default();
160 bounds
.iter().filter(|b
| bounds_dup
.insert(b
.print().to_string())).enumerate()
165 fmt
::Display
::fmt(&bound
.print(), f
)?
;
171 impl clean
::GenericParamDef
{
172 crate fn print(&self) -> impl fmt
::Display
+ '_
{
173 display_fn(move |f
| match self.kind
{
174 clean
::GenericParamDefKind
::Lifetime
=> write
!(f
, "{}", self.name
),
175 clean
::GenericParamDefKind
::Type { ref bounds, ref default, .. }
=> {
176 f
.write_str(&*self.name
.as_str())?
;
178 if !bounds
.is_empty() {
180 write
!(f
, ": {:#}", print_generic_bounds(bounds
))?
;
182 write
!(f
, ": {}", print_generic_bounds(bounds
))?
;
186 if let Some(ref ty
) = default {
188 write
!(f
, " = {:#}", ty
.print())?
;
190 write
!(f
, " = {}", ty
.print())?
;
196 clean
::GenericParamDefKind
::Const { ref ty, .. }
=> {
198 write
!(f
, "const {}: {:#}", self.name
, ty
.print())
200 write
!(f
, "const {}: {}", self.name
, ty
.print())
207 impl clean
::Generics
{
208 crate fn print(&self) -> impl fmt
::Display
+ '_
{
209 display_fn(move |f
| {
211 self.params
.iter().filter(|p
| !p
.is_synthetic_type_param()).collect
::<Vec
<_
>>();
212 if real_params
.is_empty() {
216 write
!(f
, "<{:#}>", comma_sep(real_params
.iter().map(|g
| g
.print())))
218 write
!(f
, "<{}>", comma_sep(real_params
.iter().map(|g
| g
.print())))
224 impl<'a
> fmt
::Display
for WhereClause
<'a
> {
225 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
226 let &WhereClause { gens, indent, end_newline }
= self;
227 if gens
.where_predicates
.is_empty() {
230 let mut clause
= String
::new();
232 clause
.push_str(" where");
235 clause
.push_str(" <span class=\"where fmt-newline\">where");
237 clause
.push_str(" <span class=\"where\">where");
240 for (i
, pred
) in gens
.where_predicates
.iter().enumerate() {
244 clause
.push_str("<br>");
248 &clean
::WherePredicate
::BoundPredicate { ref ty, ref bounds }
=> {
251 clause
.push_str(&format
!(
254 print_generic_bounds(bounds
)
257 clause
.push_str(&format
!(
260 print_generic_bounds(bounds
)
264 &clean
::WherePredicate
::RegionPredicate { ref lifetime, ref bounds }
=> {
265 clause
.push_str(&format
!(
270 .map(|b
| b
.print().to_string())
275 &clean
::WherePredicate
::EqPredicate { ref lhs, ref rhs }
=> {
277 clause
.push_str(&format
!("{:#} == {:#}", lhs
.print(), rhs
.print()));
279 clause
.push_str(&format
!("{} == {}", lhs
.print(), rhs
.print()));
284 if i
< gens
.where_predicates
.len() - 1 || end_newline
{
290 // add a space so stripping <br> tags and breaking spaces still renders properly
294 clause
.push_str(" ");
299 clause
.push_str("</span>");
300 let padding
= " ".repeat(indent
+ 4);
301 clause
= clause
.replace("<br>", &format
!("<br>{}", padding
));
302 clause
.insert_str(0, &" ".repeat(indent
.saturating_sub(1)));
304 clause
.insert_str(0, "<br>");
307 write
!(f
, "{}", clause
)
311 impl clean
::Lifetime
{
312 crate fn print(&self) -> impl fmt
::Display
+ '_
{
317 impl clean
::Constant
{
318 crate fn print(&self) -> impl fmt
::Display
+ '_
{
319 display_fn(move |f
| {
321 f
.write_str(&self.expr
)
323 write
!(f
, "{}", Escape(&self.expr
))
329 impl clean
::PolyTrait
{
330 fn print(&self) -> impl fmt
::Display
+ '_
{
331 display_fn(move |f
| {
332 if !self.generic_params
.is_empty() {
337 comma_sep(self.generic_params
.iter().map(|g
| g
.print()))
343 comma_sep(self.generic_params
.iter().map(|g
| g
.print()))
348 write
!(f
, "{:#}", self.trait_
.print())
350 write
!(f
, "{}", self.trait_
.print())
356 impl clean
::GenericBound
{
357 crate fn print(&self) -> impl fmt
::Display
+ '_
{
358 display_fn(move |f
| match self {
359 clean
::GenericBound
::Outlives(lt
) => write
!(f
, "{}", lt
.print()),
360 clean
::GenericBound
::TraitBound(ty
, modifier
) => {
361 let modifier_str
= match modifier
{
362 hir
::TraitBoundModifier
::None
=> "",
363 hir
::TraitBoundModifier
::Maybe
=> "?",
364 hir
::TraitBoundModifier
::MaybeConst
=> "?const",
367 write
!(f
, "{}{:#}", modifier_str
, ty
.print())
369 write
!(f
, "{}{}", modifier_str
, ty
.print())
376 impl clean
::GenericArgs
{
377 fn print(&self) -> impl fmt
::Display
+ '_
{
378 display_fn(move |f
| {
380 clean
::GenericArgs
::AngleBracketed { ref args, ref bindings }
=> {
381 if !args
.is_empty() || !bindings
.is_empty() {
385 f
.write_str("<")?
;
387 let mut comma
= false;
394 write
!(f
, "{:#}", arg
.print())?
;
396 write
!(f
, "{}", arg
.print())?
;
399 for binding
in bindings
{
405 write
!(f
, "{:#}", binding
.print())?
;
407 write
!(f
, "{}", binding
.print())?
;
413 f
.write_str(">")?
;
417 clean
::GenericArgs
::Parenthesized { ref inputs, ref output }
=> {
419 let mut comma
= false;
426 write
!(f
, "{:#}", ty
.print())?
;
428 write
!(f
, "{}", ty
.print())?
;
432 if let Some(ref ty
) = *output
{
434 write
!(f
, " -> {:#}", ty
.print())?
;
436 write
!(f
, " -> {}", ty
.print())?
;
446 impl clean
::PathSegment
{
447 crate fn print(&self) -> impl fmt
::Display
+ '_
{
448 display_fn(move |f
| {
450 write
!(f
, "{}{:#}", self.name
, self.args
.print())
452 write
!(f
, "{}{}", self.name
, self.args
.print())
459 crate fn print(&self) -> impl fmt
::Display
+ '_
{
460 display_fn(move |f
| {
465 for (i
, seg
) in self.segments
.iter().enumerate() {
470 write
!(f
, "{:#}", seg
.print())?
;
472 write
!(f
, "{}", seg
.print())?
;
480 crate fn href(did
: DefId
) -> Option
<(String
, ItemType
, Vec
<String
>)> {
482 if !did
.is_local() && !cache
.access_levels
.is_public(did
) && !cache
.document_private
{
486 let depth
= CURRENT_DEPTH
.with(|l
| l
.get());
487 let (fqp
, shortty
, mut url
) = match cache
.paths
.get(&did
) {
488 Some(&(ref fqp
, shortty
)) => (fqp
, shortty
, "../".repeat(depth
)),
490 let &(ref fqp
, shortty
) = cache
.external_paths
.get(&did
)?
;
494 match cache
.extern_locations
[&did
.krate
] {
495 (.., ExternalLocation
::Remote(ref s
)) => s
.to_string(),
496 (.., ExternalLocation
::Local
) => "../".repeat(depth
),
497 (.., ExternalLocation
::Unknown
) => return None
,
502 for component
in &fqp
[..fqp
.len() - 1] {
503 url
.push_str(component
);
507 ItemType
::Module
=> {
508 url
.push_str(fqp
.last().unwrap());
509 url
.push_str("/index.html");
512 url
.push_str(shortty
.as_str());
514 url
.push_str(fqp
.last().unwrap());
515 url
.push_str(".html");
518 Some((url
, shortty
, fqp
.to_vec()))
521 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
522 /// rendering function with the necessary arguments for linking to a local path.
524 w
: &mut fmt
::Formatter
<'_
>,
530 let last
= path
.segments
.last().unwrap();
533 for seg
in &path
.segments
[..path
.segments
.len() - 1] {
534 write
!(w
, "{}::", seg
.name
)?
;
538 write
!(w
, "{}{:#}", &last
.name
, last
.args
.print())?
;
540 let path
= if use_absolute
{
541 if let Some((_
, _
, fqp
)) = href(did
) {
542 format
!("{}::{}", fqp
[..fqp
.len() - 1].join("::"), anchor(did
, fqp
.last().unwrap()))
544 last
.name
.to_string()
547 anchor(did
, &*last
.name
.as_str()).to_string()
549 write
!(w
, "{}{}", path
, last
.args
.print())?
;
555 f
: &mut fmt
::Formatter
<'_
>,
556 prim
: clean
::PrimitiveType
,
560 let mut needs_termination
= false;
562 match m
.primitive_locations
.get(&prim
) {
563 Some(&def_id
) if def_id
.is_local() => {
564 let len
= CURRENT_DEPTH
.with(|s
| s
.get());
565 let len
= if len
== 0 { 0 }
else { len - 1 }
;
568 "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
572 needs_termination
= true;
575 let loc
= match m
.extern_locations
[&def_id
.krate
] {
576 (ref cname
, _
, ExternalLocation
::Remote(ref s
)) => Some((cname
, s
.to_string())),
577 (ref cname
, _
, ExternalLocation
::Local
) => {
578 let len
= CURRENT_DEPTH
.with(|s
| s
.get());
579 Some((cname
, "../".repeat(len
)))
581 (.., ExternalLocation
::Unknown
) => None
,
583 if let Some((cname
, root
)) = loc
{
586 "<a class=\"primitive\" href=\"{}{}/primitive.{}.html\">",
591 needs_termination
= true;
597 write
!(f
, "{}", name
)?
;
598 if needs_termination
{
604 /// Helper to render type parameters
605 fn tybounds(param_names
: &Option
<Vec
<clean
::GenericBound
>>) -> impl fmt
::Display
+ '_
{
606 display_fn(move |f
| match *param_names
{
607 Some(ref params
) => {
608 for param
in params
{
610 fmt
::Display
::fmt(¶m
.print(), f
)?
;
618 crate fn anchor(did
: DefId
, text
: &str) -> impl fmt
::Display
+ '_
{
619 display_fn(move |f
| {
620 if let Some((url
, short_ty
, fqp
)) = href(did
) {
623 r
#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
631 write
!(f
, "{}", text
)
636 fn fmt_type(t
: &clean
::Type
, f
: &mut fmt
::Formatter
<'_
>, use_absolute
: bool
) -> fmt
::Result
{
638 clean
::Generic(name
) => write
!(f
, "{}", name
),
639 clean
::ResolvedPath { did, ref param_names, ref path, is_generic }
=> {
640 if param_names
.is_some() {
641 f
.write_str("dyn ")?
;
643 // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
644 resolved_path(f
, did
, path
, is_generic
, use_absolute
)?
;
645 fmt
::Display
::fmt(&tybounds(param_names
), f
)
647 clean
::Infer
=> write
!(f
, "_"),
648 clean
::Primitive(prim
) => primitive_link(f
, prim
, prim
.as_str()),
649 clean
::BareFunction(ref decl
) => {
654 decl
.unsafety
.print_with_space(),
655 print_abi_with_space(decl
.abi
),
656 decl
.print_generic_params(),
663 decl
.unsafety
.print_with_space(),
664 print_abi_with_space(decl
.abi
)
666 primitive_link(f
, PrimitiveType
::Fn
, "fn")?
;
667 write
!(f
, "{}{}", decl
.print_generic_params(), decl
.decl
.print())
670 clean
::Tuple(ref typs
) => {
672 &[] => primitive_link(f
, PrimitiveType
::Unit
, "()"),
674 primitive_link(f
, PrimitiveType
::Tuple
, "(")?
;
675 // Carry `f.alternate()` into this display w/o branching manually.
676 fmt
::Display
::fmt(&one
.print(), f
)?
;
677 primitive_link(f
, PrimitiveType
::Tuple
, ",)")
680 primitive_link(f
, PrimitiveType
::Tuple
, "(")?
;
681 for (i
, item
) in many
.iter().enumerate() {
685 fmt
::Display
::fmt(&item
.print(), f
)?
;
687 primitive_link(f
, PrimitiveType
::Tuple
, ")")
691 clean
::Slice(ref t
) => {
692 primitive_link(f
, PrimitiveType
::Slice
, "[")?
;
693 fmt
::Display
::fmt(&t
.print(), f
)?
;
694 primitive_link(f
, PrimitiveType
::Slice
, "]")
696 clean
::Array(ref t
, ref n
) => {
697 primitive_link(f
, PrimitiveType
::Array
, "[")?
;
698 fmt
::Display
::fmt(&t
.print(), f
)?
;
700 primitive_link(f
, PrimitiveType
::Array
, &format
!("; {}]", n
))
702 primitive_link(f
, PrimitiveType
::Array
, &format
!("; {}]", Escape(n
)))
705 clean
::Never
=> primitive_link(f
, PrimitiveType
::Never
, "!"),
706 clean
::RawPointer(m
, ref t
) => {
708 hir
::Mutability
::Mut
=> "mut",
709 hir
::Mutability
::Not
=> "const",
712 clean
::Generic(_
) | clean
::ResolvedPath { is_generic: true, .. }
=> {
716 clean
::PrimitiveType
::RawPointer
,
717 &format
!("*{} {:#}", m
, t
.print()),
722 clean
::PrimitiveType
::RawPointer
,
723 &format
!("*{} {}", m
, t
.print()),
728 primitive_link(f
, clean
::PrimitiveType
::RawPointer
, &format
!("*{} ", m
))?
;
729 fmt
::Display
::fmt(&t
.print(), f
)
733 clean
::BorrowedRef { lifetime: ref l, mutability, type_: ref ty }
=> {
735 Some(l
) => format
!("{} ", l
.print()),
738 let m
= mutability
.print_with_space();
739 let amp
= if f
.alternate() { "&".to_string() }
else { "&".to_string() }
;
741 clean
::Slice(ref bt
) => {
742 // `BorrowedRef{ ... Slice(T) }` is `&[T]`
744 clean
::Generic(_
) => {
748 PrimitiveType
::Slice
,
749 &format
!("{}{}{}[{:#}]", amp
, lt
, m
, bt
.print()),
754 PrimitiveType
::Slice
,
755 &format
!("{}{}{}[{}]", amp
, lt
, m
, bt
.print()),
762 PrimitiveType
::Slice
,
763 &format
!("{}{}{}[", amp
, lt
, m
),
766 write
!(f
, "{:#}", bt
.print())?
;
768 write
!(f
, "{}", bt
.print())?
;
770 primitive_link(f
, PrimitiveType
::Slice
, "]")
774 clean
::ResolvedPath { param_names: Some(ref v), .. }
if !v
.is_empty() => {
775 write
!(f
, "{}{}{}(", amp
, lt
, m
)?
;
776 fmt_type(&ty
, f
, use_absolute
)?
;
779 clean
::Generic(..) => {
780 primitive_link(f
, PrimitiveType
::Reference
, &format
!("{}{}{}", amp
, lt
, m
))?
;
781 fmt_type(&ty
, f
, use_absolute
)
784 write
!(f
, "{}{}{}", amp
, lt
, m
)?
;
785 fmt_type(&ty
, f
, use_absolute
)
789 clean
::ImplTrait(ref bounds
) => {
791 write
!(f
, "impl {:#}", print_generic_bounds(bounds
))
793 write
!(f
, "impl {}", print_generic_bounds(bounds
))
796 clean
::QPath { ref name, ref self_type, ref trait_ }
=> {
797 let should_show_cast
= match *trait_
{
798 box clean
::ResolvedPath { ref path, .. }
=> {
799 !path
.segments
.is_empty() && !self_type
.is_self_type()
804 if should_show_cast
{
805 write
!(f
, "<{:#} as {:#}>::", self_type
.print(), trait_
.print())?
807 write
!(f
, "{:#}::", self_type
.print())?
810 if should_show_cast
{
811 write
!(f
, "<{} as {}>::", self_type
.print(), trait_
.print())?
813 write
!(f
, "{}::", self_type
.print())?
817 // It's pretty unsightly to look at `<A as B>::C` in output, and
818 // we've got hyperlinking on our side, so try to avoid longer
819 // notation as much as possible by making `C` a hyperlink to trait
820 // `B` to disambiguate.
822 // FIXME: this is still a lossy conversion and there should probably
823 // be a better way of representing this in general? Most of
824 // the ugliness comes from inlining across crates where
825 // everything comes in as a fully resolved QPath (hard to
827 box clean
::ResolvedPath { did, ref param_names, .. }
=> {
829 Some((ref url
, _
, ref path
)) if !f
.alternate() => {
832 "<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
833 title=\"type {path}::{name}\">{name}</a>",
835 shortty
= ItemType
::AssocType
,
837 path
= path
.join("::")
840 _
=> write
!(f
, "{}", name
)?
,
843 // FIXME: `param_names` are not rendered, and this seems bad?
847 _
=> write
!(f
, "{}", name
),
854 crate fn print(&self) -> impl fmt
::Display
+ '_
{
855 display_fn(move |f
| fmt_type(self, f
, false))
860 crate fn print(&self) -> impl fmt
::Display
+ '_
{
861 self.print_inner(true, false)
864 fn print_inner(&self, link_trait
: bool
, use_absolute
: bool
) -> impl fmt
::Display
+ '_
{
865 display_fn(move |f
| {
867 write
!(f
, "impl{:#} ", self.generics
.print())?
;
869 write
!(f
, "impl{} ", self.generics
.print())?
;
872 if let Some(ref ty
) = self.trait_
{
873 if self.polarity
== Some(clean
::ImplPolarity
::Negative
) {
878 fmt
::Display
::fmt(&ty
.print(), f
)?
;
881 clean
::ResolvedPath
{
882 param_names
: None
, path
, is_generic
: false, ..
884 let last
= path
.segments
.last().unwrap();
885 fmt
::Display
::fmt(&last
.name
, f
)?
;
886 fmt
::Display
::fmt(&last
.args
.print(), f
)?
;
894 if let Some(ref ty
) = self.blanket_impl
{
895 fmt_type(ty
, f
, use_absolute
)?
;
897 fmt_type(&self.for_
, f
, use_absolute
)?
;
901 &WhereClause { gens: &self.generics, indent: 0, end_newline: true }
,
909 // The difference from above is that trait is not hyperlinked.
910 crate fn fmt_impl_for_trait_page(i
: &clean
::Impl
, f
: &mut Buffer
, use_absolute
: bool
) {
911 f
.from_display(i
.print_inner(false, use_absolute
))
914 impl clean
::Arguments
{
915 crate fn print(&self) -> impl fmt
::Display
+ '_
{
916 display_fn(move |f
| {
917 for (i
, input
) in self.values
.iter().enumerate() {
918 if !input
.name
.is_empty() {
919 write
!(f
, "{}: ", input
.name
)?
;
922 write
!(f
, "{:#}", input
.type_
.print())?
;
924 write
!(f
, "{}", input
.type_
.print())?
;
926 if i
+ 1 < self.values
.len() {
935 impl clean
::FnRetTy
{
936 crate fn print(&self) -> impl fmt
::Display
+ '_
{
937 display_fn(move |f
| match self {
938 clean
::Return(clean
::Tuple(tys
)) if tys
.is_empty() => Ok(()),
939 clean
::Return(ty
) if f
.alternate() => write
!(f
, " -> {:#}", ty
.print()),
940 clean
::Return(ty
) => write
!(f
, " -> {}", ty
.print()),
941 clean
::DefaultReturn
=> Ok(()),
946 impl clean
::BareFunctionDecl
{
947 fn print_generic_params(&self) -> impl fmt
::Display
+ '_
{
948 comma_sep(self.generic_params
.iter().map(|g
| g
.print()))
953 crate fn print(&self) -> impl fmt
::Display
+ '_
{
954 display_fn(move |f
| {
955 let ellipsis
= if self.c_variadic { ", ..." }
else { "" }
;
959 "({args:#}{ellipsis}){arrow:#}",
960 args
= self.inputs
.print(),
962 arrow
= self.output
.print()
967 "({args}{ellipsis}){arrow}",
968 args
= self.inputs
.print(),
970 arrow
= self.output
.print()
978 crate fn print(&self) -> impl fmt
::Display
+ '_
{
979 display_fn(move |f
| {
980 let &Function { decl, header_len, indent, asyncness }
= self;
981 let amp
= if f
.alternate() { "&" }
else { "&" }
;
982 let mut args
= String
::new();
983 let mut args_plain
= String
::new();
984 for (i
, input
) in decl
.inputs
.values
.iter().enumerate() {
986 args
.push_str("<br>");
989 if let Some(selfty
) = input
.to_self() {
991 clean
::SelfValue
=> {
992 args
.push_str("self");
993 args_plain
.push_str("self");
995 clean
::SelfBorrowed(Some(ref lt
), mtbl
) => {
996 args
.push_str(&format
!(
1000 mtbl
.print_with_space()
1002 args_plain
.push_str(&format
!(
1005 mtbl
.print_with_space()
1008 clean
::SelfBorrowed(None
, mtbl
) => {
1009 args
.push_str(&format
!("{}{}self", amp
, mtbl
.print_with_space()));
1010 args_plain
.push_str(&format
!("&{}self", mtbl
.print_with_space()));
1012 clean
::SelfExplicit(ref typ
) => {
1014 args
.push_str(&format
!("self: {:#}", typ
.print()));
1016 args
.push_str(&format
!("self: {}", typ
.print()));
1018 args_plain
.push_str(&format
!("self: {:#}", typ
.print()));
1023 args
.push_str(" <br>");
1024 args_plain
.push_str(" ");
1026 if !input
.name
.is_empty() {
1027 args
.push_str(&format
!("{}: ", input
.name
));
1028 args_plain
.push_str(&format
!("{}: ", input
.name
));
1032 args
.push_str(&format
!("{:#}", input
.type_
.print()));
1034 args
.push_str(&input
.type_
.print().to_string());
1036 args_plain
.push_str(&format
!("{:#}", input
.type_
.print()));
1038 if i
+ 1 < decl
.inputs
.values
.len() {
1040 args_plain
.push('
,'
);
1044 let mut args_plain
= format
!("({})", args_plain
);
1046 if decl
.c_variadic
{
1047 args
.push_str(",<br> ...");
1048 args_plain
.push_str(", ...");
1051 let output
= if let hir
::IsAsync
::Async
= asyncness
{
1052 Cow
::Owned(decl
.sugared_async_return_type())
1054 Cow
::Borrowed(&decl
.output
)
1057 let arrow_plain
= format
!("{:#}", &output
.print());
1058 let arrow
= if f
.alternate() {
1059 format
!("{:#}", &output
.print())
1061 output
.print().to_string()
1064 let declaration_len
= header_len
+ args_plain
.len() + arrow_plain
.len();
1065 let output
= if declaration_len
> 80 {
1066 let full_pad
= format
!("<br>{}", " ".repeat(indent
+ 4));
1067 let close_pad
= format
!("<br>{}", " ".repeat(indent
));
1069 "({args}{close}){arrow}",
1070 args
= args
.replace("<br>", &full_pad
),
1075 format
!("({args}){arrow}", args
= args
.replace("<br>", ""), arrow
= arrow
)
1079 write
!(f
, "{}", output
.replace("<br>", "\n"))
1081 write
!(f
, "{}", output
)
1087 impl clean
::Visibility
{
1088 crate fn print_with_space
<'tcx
>(
1092 ) -> impl fmt
::Display
+ 'tcx
{
1093 use rustc_span
::symbol
::kw
;
1095 display_fn(move |f
| match self {
1096 clean
::Public
=> f
.write_str("pub "),
1097 clean
::Inherited
=> Ok(()),
1099 clean
::Visibility
::Restricted(vis_did
) => {
1100 // FIXME(camelid): This may not work correctly if `item_did` is a module.
1101 // However, rustdoc currently never displays a module's
1102 // visibility, so it shouldn't matter.
1103 let parent_module
= find_nearest_parent_module(tcx
, item_did
);
1105 if vis_did
.index
== CRATE_DEF_INDEX
{
1106 write
!(f
, "pub(crate) ")
1107 } else if parent_module
== Some(vis_did
) {
1108 // `pub(in foo)` where `foo` is the parent module
1109 // is the same as no visibility modifier
1111 } else if parent_module
1112 .map(|parent
| find_nearest_parent_module(tcx
, parent
))
1116 write
!(f
, "pub(super) ")
1118 f
.write_str("pub(")?
;
1119 let path
= tcx
.def_path(vis_did
);
1120 debug
!("path={:?}", path
);
1122 path
.data
[0].data
.get_opt_name().expect("modules are always named");
1123 if path
.data
.len() != 1
1124 || (first_name
!= kw
::SelfLower
&& first_name
!= kw
::Super
)
1126 f
.write_str("in ")?
;
1128 // modified from `resolved_path()` to work with `DefPathData`
1129 let last_name
= path
.data
.last().unwrap().data
.get_opt_name().unwrap();
1130 for seg
in &path
.data
[..path
.data
.len() - 1] {
1131 write
!(f
, "{}::", seg
.data
.get_opt_name().unwrap())?
;
1133 let path
= anchor(vis_did
, &last_name
.as_str()).to_string();
1134 write
!(f
, "{}) ", path
)
1141 crate trait PrintWithSpace
{
1142 fn print_with_space(&self) -> &str;
1145 impl PrintWithSpace
for hir
::Unsafety
{
1146 fn print_with_space(&self) -> &str {
1148 hir
::Unsafety
::Unsafe
=> "unsafe ",
1149 hir
::Unsafety
::Normal
=> "",
1154 impl PrintWithSpace
for hir
::Constness
{
1155 fn print_with_space(&self) -> &str {
1157 hir
::Constness
::Const
=> "const ",
1158 hir
::Constness
::NotConst
=> "",
1163 impl PrintWithSpace
for hir
::IsAsync
{
1164 fn print_with_space(&self) -> &str {
1166 hir
::IsAsync
::Async
=> "async ",
1167 hir
::IsAsync
::NotAsync
=> "",
1172 impl PrintWithSpace
for hir
::Mutability
{
1173 fn print_with_space(&self) -> &str {
1175 hir
::Mutability
::Not
=> "",
1176 hir
::Mutability
::Mut
=> "mut ",
1181 impl clean
::Import
{
1182 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1183 display_fn(move |f
| match self.kind
{
1184 clean
::ImportKind
::Simple(name
) => {
1185 if name
== self.source
.path
.last() {
1186 write
!(f
, "use {};", self.source
.print())
1188 write
!(f
, "use {} as {};", self.source
.print(), name
)
1191 clean
::ImportKind
::Glob
=> {
1192 if self.source
.path
.segments
.is_empty() {
1195 write
!(f
, "use {}::*;", self.source
.print())
1202 impl clean
::ImportSource
{
1203 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1204 display_fn(move |f
| match self.did
{
1205 Some(did
) => resolved_path(f
, did
, &self.path
, true, false),
1207 for seg
in &self.path
.segments
[..self.path
.segments
.len() - 1] {
1208 write
!(f
, "{}::", seg
.name
)?
;
1210 let name
= self.path
.last_name();
1211 if let hir
::def
::Res
::PrimTy(p
) = self.path
.res
{
1212 primitive_link(f
, PrimitiveType
::from(p
), &*name
)?
;
1214 write
!(f
, "{}", name
)?
;
1222 impl clean
::TypeBinding
{
1223 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1224 display_fn(move |f
| {
1225 f
.write_str(&*self.name
.as_str())?
;
1227 clean
::TypeBindingKind
::Equality { ref ty }
=> {
1229 write
!(f
, " = {:#}", ty
.print())?
;
1231 write
!(f
, " = {}", ty
.print())?
;
1234 clean
::TypeBindingKind
::Constraint { ref bounds }
=> {
1235 if !bounds
.is_empty() {
1237 write
!(f
, ": {:#}", print_generic_bounds(bounds
))?
;
1239 write
!(f
, ": {}", print_generic_bounds(bounds
))?
;
1249 crate fn print_abi_with_space(abi
: Abi
) -> impl fmt
::Display
{
1250 display_fn(move |f
| {
1251 let quot
= if f
.alternate() { "\"" }
else { """ }
;
1253 Abi
::Rust
=> Ok(()),
1254 abi
=> write
!(f
, "extern {0}{1}{0} ", quot
, abi
.name()),
1259 crate fn print_default_space
<'a
>(v
: bool
) -> &'a
str {
1260 if v { "default " }
else { "" }
1263 impl clean
::GenericArg
{
1264 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1265 display_fn(move |f
| match self {
1266 clean
::GenericArg
::Lifetime(lt
) => fmt
::Display
::fmt(<
.print(), f
),
1267 clean
::GenericArg
::Type(ty
) => fmt
::Display
::fmt(&ty
.print(), f
),
1268 clean
::GenericArg
::Const(ct
) => fmt
::Display
::fmt(&ct
.print(), f
),
1273 crate fn display_fn(f
: impl FnOnce(&mut fmt
::Formatter
<'_
>) -> fmt
::Result
) -> impl fmt
::Display
{
1274 WithFormatter(Cell
::new(Some(f
)))
1277 struct WithFormatter
<F
>(Cell
<Option
<F
>>);
1279 impl<F
> fmt
::Display
for WithFormatter
<F
>
1281 F
: FnOnce(&mut fmt
::Formatter
<'_
>) -> fmt
::Result
,
1283 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1284 (self.0.take()).unwrap()(f
)