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_span
::def_id
::DefId
;
15 use rustc_target
::spec
::abi
::Abi
;
17 use crate::clean
::{self, PrimitiveType}
;
18 use crate::formats
::cache
::cache
;
19 use crate::formats
::item_type
::ItemType
;
20 use crate::html
::escape
::Escape
;
21 use crate::html
::render
::cache
::ExternalLocation
;
22 use crate::html
::render
::CURRENT_DEPTH
;
25 fn print(self, buffer
: &mut Buffer
);
30 F
: FnOnce(&mut Buffer
),
32 fn print(self, buffer
: &mut Buffer
) {
37 impl Print
for String
{
38 fn print(self, buffer
: &mut Buffer
) {
39 buffer
.write_str(&self);
43 impl Print
for &'_
str {
44 fn print(self, buffer
: &mut Buffer
) {
45 buffer
.write_str(self);
49 #[derive(Debug, Clone)]
56 crate fn empty_from(v
: &Buffer
) -> Buffer
{
57 Buffer { for_html: v.for_html, buffer: String::new() }
60 crate fn html() -> Buffer
{
61 Buffer { for_html: true, buffer: String::new() }
64 crate fn new() -> Buffer
{
65 Buffer { for_html: false, buffer: String::new() }
68 crate fn is_empty(&self) -> bool
{
69 self.buffer
.is_empty()
72 crate fn into_inner(self) -> String
{
76 crate fn insert_str(&mut self, idx
: usize, s
: &str) {
77 self.buffer
.insert_str(idx
, s
);
80 crate fn push_str(&mut self, s
: &str) {
81 self.buffer
.push_str(s
);
84 // Intended for consumption by write! and writeln! (std::fmt) but without
85 // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
87 crate fn write_str(&mut self, s
: &str) {
88 self.buffer
.push_str(s
);
91 // Intended for consumption by write! and writeln! (std::fmt) but without
92 // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
94 crate fn write_fmt(&mut self, v
: fmt
::Arguments
<'_
>) {
96 self.buffer
.write_fmt(v
).unwrap();
99 crate fn to_display
<T
: Print
>(mut self, t
: T
) -> String
{
104 crate fn from_display
<T
: std
::fmt
::Display
>(&mut self, t
: T
) {
106 write
!(self, "{}", t
);
108 write
!(self, "{:#}", t
);
112 crate fn is_for_html(&self) -> bool
{
117 /// Wrapper struct for properly emitting a function or method declaration.
118 pub struct Function
<'a
> {
119 /// The declaration to emit.
120 pub decl
: &'a clean
::FnDecl
,
121 /// The length of the function header and name. In other words, the number of characters in the
122 /// function declaration up to but not including the parentheses.
124 /// Used to determine line-wrapping.
125 pub header_len
: usize,
126 /// The number of spaces to indent each successive line with, if line-wrapping is necessary.
128 /// Whether the function is async or not.
129 pub asyncness
: hir
::IsAsync
,
132 /// Wrapper struct for emitting a where-clause from Generics.
133 pub struct WhereClause
<'a
> {
134 /// The Generics from which to emit a where-clause.
135 pub gens
: &'a clean
::Generics
,
136 /// The number of spaces to indent each line with.
138 /// Whether the where-clause needs to add a comma and newline after the last bound.
139 pub end_newline
: bool
,
142 fn comma_sep
<T
: fmt
::Display
>(items
: impl Iterator
<Item
= T
>) -> impl fmt
::Display
{
143 display_fn(move |f
| {
144 for (i
, item
) in items
.enumerate() {
148 fmt
::Display
::fmt(&item
, f
)?
;
154 crate fn print_generic_bounds(bounds
: &[clean
::GenericBound
]) -> impl fmt
::Display
+ '_
{
155 display_fn(move |f
| {
156 let mut bounds_dup
= FxHashSet
::default();
159 bounds
.iter().filter(|b
| bounds_dup
.insert(b
.print().to_string())).enumerate()
164 fmt
::Display
::fmt(&bound
.print(), f
)?
;
170 impl clean
::GenericParamDef
{
171 crate fn print(&self) -> impl fmt
::Display
+ '_
{
172 display_fn(move |f
| match self.kind
{
173 clean
::GenericParamDefKind
::Lifetime
=> write
!(f
, "{}", self.name
),
174 clean
::GenericParamDefKind
::Type { ref bounds, ref default, .. }
=> {
175 f
.write_str(&self.name
)?
;
177 if !bounds
.is_empty() {
179 write
!(f
, ": {:#}", print_generic_bounds(bounds
))?
;
181 write
!(f
, ": {}", print_generic_bounds(bounds
))?
;
185 if let Some(ref ty
) = default {
187 write
!(f
, " = {:#}", ty
.print())?
;
189 write
!(f
, " = {}", ty
.print())?
;
195 clean
::GenericParamDefKind
::Const { ref ty, .. }
=> {
196 f
.write_str("const ")?
;
197 f
.write_str(&self.name
)?
;
200 write
!(f
, ": {:#}", ty
.print())
202 write
!(f
, ": {}", ty
.print())
209 impl clean
::Generics
{
210 crate fn print(&self) -> impl fmt
::Display
+ '_
{
211 display_fn(move |f
| {
213 self.params
.iter().filter(|p
| !p
.is_synthetic_type_param()).collect
::<Vec
<_
>>();
214 if real_params
.is_empty() {
218 write
!(f
, "<{:#}>", comma_sep(real_params
.iter().map(|g
| g
.print())))
220 write
!(f
, "<{}>", comma_sep(real_params
.iter().map(|g
| g
.print())))
226 impl<'a
> fmt
::Display
for WhereClause
<'a
> {
227 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
228 let &WhereClause { gens, indent, end_newline }
= self;
229 if gens
.where_predicates
.is_empty() {
232 let mut clause
= String
::new();
234 clause
.push_str(" where");
237 clause
.push_str(" <span class=\"where fmt-newline\">where");
239 clause
.push_str(" <span class=\"where\">where");
242 for (i
, pred
) in gens
.where_predicates
.iter().enumerate() {
246 clause
.push_str("<br>");
250 &clean
::WherePredicate
::BoundPredicate { ref ty, ref bounds }
=> {
253 clause
.push_str(&format
!(
256 print_generic_bounds(bounds
)
259 clause
.push_str(&format
!(
262 print_generic_bounds(bounds
)
266 &clean
::WherePredicate
::RegionPredicate { ref lifetime, ref bounds }
=> {
267 clause
.push_str(&format
!(
272 .map(|b
| b
.print().to_string())
277 &clean
::WherePredicate
::EqPredicate { ref lhs, ref rhs }
=> {
279 clause
.push_str(&format
!("{:#} == {:#}", lhs
.print(), rhs
.print()));
281 clause
.push_str(&format
!("{} == {}", lhs
.print(), rhs
.print()));
286 if i
< gens
.where_predicates
.len() - 1 || end_newline
{
292 // add a space so stripping <br> tags and breaking spaces still renders properly
296 clause
.push_str(" ");
301 clause
.push_str("</span>");
302 let padding
= " ".repeat(indent
+ 4);
303 clause
= clause
.replace("<br>", &format
!("<br>{}", padding
));
304 clause
.insert_str(0, &" ".repeat(indent
.saturating_sub(1)));
306 clause
.insert_str(0, "<br>");
309 write
!(f
, "{}", clause
)
313 impl clean
::Lifetime
{
314 crate fn print(&self) -> &str {
319 impl clean
::Constant
{
320 crate fn print(&self) -> impl fmt
::Display
+ '_
{
321 display_fn(move |f
| {
323 f
.write_str(&self.expr
)
325 write
!(f
, "{}", Escape(&self.expr
))
331 impl clean
::PolyTrait
{
332 fn print(&self) -> impl fmt
::Display
+ '_
{
333 display_fn(move |f
| {
334 if !self.generic_params
.is_empty() {
339 comma_sep(self.generic_params
.iter().map(|g
| g
.print()))
345 comma_sep(self.generic_params
.iter().map(|g
| g
.print()))
350 write
!(f
, "{:#}", self.trait_
.print())
352 write
!(f
, "{}", self.trait_
.print())
358 impl clean
::GenericBound
{
359 crate fn print(&self) -> impl fmt
::Display
+ '_
{
360 display_fn(move |f
| match self {
361 clean
::GenericBound
::Outlives(lt
) => write
!(f
, "{}", lt
.print()),
362 clean
::GenericBound
::TraitBound(ty
, modifier
) => {
363 let modifier_str
= match modifier
{
364 hir
::TraitBoundModifier
::None
=> "",
365 hir
::TraitBoundModifier
::Maybe
=> "?",
366 hir
::TraitBoundModifier
::MaybeConst
=> "?const",
369 write
!(f
, "{}{:#}", modifier_str
, ty
.print())
371 write
!(f
, "{}{}", modifier_str
, ty
.print())
378 impl clean
::GenericArgs
{
379 fn print(&self) -> impl fmt
::Display
+ '_
{
380 display_fn(move |f
| {
382 clean
::GenericArgs
::AngleBracketed { ref args, ref bindings }
=> {
383 if !args
.is_empty() || !bindings
.is_empty() {
387 f
.write_str("<")?
;
389 let mut comma
= false;
396 write
!(f
, "{:#}", arg
.print())?
;
398 write
!(f
, "{}", arg
.print())?
;
401 for binding
in bindings
{
407 write
!(f
, "{:#}", binding
.print())?
;
409 write
!(f
, "{}", binding
.print())?
;
415 f
.write_str(">")?
;
419 clean
::GenericArgs
::Parenthesized { ref inputs, ref output }
=> {
421 let mut comma
= false;
428 write
!(f
, "{:#}", ty
.print())?
;
430 write
!(f
, "{}", ty
.print())?
;
434 if let Some(ref ty
) = *output
{
436 write
!(f
, " -> {:#}", ty
.print())?
;
438 write
!(f
, " -> {}", ty
.print())?
;
448 impl clean
::PathSegment
{
449 crate fn print(&self) -> impl fmt
::Display
+ '_
{
450 display_fn(move |f
| {
451 f
.write_str(&self.name
)?
;
453 write
!(f
, "{:#}", self.args
.print())
455 write
!(f
, "{}", self.args
.print())
462 crate fn print(&self) -> impl fmt
::Display
+ '_
{
463 display_fn(move |f
| {
468 for (i
, seg
) in self.segments
.iter().enumerate() {
473 write
!(f
, "{:#}", seg
.print())?
;
475 write
!(f
, "{}", seg
.print())?
;
483 pub fn href(did
: DefId
) -> Option
<(String
, ItemType
, Vec
<String
>)> {
485 if !did
.is_local() && !cache
.access_levels
.is_public(did
) && !cache
.document_private
{
489 let depth
= CURRENT_DEPTH
.with(|l
| l
.get());
490 let (fqp
, shortty
, mut url
) = match cache
.paths
.get(&did
) {
491 Some(&(ref fqp
, shortty
)) => (fqp
, shortty
, "../".repeat(depth
)),
493 let &(ref fqp
, shortty
) = cache
.external_paths
.get(&did
)?
;
497 match cache
.extern_locations
[&did
.krate
] {
498 (.., ExternalLocation
::Remote(ref s
)) => s
.to_string(),
499 (.., ExternalLocation
::Local
) => "../".repeat(depth
),
500 (.., ExternalLocation
::Unknown
) => return None
,
505 for component
in &fqp
[..fqp
.len() - 1] {
506 url
.push_str(component
);
510 ItemType
::Module
=> {
511 url
.push_str(fqp
.last().unwrap());
512 url
.push_str("/index.html");
515 url
.push_str(shortty
.as_str());
517 url
.push_str(fqp
.last().unwrap());
518 url
.push_str(".html");
521 Some((url
, shortty
, fqp
.to_vec()))
524 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
525 /// rendering function with the necessary arguments for linking to a local path.
527 w
: &mut fmt
::Formatter
<'_
>,
533 let last
= path
.segments
.last().unwrap();
536 for seg
in &path
.segments
[..path
.segments
.len() - 1] {
537 write
!(w
, "{}::", seg
.name
)?
;
541 write
!(w
, "{}{:#}", &last
.name
, last
.args
.print())?
;
543 let path
= if use_absolute
{
544 if let Some((_
, _
, fqp
)) = href(did
) {
545 format
!("{}::{}", fqp
[..fqp
.len() - 1].join("::"), anchor(did
, fqp
.last().unwrap()))
547 last
.name
.to_string()
550 anchor(did
, &last
.name
).to_string()
552 write
!(w
, "{}{}", path
, last
.args
.print())?
;
558 f
: &mut fmt
::Formatter
<'_
>,
559 prim
: clean
::PrimitiveType
,
563 let mut needs_termination
= false;
565 match m
.primitive_locations
.get(&prim
) {
566 Some(&def_id
) if def_id
.is_local() => {
567 let len
= CURRENT_DEPTH
.with(|s
| s
.get());
568 let len
= if len
== 0 { 0 }
else { len - 1 }
;
571 "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
575 needs_termination
= true;
578 let loc
= match m
.extern_locations
[&def_id
.krate
] {
579 (ref cname
, _
, ExternalLocation
::Remote(ref s
)) => Some((cname
, s
.to_string())),
580 (ref cname
, _
, ExternalLocation
::Local
) => {
581 let len
= CURRENT_DEPTH
.with(|s
| s
.get());
582 Some((cname
, "../".repeat(len
)))
584 (.., ExternalLocation
::Unknown
) => None
,
586 if let Some((cname
, root
)) = loc
{
589 "<a class=\"primitive\" href=\"{}{}/primitive.{}.html\">",
594 needs_termination
= true;
600 write
!(f
, "{}", name
)?
;
601 if needs_termination
{
607 /// Helper to render type parameters
608 fn tybounds(param_names
: &Option
<Vec
<clean
::GenericBound
>>) -> impl fmt
::Display
+ '_
{
609 display_fn(move |f
| match *param_names
{
610 Some(ref params
) => {
611 for param
in params
{
613 fmt
::Display
::fmt(¶m
.print(), f
)?
;
621 pub fn anchor(did
: DefId
, text
: &str) -> impl fmt
::Display
+ '_
{
622 display_fn(move |f
| {
623 if let Some((url
, short_ty
, fqp
)) = href(did
) {
626 r
#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
634 write
!(f
, "{}", text
)
639 fn fmt_type(t
: &clean
::Type
, f
: &mut fmt
::Formatter
<'_
>, use_absolute
: bool
) -> fmt
::Result
{
641 clean
::Generic(ref name
) => f
.write_str(name
),
642 clean
::ResolvedPath { did, ref param_names, ref path, is_generic }
=> {
643 if param_names
.is_some() {
644 f
.write_str("dyn ")?
;
646 // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
647 resolved_path(f
, did
, path
, is_generic
, use_absolute
)?
;
648 fmt
::Display
::fmt(&tybounds(param_names
), f
)
650 clean
::Infer
=> write
!(f
, "_"),
651 clean
::Primitive(prim
) => primitive_link(f
, prim
, prim
.as_str()),
652 clean
::BareFunction(ref decl
) => {
657 decl
.unsafety
.print_with_space(),
658 print_abi_with_space(decl
.abi
),
659 decl
.print_generic_params(),
666 decl
.unsafety
.print_with_space(),
667 print_abi_with_space(decl
.abi
)
669 primitive_link(f
, PrimitiveType
::Fn
, "fn")?
;
670 write
!(f
, "{}{}", decl
.print_generic_params(), decl
.decl
.print())
673 clean
::Tuple(ref typs
) => {
675 &[] => primitive_link(f
, PrimitiveType
::Unit
, "()"),
677 primitive_link(f
, PrimitiveType
::Tuple
, "(")?
;
678 // Carry `f.alternate()` into this display w/o branching manually.
679 fmt
::Display
::fmt(&one
.print(), f
)?
;
680 primitive_link(f
, PrimitiveType
::Tuple
, ",)")
683 primitive_link(f
, PrimitiveType
::Tuple
, "(")?
;
684 for (i
, item
) in many
.iter().enumerate() {
688 fmt
::Display
::fmt(&item
.print(), f
)?
;
690 primitive_link(f
, PrimitiveType
::Tuple
, ")")
694 clean
::Slice(ref t
) => {
695 primitive_link(f
, PrimitiveType
::Slice
, "[")?
;
696 fmt
::Display
::fmt(&t
.print(), f
)?
;
697 primitive_link(f
, PrimitiveType
::Slice
, "]")
699 clean
::Array(ref t
, ref n
) => {
700 primitive_link(f
, PrimitiveType
::Array
, "[")?
;
701 fmt
::Display
::fmt(&t
.print(), f
)?
;
703 primitive_link(f
, PrimitiveType
::Array
, &format
!("; {}]", n
))
705 primitive_link(f
, PrimitiveType
::Array
, &format
!("; {}]", Escape(n
)))
708 clean
::Never
=> primitive_link(f
, PrimitiveType
::Never
, "!"),
709 clean
::RawPointer(m
, ref t
) => {
711 hir
::Mutability
::Mut
=> "mut",
712 hir
::Mutability
::Not
=> "const",
715 clean
::Generic(_
) | clean
::ResolvedPath { is_generic: true, .. }
=> {
719 clean
::PrimitiveType
::RawPointer
,
720 &format
!("*{} {:#}", m
, t
.print()),
725 clean
::PrimitiveType
::RawPointer
,
726 &format
!("*{} {}", m
, t
.print()),
731 primitive_link(f
, clean
::PrimitiveType
::RawPointer
, &format
!("*{} ", m
))?
;
732 fmt
::Display
::fmt(&t
.print(), f
)
736 clean
::BorrowedRef { lifetime: ref l, mutability, type_: ref ty }
=> {
738 Some(l
) => format
!("{} ", l
.print()),
741 let m
= mutability
.print_with_space();
742 let amp
= if f
.alternate() { "&".to_string() }
else { "&".to_string() }
;
744 clean
::Slice(ref bt
) => {
745 // `BorrowedRef{ ... Slice(T) }` is `&[T]`
747 clean
::Generic(_
) => {
751 PrimitiveType
::Slice
,
752 &format
!("{}{}{}[{:#}]", amp
, lt
, m
, bt
.print()),
757 PrimitiveType
::Slice
,
758 &format
!("{}{}{}[{}]", amp
, lt
, m
, bt
.print()),
765 PrimitiveType
::Slice
,
766 &format
!("{}{}{}[", amp
, lt
, m
),
769 write
!(f
, "{:#}", bt
.print())?
;
771 write
!(f
, "{}", bt
.print())?
;
773 primitive_link(f
, PrimitiveType
::Slice
, "]")
777 clean
::ResolvedPath { param_names: Some(ref v), .. }
if !v
.is_empty() => {
778 write
!(f
, "{}{}{}(", amp
, lt
, m
)?
;
779 fmt_type(&ty
, f
, use_absolute
)?
;
782 clean
::Generic(..) => {
783 primitive_link(f
, PrimitiveType
::Reference
, &format
!("{}{}{}", amp
, lt
, m
))?
;
784 fmt_type(&ty
, f
, use_absolute
)
787 write
!(f
, "{}{}{}", amp
, lt
, m
)?
;
788 fmt_type(&ty
, f
, use_absolute
)
792 clean
::ImplTrait(ref bounds
) => {
794 write
!(f
, "impl {:#}", print_generic_bounds(bounds
))
796 write
!(f
, "impl {}", print_generic_bounds(bounds
))
799 clean
::QPath { ref name, ref self_type, ref trait_ }
=> {
800 let should_show_cast
= match *trait_
{
801 box clean
::ResolvedPath { ref path, .. }
=> {
802 !path
.segments
.is_empty() && !self_type
.is_self_type()
807 if should_show_cast
{
808 write
!(f
, "<{:#} as {:#}>::", self_type
.print(), trait_
.print())?
810 write
!(f
, "{:#}::", self_type
.print())?
813 if should_show_cast
{
814 write
!(f
, "<{} as {}>::", self_type
.print(), trait_
.print())?
816 write
!(f
, "{}::", self_type
.print())?
820 // It's pretty unsightly to look at `<A as B>::C` in output, and
821 // we've got hyperlinking on our side, so try to avoid longer
822 // notation as much as possible by making `C` a hyperlink to trait
823 // `B` to disambiguate.
825 // FIXME: this is still a lossy conversion and there should probably
826 // be a better way of representing this in general? Most of
827 // the ugliness comes from inlining across crates where
828 // everything comes in as a fully resolved QPath (hard to
830 box clean
::ResolvedPath { did, ref param_names, .. }
=> {
832 Some((ref url
, _
, ref path
)) if !f
.alternate() => {
835 "<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
836 title=\"type {path}::{name}\">{name}</a>",
838 shortty
= ItemType
::AssocType
,
840 path
= path
.join("::")
843 _
=> write
!(f
, "{}", name
)?
,
846 // FIXME: `param_names` are not rendered, and this seems bad?
850 _
=> write
!(f
, "{}", name
),
857 crate fn print(&self) -> impl fmt
::Display
+ '_
{
858 display_fn(move |f
| fmt_type(self, f
, false))
863 crate fn print(&self) -> impl fmt
::Display
+ '_
{
864 self.print_inner(true, false)
867 fn print_inner(&self, link_trait
: bool
, use_absolute
: bool
) -> impl fmt
::Display
+ '_
{
868 display_fn(move |f
| {
870 write
!(f
, "impl{:#} ", self.generics
.print())?
;
872 write
!(f
, "impl{} ", self.generics
.print())?
;
875 if let Some(ref ty
) = self.trait_
{
876 if self.polarity
== Some(clean
::ImplPolarity
::Negative
) {
881 fmt
::Display
::fmt(&ty
.print(), f
)?
;
884 clean
::ResolvedPath
{
885 param_names
: None
, path
, is_generic
: false, ..
887 let last
= path
.segments
.last().unwrap();
888 fmt
::Display
::fmt(&last
.name
, f
)?
;
889 fmt
::Display
::fmt(&last
.args
.print(), f
)?
;
897 if let Some(ref ty
) = self.blanket_impl
{
898 fmt_type(ty
, f
, use_absolute
)?
;
900 fmt_type(&self.for_
, f
, use_absolute
)?
;
904 &WhereClause { gens: &self.generics, indent: 0, end_newline: true }
,
912 // The difference from above is that trait is not hyperlinked.
913 pub fn fmt_impl_for_trait_page(i
: &clean
::Impl
, f
: &mut Buffer
, use_absolute
: bool
) {
914 f
.from_display(i
.print_inner(false, use_absolute
))
917 impl clean
::Arguments
{
918 crate fn print(&self) -> impl fmt
::Display
+ '_
{
919 display_fn(move |f
| {
920 for (i
, input
) in self.values
.iter().enumerate() {
921 if !input
.name
.is_empty() {
922 write
!(f
, "{}: ", input
.name
)?
;
925 write
!(f
, "{:#}", input
.type_
.print())?
;
927 write
!(f
, "{}", input
.type_
.print())?
;
929 if i
+ 1 < self.values
.len() {
938 impl clean
::FnRetTy
{
939 crate fn print(&self) -> impl fmt
::Display
+ '_
{
940 display_fn(move |f
| match self {
941 clean
::Return(clean
::Tuple(tys
)) if tys
.is_empty() => Ok(()),
942 clean
::Return(ty
) if f
.alternate() => write
!(f
, " -> {:#}", ty
.print()),
943 clean
::Return(ty
) => write
!(f
, " -> {}", ty
.print()),
944 clean
::DefaultReturn
=> Ok(()),
949 impl clean
::BareFunctionDecl
{
950 fn print_generic_params(&self) -> impl fmt
::Display
+ '_
{
951 comma_sep(self.generic_params
.iter().map(|g
| g
.print()))
956 crate fn print(&self) -> impl fmt
::Display
+ '_
{
957 display_fn(move |f
| {
958 let ellipsis
= if self.c_variadic { ", ..." }
else { "" }
;
962 "({args:#}{ellipsis}){arrow:#}",
963 args
= self.inputs
.print(),
965 arrow
= self.output
.print()
970 "({args}{ellipsis}){arrow}",
971 args
= self.inputs
.print(),
973 arrow
= self.output
.print()
981 crate fn print(&self) -> impl fmt
::Display
+ '_
{
982 display_fn(move |f
| {
983 let &Function { decl, header_len, indent, asyncness }
= self;
984 let amp
= if f
.alternate() { "&" }
else { "&" }
;
985 let mut args
= String
::new();
986 let mut args_plain
= String
::new();
987 for (i
, input
) in decl
.inputs
.values
.iter().enumerate() {
989 args
.push_str("<br>");
992 if let Some(selfty
) = input
.to_self() {
994 clean
::SelfValue
=> {
995 args
.push_str("self");
996 args_plain
.push_str("self");
998 clean
::SelfBorrowed(Some(ref lt
), mtbl
) => {
999 args
.push_str(&format
!(
1003 mtbl
.print_with_space()
1005 args_plain
.push_str(&format
!(
1008 mtbl
.print_with_space()
1011 clean
::SelfBorrowed(None
, mtbl
) => {
1012 args
.push_str(&format
!("{}{}self", amp
, mtbl
.print_with_space()));
1013 args_plain
.push_str(&format
!("&{}self", mtbl
.print_with_space()));
1015 clean
::SelfExplicit(ref typ
) => {
1017 args
.push_str(&format
!("self: {:#}", typ
.print()));
1019 args
.push_str(&format
!("self: {}", typ
.print()));
1021 args_plain
.push_str(&format
!("self: {:#}", typ
.print()));
1026 args
.push_str(" <br>");
1027 args_plain
.push_str(" ");
1029 if !input
.name
.is_empty() {
1030 args
.push_str(&format
!("{}: ", input
.name
));
1031 args_plain
.push_str(&format
!("{}: ", input
.name
));
1035 args
.push_str(&format
!("{:#}", input
.type_
.print()));
1037 args
.push_str(&input
.type_
.print().to_string());
1039 args_plain
.push_str(&format
!("{:#}", input
.type_
.print()));
1041 if i
+ 1 < decl
.inputs
.values
.len() {
1043 args_plain
.push('
,'
);
1047 let mut args_plain
= format
!("({})", args_plain
);
1049 if decl
.c_variadic
{
1050 args
.push_str(",<br> ...");
1051 args_plain
.push_str(", ...");
1054 let output
= if let hir
::IsAsync
::Async
= asyncness
{
1055 Cow
::Owned(decl
.sugared_async_return_type())
1057 Cow
::Borrowed(&decl
.output
)
1060 let arrow_plain
= format
!("{:#}", &output
.print());
1061 let arrow
= if f
.alternate() {
1062 format
!("{:#}", &output
.print())
1064 output
.print().to_string()
1067 let declaration_len
= header_len
+ args_plain
.len() + arrow_plain
.len();
1068 let output
= if declaration_len
> 80 {
1069 let full_pad
= format
!("<br>{}", " ".repeat(indent
+ 4));
1070 let close_pad
= format
!("<br>{}", " ".repeat(indent
));
1072 "({args}{close}){arrow}",
1073 args
= args
.replace("<br>", &full_pad
),
1078 format
!("({args}){arrow}", args
= args
.replace("<br>", ""), arrow
= arrow
)
1082 write
!(f
, "{}", output
.replace("<br>", "\n"))
1084 write
!(f
, "{}", output
)
1090 impl clean
::Visibility
{
1091 crate fn print_with_space(&self) -> impl fmt
::Display
+ '_
{
1092 display_fn(move |f
| match *self {
1093 clean
::Public
=> f
.write_str("pub "),
1094 clean
::Inherited
=> Ok(()),
1095 clean
::Visibility
::Crate
=> write
!(f
, "pub(crate) "),
1096 clean
::Visibility
::Restricted(did
, ref path
) => {
1097 f
.write_str("pub(")?
;
1098 if path
.segments
.len() != 1
1099 || (path
.segments
[0].name
!= "self" && path
.segments
[0].name
!= "super")
1101 f
.write_str("in ")?
;
1103 resolved_path(f
, did
, path
, true, false)?
;
1110 crate trait PrintWithSpace
{
1111 fn print_with_space(&self) -> &str;
1114 impl PrintWithSpace
for hir
::Unsafety
{
1115 fn print_with_space(&self) -> &str {
1117 hir
::Unsafety
::Unsafe
=> "unsafe ",
1118 hir
::Unsafety
::Normal
=> "",
1123 impl PrintWithSpace
for hir
::Constness
{
1124 fn print_with_space(&self) -> &str {
1126 hir
::Constness
::Const
=> "const ",
1127 hir
::Constness
::NotConst
=> "",
1132 impl PrintWithSpace
for hir
::IsAsync
{
1133 fn print_with_space(&self) -> &str {
1135 hir
::IsAsync
::Async
=> "async ",
1136 hir
::IsAsync
::NotAsync
=> "",
1141 impl PrintWithSpace
for hir
::Mutability
{
1142 fn print_with_space(&self) -> &str {
1144 hir
::Mutability
::Not
=> "",
1145 hir
::Mutability
::Mut
=> "mut ",
1150 impl clean
::Import
{
1151 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1152 display_fn(move |f
| match *self {
1153 clean
::Import
::Simple(ref name
, ref src
) => {
1154 if *name
== src
.path
.last_name() {
1155 write
!(f
, "use {};", src
.print())
1157 write
!(f
, "use {} as {};", src
.print(), *name
)
1160 clean
::Import
::Glob(ref src
) => {
1161 if src
.path
.segments
.is_empty() {
1164 write
!(f
, "use {}::*;", src
.print())
1171 impl clean
::ImportSource
{
1172 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1173 display_fn(move |f
| match self.did
{
1174 Some(did
) => resolved_path(f
, did
, &self.path
, true, false),
1176 for seg
in &self.path
.segments
[..self.path
.segments
.len() - 1] {
1177 write
!(f
, "{}::", seg
.name
)?
;
1179 let name
= self.path
.last_name();
1180 if let hir
::def
::Res
::PrimTy(p
) = self.path
.res
{
1181 primitive_link(f
, PrimitiveType
::from(p
), name
)?
;
1183 write
!(f
, "{}", name
)?
;
1191 impl clean
::TypeBinding
{
1192 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1193 display_fn(move |f
| {
1194 f
.write_str(&self.name
)?
;
1196 clean
::TypeBindingKind
::Equality { ref ty }
=> {
1198 write
!(f
, " = {:#}", ty
.print())?
;
1200 write
!(f
, " = {}", ty
.print())?
;
1203 clean
::TypeBindingKind
::Constraint { ref bounds }
=> {
1204 if !bounds
.is_empty() {
1206 write
!(f
, ": {:#}", print_generic_bounds(bounds
))?
;
1208 write
!(f
, ": {}", print_generic_bounds(bounds
))?
;
1218 crate fn print_abi_with_space(abi
: Abi
) -> impl fmt
::Display
{
1219 display_fn(move |f
| {
1220 let quot
= if f
.alternate() { "\"" }
else { """ }
;
1222 Abi
::Rust
=> Ok(()),
1223 abi
=> write
!(f
, "extern {0}{1}{0} ", quot
, abi
.name()),
1228 crate fn print_default_space
<'a
>(v
: bool
) -> &'a
str {
1229 if v { "default " }
else { "" }
1232 impl clean
::GenericArg
{
1233 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1234 display_fn(move |f
| match self {
1235 clean
::GenericArg
::Lifetime(lt
) => fmt
::Display
::fmt(<
.print(), f
),
1236 clean
::GenericArg
::Type(ty
) => fmt
::Display
::fmt(&ty
.print(), f
),
1237 clean
::GenericArg
::Const(ct
) => fmt
::Display
::fmt(&ct
.print(), f
),
1242 crate fn display_fn(f
: impl FnOnce(&mut fmt
::Formatter
<'_
>) -> fmt
::Result
) -> impl fmt
::Display
{
1243 WithFormatter(Cell
::new(Some(f
)))
1246 struct WithFormatter
<F
>(Cell
<Option
<F
>>);
1248 impl<F
> fmt
::Display
for WithFormatter
<F
>
1250 F
: FnOnce(&mut fmt
::Formatter
<'_
>) -> fmt
::Result
,
1252 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1253 (self.0.take()).unwrap()(f
)