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)))