, _>(|i| {
+ i.inner_impl()
+ .for_
+ .def_id_full(cx.cache())
+ .map_or(true, |d| cx.cache.paths.contains_key(&d))
+ });
+
+ let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
+ local.iter().partition(|i| i.inner_impl().synthetic);
+
+ synthetic.sort_by(|a, b| compare_impl(a, b, cx.cache()));
+ concrete.sort_by(|a, b| compare_impl(a, b, cx.cache()));
+
+ if !foreign.is_empty() {
+ write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "");
+
+ for implementor in foreign {
+ let assoc_link = AssocItemLink::GotoSource(
+ implementor.impl_item.def_id,
+ &implementor.inner_impl().provided_trait_methods,
+ );
+ render_impl(
+ w,
+ cx,
+ &implementor,
+ it,
+ assoc_link,
+ RenderMode::Normal,
+ implementor.impl_item.stable_since(cx.tcx()).as_deref(),
+ implementor.impl_item.const_stable_since(cx.tcx()).as_deref(),
+ false,
+ None,
+ true,
+ false,
+ &[],
+ );
+ }
+ write_loading_content(w, "");
+ }
+
+ write_small_section_header(
+ w,
+ "implementors",
+ "Implementors",
+ "",
+ );
+ for implementor in concrete {
+ render_implementor(cx, implementor, it, w, &implementor_dups, &[]);
+ }
+ write_loading_content(w, "
");
+
+ if t.is_auto {
+ write_small_section_header(
+ w,
+ "synthetic-implementors",
+ "Auto implementors",
+ "",
+ );
+ for implementor in synthetic {
+ render_implementor(
+ cx,
+ implementor,
+ it,
+ w,
+ &implementor_dups,
+ &collect_paths_for_type(implementor.inner_impl().for_.clone(), &cx.cache),
+ );
+ }
+ write_loading_content(w, "
");
+ }
+ } else {
+ // even without any implementations to write in, we still want the heading and list, so the
+ // implementors javascript file pulled in below has somewhere to write the impls into
+ write_small_section_header(
+ w,
+ "implementors",
+ "Implementors",
+ "",
+ );
+ write_loading_content(w, "
");
+
+ if t.is_auto {
+ write_small_section_header(
+ w,
+ "synthetic-implementors",
+ "Auto implementors",
+ "",
+ );
+ write_loading_content(w, "
");
+ }
+ }
+
+ write!(
+ w,
+ "",
+ root_path = vec![".."; cx.current.len()].join("/"),
+ path = if it.def_id.is_local() {
+ cx.current.join("/")
+ } else {
+ let (ref path, _) = cx.cache.external_paths[&it.def_id];
+ path[..path.len() - 1].join("/")
+ },
+ ty = it.type_(),
+ name = *it.name.as_ref().unwrap()
+ );
+}
+
+fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
+ w.write_str("");
+ render_attributes(w, it, false);
+ write!(
+ w,
+ "trait {}{}{} = {};
",
+ it.name.as_ref().unwrap(),
+ t.generics.print(cx.cache()),
+ WhereClause { gens: &t.generics, indent: 0, end_newline: true }.print(cx.cache()),
+ bounds(&t.bounds, true, cx.cache())
+ );
+
+ document(w, cx, it, None);
+
+ // Render any items associated directly to this alias, as otherwise they
+ // won't be visible anywhere in the docs. It would be nice to also show
+ // associated items from the aliased type (see discussion in #32077), but
+ // we need #14072 to make sense of the generics.
+ render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+}
+
+fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
+ w.write_str("");
+ render_attributes(w, it, false);
+ write!(
+ w,
+ "type {}{}{where_clause} = impl {bounds};
",
+ it.name.as_ref().unwrap(),
+ t.generics.print(cx.cache()),
+ where_clause =
+ WhereClause { gens: &t.generics, indent: 0, end_newline: true }.print(cx.cache()),
+ bounds = bounds(&t.bounds, false, cx.cache())
+ );
+
+ document(w, cx, it, None);
+
+ // Render any items associated directly to this alias, as otherwise they
+ // won't be visible anywhere in the docs. It would be nice to also show
+ // associated items from the aliased type (see discussion in #32077), but
+ // we need #14072 to make sense of the generics.
+ render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+}
+
+fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
+ w.write_str("");
+ render_attributes(w, it, false);
+ write!(
+ w,
+ "type {}{}{where_clause} = {type_};
",
+ it.name.as_ref().unwrap(),
+ t.generics.print(cx.cache()),
+ where_clause =
+ WhereClause { gens: &t.generics, indent: 0, end_newline: true }.print(cx.cache()),
+ type_ = t.type_.print(cx.cache())
+ );
+
+ document(w, cx, it, None);
+
+ // Render any items associated directly to this alias, as otherwise they
+ // won't be visible anywhere in the docs. It would be nice to also show
+ // associated items from the aliased type (see discussion in #32077), but
+ // we need #14072 to make sense of the generics.
+ render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+}
+
+fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
+ wrap_into_docblock(w, |w| {
+ w.write_str("");
+ render_attributes(w, it, true);
+ render_union(w, it, Some(&s.generics), &s.fields, "", true, cx);
+ w.write_str("
")
+ });
+
+ document(w, cx, it, None);
+ let mut fields = s
+ .fields
+ .iter()
+ .filter_map(|f| match *f.kind {
+ clean::StructFieldItem(ref ty) => Some((f, ty)),
+ _ => None,
+ })
+ .peekable();
+ if fields.peek().is_some() {
+ write!(
+ w,
+ "
+ Fields
"
+ );
+ for (field, ty) in fields {
+ let name = field.name.as_ref().expect("union field name");
+ let id = format!("{}.{}", ItemType::StructField, name);
+ write!(
+ w,
+ "\
+ \
+ {name}: {ty}
\
+ ",
+ id = id,
+ name = name,
+ shortty = ItemType::StructField,
+ ty = ty.print(cx.cache())
+ );
+ if let Some(stability_class) = field.stability_class(cx.tcx()) {
+ write!(w, "", stab = stability_class);
+ }
+ document(w, cx, field, Some(it));
+ }
+ }
+ render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+}
+
+fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
+ wrap_into_docblock(w, |w| {
+ w.write_str("");
+ render_attributes(w, it, true);
+ write!(
+ w,
+ "{}enum {}{}{}",
+ it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
+ it.name.as_ref().unwrap(),
+ e.generics.print(cx.cache()),
+ WhereClause { gens: &e.generics, indent: 0, end_newline: true }.print(cx.cache())
+ );
+ if e.variants.is_empty() && !e.variants_stripped {
+ w.write_str(" {}");
+ } else {
+ w.write_str(" {\n");
+ for v in &e.variants {
+ w.write_str(" ");
+ let name = v.name.as_ref().unwrap();
+ match *v.kind {
+ clean::VariantItem(ref var) => match var {
+ clean::Variant::CLike => write!(w, "{}", name),
+ clean::Variant::Tuple(ref tys) => {
+ write!(w, "{}(", name);
+ for (i, ty) in tys.iter().enumerate() {
+ if i > 0 {
+ w.write_str(", ")
+ }
+ write!(w, "{}", ty.print(cx.cache()));
+ }
+ w.write_str(")");
+ }
+ clean::Variant::Struct(ref s) => {
+ render_struct(w, v, None, s.struct_type, &s.fields, " ", false, cx);
+ }
+ },
+ _ => unreachable!(),
+ }
+ w.write_str(",\n");
+ }
+
+ if e.variants_stripped {
+ w.write_str(" // some variants omitted\n");
+ }
+ w.write_str("}");
+ }
+ w.write_str("
")
+ });
+
+ document(w, cx, it, None);
+ if !e.variants.is_empty() {
+ write!(
+ w,
+ "
+ Variants{}
\n",
+ document_non_exhaustive_header(it)
+ );
+ document_non_exhaustive(w, it);
+ for variant in &e.variants {
+ let id =
+ cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.as_ref().unwrap()));
+ write!(
+ w,
+ "\
+
\
+
{name}",
+ id = id,
+ name = variant.name.as_ref().unwrap()
+ );
+ if let clean::VariantItem(clean::Variant::Tuple(ref tys)) = *variant.kind {
+ w.write_str("(");
+ for (i, ty) in tys.iter().enumerate() {
+ if i > 0 {
+ w.write_str(", ");
+ }
+ write!(w, "{}", ty.print(cx.cache()));
+ }
+ w.write_str(")");
+ }
+ w.write_str("
");
+ document(w, cx, variant, Some(it));
+ document_non_exhaustive(w, variant);
+
+ use crate::clean::Variant;
+ if let clean::VariantItem(Variant::Struct(ref s)) = *variant.kind {
+ let variant_id = cx.derive_id(format!(
+ "{}.{}.fields",
+ ItemType::Variant,
+ variant.name.as_ref().unwrap()
+ ));
+ write!(w, "", id = variant_id);
+ write!(
+ w,
+ "
Fields of {name}
",
+ name = variant.name.as_ref().unwrap()
+ );
+ for field in &s.fields {
+ use crate::clean::StructFieldItem;
+ if let StructFieldItem(ref ty) = *field.kind {
+ let id = cx.derive_id(format!(
+ "variant.{}.field.{}",
+ variant.name.as_ref().unwrap(),
+ field.name.as_ref().unwrap()
+ ));
+ write!(
+ w,
+ "
\
+ \
+ {f}: {t}
\
+ ",
+ id = id,
+ f = field.name.as_ref().unwrap(),
+ t = ty.print(cx.cache())
+ );
+ document(w, cx, field, Some(variant));
+ }
+ }
+ w.write_str("
");
+ }
+ render_stability_since(w, variant, it, cx.tcx());
+ }
+ }
+ render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+}
+
+fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) {
+ wrap_into_docblock(w, |w| {
+ highlight::render_with_highlighting(
+ &t.source,
+ w,
+ Some("macro"),
+ None,
+ None,
+ it.source.span().edition(),
+ );
+ });
+ document(w, cx, it, None)
+}
+
+fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) {
+ let name = it.name.as_ref().expect("proc-macros always have names");
+ match m.kind {
+ MacroKind::Bang => {
+ w.push_str("");
+ write!(w, "{}!() {{ /* proc-macro */ }}", name);
+ w.push_str("
");
+ }
+ MacroKind::Attr => {
+ w.push_str("");
+ write!(w, "#[{}]", name);
+ w.push_str("
");
+ }
+ MacroKind::Derive => {
+ w.push_str("");
+ write!(w, "#[derive({})]", name);
+ if !m.helpers.is_empty() {
+ w.push_str("\n{\n");
+ w.push_str(" // Attributes available to this derive:\n");
+ for attr in &m.helpers {
+ writeln!(w, " #[{}]", attr);
+ }
+ w.push_str("}\n");
+ }
+ w.push_str("
");
+ }
+ }
+ document(w, cx, it, None)
+}
+
+fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
+ document(w, cx, it, None);
+ render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+}
+
+fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) {
+ w.write_str("");
+ render_attributes(w, it, false);
+
+ write!(
+ w,
+ "{vis}const {name}: {typ}",
+ vis = it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
+ name = it.name.as_ref().unwrap(),
+ typ = c.type_.print(cx.cache()),
+ );
+
+ if c.value.is_some() || c.is_literal {
+ write!(w, " = {expr};", expr = Escape(&c.expr));
+ } else {
+ w.write_str(";");
+ }
+
+ if let Some(value) = &c.value {
+ if !c.is_literal {
+ let value_lowercase = value.to_lowercase();
+ let expr_lowercase = c.expr.to_lowercase();
+
+ if value_lowercase != expr_lowercase
+ && value_lowercase.trim_end_matches("i32") != expr_lowercase
+ {
+ write!(w, " // {value}", value = Escape(value));
+ }
+ }
+ }
+
+ w.write_str("
");
+ document(w, cx, it, None)
+}
+
+fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
+ wrap_into_docblock(w, |w| {
+ w.write_str("");
+ render_attributes(w, it, true);
+ render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true, cx);
+ w.write_str("
")
+ });
+
+ document(w, cx, it, None);
+ let mut fields = s
+ .fields
+ .iter()
+ .filter_map(|f| match *f.kind {
+ clean::StructFieldItem(ref ty) => Some((f, ty)),
+ _ => None,
+ })
+ .peekable();
+ if let CtorKind::Fictive = s.struct_type {
+ if fields.peek().is_some() {
+ write!(
+ w,
+ "
+ Fields{}
",
+ document_non_exhaustive_header(it)
+ );
+ document_non_exhaustive(w, it);
+ for (field, ty) in fields {
+ let id = cx.derive_id(format!(
+ "{}.{}",
+ ItemType::StructField,
+ field.name.as_ref().unwrap()
+ ));
+ write!(
+ w,
+ "\
+ \
+ {name}: {ty}
\
+ ",
+ item_type = ItemType::StructField,
+ id = id,
+ name = field.name.as_ref().unwrap(),
+ ty = ty.print(cx.cache())
+ );
+ document(w, cx, field, Some(it));
+ }
+ }
+ }
+ render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+}
+
+fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) {
+ w.write_str("");
+ render_attributes(w, it, false);
+ write!(
+ w,
+ "{vis}static {mutability}{name}: {typ}
",
+ vis = it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
+ mutability = s.mutability.print_with_space(),
+ name = it.name.as_ref().unwrap(),
+ typ = s.type_.print(cx.cache())
+ );
+ document(w, cx, it, None)
+}
+
+fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
+ w.write_str("extern {\n");
+ render_attributes(w, it, false);
+ write!(
+ w,
+ " {}type {};\n}}
",
+ it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
+ it.name.as_ref().unwrap(),
+ );
+
+ document(w, cx, it, None);
+
+ render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+}
+
+fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
+ document(w, cx, it, None)
+}
+
+/// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order).
+crate fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering {
+ /// Takes a non-numeric and a numeric part from the given &str.
+ fn take_parts<'a>(s: &mut &'a str) -> (&'a str, &'a str) {
+ let i = s.find(|c: char| c.is_ascii_digit());
+ let (a, b) = s.split_at(i.unwrap_or(s.len()));
+ let i = b.find(|c: char| !c.is_ascii_digit());
+ let (b, c) = b.split_at(i.unwrap_or(b.len()));
+ *s = c;
+ (a, b)
+ }
+
+ while !lhs.is_empty() || !rhs.is_empty() {
+ let (la, lb) = take_parts(&mut lhs);
+ let (ra, rb) = take_parts(&mut rhs);
+ // First process the non-numeric part.
+ match la.cmp(ra) {
+ Ordering::Equal => (),
+ x => return x,
+ }
+ // Then process the numeric part, if both sides have one (and they fit in a u64).
+ if let (Ok(ln), Ok(rn)) = (lb.parse::(), rb.parse::()) {
+ match ln.cmp(&rn) {
+ Ordering::Equal => (),
+ x => return x,
+ }
+ }
+ // Then process the numeric part again, but this time as strings.
+ match lb.cmp(rb) {
+ Ordering::Equal => (),
+ x => return x,
+ }
+ }
+
+ Ordering::Equal
+}
+
+pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String {
+ let mut s = cx.current.join("::");
+ s.push_str("::");
+ s.push_str(&item.name.unwrap().as_str());
+ s
+}
+
+pub(super) fn item_path(ty: ItemType, name: &str) -> String {
+ match ty {
+ ItemType::Module => format!("{}index.html", ensure_trailing_slash(name)),
+ _ => format!("{}.{}.html", ty, name),
+ }
+}
+
+fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cache: &Cache) -> String {
+ let mut bounds = String::new();
+ if !t_bounds.is_empty() {
+ if !trait_alias {
+ bounds.push_str(": ");
+ }
+ for (i, p) in t_bounds.iter().enumerate() {
+ if i > 0 {
+ bounds.push_str(" + ");
+ }
+ bounds.push_str(&p.print(cache).to_string());
+ }
+ }
+ bounds
+}
+
+fn wrap_into_docblock(w: &mut Buffer, f: F)
+where
+ F: FnOnce(&mut Buffer),
+{
+ w.write_str("");
+ f(w);
+ w.write_str("
")
+}
+
+fn render_stability_since(
+ w: &mut Buffer,
+ item: &clean::Item,
+ containing_item: &clean::Item,
+ tcx: TyCtxt<'_>,
+) {
+ render_stability_since_raw(
+ w,
+ item.stable_since(tcx).as_deref(),
+ item.const_stable_since(tcx).as_deref(),
+ containing_item.stable_since(tcx).as_deref(),
+ containing_item.const_stable_since(tcx).as_deref(),
+ )
+}
+
+fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cache: &Cache) -> Ordering {
+ let lhs = format!("{}", lhs.inner_impl().print(cache, false));
+ let rhs = format!("{}", rhs.inner_impl().print(cache, false));
+
+ // lhs and rhs are formatted as HTML, which may be unnecessary
+ compare_names(&lhs, &rhs)
+}
+
+fn render_implementor(
+ cx: &Context<'_>,
+ implementor: &Impl,
+ trait_: &clean::Item,
+ w: &mut Buffer,
+ implementor_dups: &FxHashMap,
+ aliases: &[String],
+) {
+ // If there's already another implementor that has the same abbridged name, use the
+ // full path, for example in `std::iter::ExactSizeIterator`
+ let use_absolute = match implementor.inner_impl().for_ {
+ clean::ResolvedPath { ref path, is_generic: false, .. }
+ | clean::BorrowedRef {
+ type_: box clean::ResolvedPath { ref path, is_generic: false, .. },
+ ..
+ } => implementor_dups[&path.last()].1,
+ _ => false,
+ };
+ render_impl(
+ w,
+ cx,
+ implementor,
+ trait_,
+ AssocItemLink::Anchor(None),
+ RenderMode::Normal,
+ trait_.stable_since(cx.tcx()).as_deref(),
+ trait_.const_stable_since(cx.tcx()).as_deref(),
+ false,
+ Some(use_absolute),
+ false,
+ false,
+ aliases,
+ );
+}
+
+fn render_union(
+ w: &mut Buffer,
+ it: &clean::Item,
+ g: Option<&clean::Generics>,
+ fields: &[clean::Item],
+ tab: &str,
+ structhead: bool,
+ cx: &Context<'_>,
+) {
+ write!(
+ w,
+ "{}{}{}",
+ it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
+ if structhead { "union " } else { "" },
+ it.name.as_ref().unwrap()
+ );
+ if let Some(g) = g {
+ write!(w, "{}", g.print(cx.cache()));
+ write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true }.print(cx.cache()));
+ }
+
+ write!(w, " {{\n{}", tab);
+ for field in fields {
+ if let clean::StructFieldItem(ref ty) = *field.kind {
+ write!(
+ w,
+ " {}{}: {},\n{}",
+ field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()),
+ field.name.as_ref().unwrap(),
+ ty.print(cx.cache()),
+ tab
+ );
+ }
+ }
+
+ if it.has_stripped_fields().unwrap() {
+ write!(w, " // some fields omitted\n{}", tab);
+ }
+ w.write_str("}");
+}
+
+fn render_struct(
+ w: &mut Buffer,
+ it: &clean::Item,
+ g: Option<&clean::Generics>,
+ ty: CtorKind,
+ fields: &[clean::Item],
+ tab: &str,
+ structhead: bool,
+ cx: &Context<'_>,
+) {
+ write!(
+ w,
+ "{}{}{}",
+ it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()),
+ if structhead { "struct " } else { "" },
+ it.name.as_ref().unwrap()
+ );
+ if let Some(g) = g {
+ write!(w, "{}", g.print(cx.cache()))
+ }
+ match ty {
+ CtorKind::Fictive => {
+ if let Some(g) = g {
+ write!(
+ w,
+ "{}",
+ WhereClause { gens: g, indent: 0, end_newline: true }.print(cx.cache())
+ )
+ }
+ let mut has_visible_fields = false;
+ w.write_str(" {");
+ for field in fields {
+ if let clean::StructFieldItem(ref ty) = *field.kind {
+ write!(
+ w,
+ "\n{} {}{}: {},",
+ tab,
+ field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()),
+ field.name.as_ref().unwrap(),
+ ty.print(cx.cache())
+ );
+ has_visible_fields = true;
+ }
+ }
+
+ if has_visible_fields {
+ if it.has_stripped_fields().unwrap() {
+ write!(w, "\n{} // some fields omitted", tab);
+ }
+ write!(w, "\n{}", tab);
+ } else if it.has_stripped_fields().unwrap() {
+ // If there are no visible fields we can just display
+ // `{ /* fields omitted */ }` to save space.
+ write!(w, " /* fields omitted */ ");
+ }
+ w.write_str("}");
+ }
+ CtorKind::Fn => {
+ w.write_str("(");
+ for (i, field) in fields.iter().enumerate() {
+ if i > 0 {
+ w.write_str(", ");
+ }
+ match *field.kind {
+ clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"),
+ clean::StructFieldItem(ref ty) => {
+ write!(
+ w,
+ "{}{}",
+ field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()),
+ ty.print(cx.cache())
+ )
+ }
+ _ => unreachable!(),
+ }
+ }
+ w.write_str(")");
+ if let Some(g) = g {
+ write!(
+ w,
+ "{}",
+ WhereClause { gens: g, indent: 0, end_newline: false }.print(cx.cache())
+ )
+ }
+ w.write_str(";");
+ }
+ CtorKind::Const => {
+ // Needed for PhantomData.
+ if let Some(g) = g {
+ write!(
+ w,
+ "{}",
+ WhereClause { gens: g, indent: 0, end_newline: false }.print(cx.cache())
+ )
+ }
+ w.write_str(";");
+ }
+ }
+}
+
+fn document_non_exhaustive_header(item: &clean::Item) -> &str {
+ if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" }
+}
+
+fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
+ if item.is_non_exhaustive() {
+ write!(w, "", {
+ if item.is_struct() {
+ "struct"
+ } else if item.is_enum() {
+ "enum"
+ } else if item.is_variant() {
+ "variant"
+ } else {
+ "type"
+ }
+ });
+
+ if item.is_struct() {
+ w.write_str(
+ "Non-exhaustive structs could have additional fields added in future. \
+ Therefore, non-exhaustive structs cannot be constructed in external crates \
+ using the traditional Struct {{ .. }}
syntax; cannot be \
+ matched against without a wildcard ..
; and \
+ struct update syntax will not work.",
+ );
+ } else if item.is_enum() {
+ w.write_str(
+ "Non-exhaustive enums could have additional variants added in future. \
+ Therefore, when matching against variants of non-exhaustive enums, an \
+ extra wildcard arm must be added to account for any future variants.",
+ );
+ } else if item.is_variant() {
+ w.write_str(
+ "Non-exhaustive enum variants could have additional fields added in future. \
+ Therefore, non-exhaustive enum variants cannot be constructed in external \
+ crates and cannot be matched against.",
+ );
+ } else {
+ w.write_str(
+ "This type will require a wildcard arm in any match statements or constructors.",
+ );
+ }
+
+ w.write_str("
");
+ }
+}