2019-02-08 14:53:55 +01:00
|
|
|
//! Rustdoc's HTML rendering module.
|
2013-10-03 10:24:40 -07:00
|
|
|
//!
|
|
|
|
//! This modules contains the bulk of the logic necessary for rendering a
|
|
|
|
//! rustdoc `clean::Crate` instance to a set of static HTML pages. This
|
|
|
|
//! rendering process is largely driven by the `format!` syntax extension to
|
|
|
|
//! perform all I/O into files and streams.
|
|
|
|
//!
|
|
|
|
//! The rendering process is largely driven by the `Context` and `Cache`
|
|
|
|
//! structures. The cache is pre-populated by crawling the crate in question,
|
2015-05-09 00:12:29 +09:00
|
|
|
//! and then it is shared among the various rendering threads. The cache is meant
|
2013-10-03 10:24:40 -07:00
|
|
|
//! to be a fairly large structure not implementing `Clone` (because it's shared
|
2015-05-09 00:12:29 +09:00
|
|
|
//! among threads). The context, however, should be a lightweight structure. This
|
|
|
|
//! is cloned per-thread and contains information about what is currently being
|
2013-10-03 10:24:40 -07:00
|
|
|
//! rendered.
|
|
|
|
//!
|
|
|
|
//! In order to speed up rendering (mostly because of markdown rendering), the
|
|
|
|
//! rendering process has been parallelized. This parallelization is only
|
|
|
|
//! exposed through the `crate` method on the context, and then also from the
|
|
|
|
//! fact that the shared cache is stored in TLS (and must be accessed as such).
|
|
|
|
//!
|
|
|
|
//! In addition to rendering the crate itself, this module is also responsible
|
|
|
|
//! for creating the corresponding search index and source file renderings.
|
2015-05-09 00:12:29 +09:00
|
|
|
//! These threads are not parallelized (they haven't been a bottleneck yet), and
|
2013-10-03 10:24:40 -07:00
|
|
|
//! both occur before the crate is rendered.
|
2018-02-24 19:14:36 +01:00
|
|
|
|
2020-11-14 17:59:58 -05:00
|
|
|
crate mod cache;
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
2021-02-13 21:28:34 -08:00
|
|
|
mod context;
|
2021-02-13 22:23:05 -08:00
|
|
|
mod print_item;
|
2021-04-06 00:07:46 +02:00
|
|
|
mod span_map;
|
2021-02-13 23:17:38 -08:00
|
|
|
mod write_shared;
|
|
|
|
|
|
|
|
crate use context::*;
|
2021-08-02 17:44:04 +02:00
|
|
|
crate use span_map::{collect_spans_and_sources, LinkFromSrc};
|
2021-02-13 22:23:05 -08:00
|
|
|
|
2021-02-13 21:28:34 -08:00
|
|
|
use std::collections::VecDeque;
|
2014-11-14 14:20:57 -08:00
|
|
|
use std::default::Default;
|
2021-02-13 23:17:38 -08:00
|
|
|
use std::fmt;
|
2021-05-09 16:22:22 -07:00
|
|
|
use std::fs;
|
2021-09-13 18:08:14 -07:00
|
|
|
use std::iter::Peekable;
|
2021-04-02 12:08:28 -07:00
|
|
|
use std::path::PathBuf;
|
2014-04-02 16:54:22 -07:00
|
|
|
use std::str;
|
2020-05-04 23:36:22 +02:00
|
|
|
use std::string::ToString;
|
2013-09-18 22:18:38 -07:00
|
|
|
|
2020-01-11 17:02:46 +01:00
|
|
|
use rustc_ast_pretty::pprust;
|
2021-06-20 08:13:23 +08:00
|
|
|
use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
|
2021-08-26 14:43:12 -07:00
|
|
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir as hir;
|
2021-01-20 17:19:46 -05:00
|
|
|
use rustc_hir::def::CtorKind;
|
2021-02-13 21:28:34 -08:00
|
|
|
use rustc_hir::def_id::DefId;
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir::Mutability;
|
2020-03-29 17:19:48 +02:00
|
|
|
use rustc_middle::middle::stability;
|
2021-08-27 16:49:14 -07:00
|
|
|
use rustc_middle::ty::TyCtxt;
|
2021-09-13 18:08:14 -07:00
|
|
|
use rustc_span::{
|
|
|
|
symbol::{kw, sym, Symbol},
|
|
|
|
BytePos, FileName, RealFileName,
|
|
|
|
};
|
2019-12-22 17:42:04 -05:00
|
|
|
use serde::ser::SerializeSeq;
|
|
|
|
use serde::{Serialize, Serializer};
|
2013-09-18 22:18:38 -07:00
|
|
|
|
2021-06-26 13:52:31 +02:00
|
|
|
use crate::clean::{self, GetDefId, ItemId, RenderedLink, SelfTy};
|
2021-04-02 12:08:28 -07:00
|
|
|
use crate::docfs::PathError;
|
2020-06-15 13:42:29 -05:00
|
|
|
use crate::error::Error;
|
2021-01-12 23:36:04 +01:00
|
|
|
use crate::formats::cache::Cache;
|
2020-06-24 08:16:21 -05:00
|
|
|
use crate::formats::item_type::ItemType;
|
2021-03-17 11:41:01 -07:00
|
|
|
use crate::formats::{AssocItemRender, Impl, RenderMode};
|
2019-02-23 16:40:07 +09:00
|
|
|
use crate::html::escape::Escape;
|
2021-02-13 22:23:05 -08:00
|
|
|
use crate::html::format::{
|
2021-06-20 08:39:54 +08:00
|
|
|
href, print_abi_with_space, print_constness_with_space, print_default_space,
|
2021-06-27 11:10:36 +02:00
|
|
|
print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace,
|
2021-02-13 22:23:05 -08:00
|
|
|
};
|
2021-09-16 18:12:45 -07:00
|
|
|
use crate::html::highlight;
|
2021-10-06 21:43:40 -07:00
|
|
|
use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
|
2021-05-09 16:22:22 -07:00
|
|
|
use crate::html::sources;
|
2021-09-16 18:12:45 -07:00
|
|
|
use crate::scrape_examples::CallData;
|
2019-09-13 11:22:12 -04:00
|
|
|
|
2014-12-23 09:58:38 +08:00
|
|
|
/// A pair of name and its optional document.
|
2020-11-14 17:59:58 -05:00
|
|
|
crate type NameDoc = (String, Option<String>);
|
2014-12-23 09:58:38 +08:00
|
|
|
|
2019-09-13 09:26:11 -04:00
|
|
|
crate fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
|
|
|
|
crate::html::format::display_fn(move |f| {
|
2021-01-30 01:02:18 +00:00
|
|
|
if !v.ends_with('/') && !v.is_empty() { write!(f, "{}/", v) } else { f.write_str(v) }
|
2019-09-13 09:26:11 -04:00
|
|
|
})
|
2019-01-31 15:42:45 +01:00
|
|
|
}
|
|
|
|
|
2013-10-03 10:24:40 -07:00
|
|
|
// Helper structs for rendering items/sidebars and carrying along contextual
|
|
|
|
// information
|
|
|
|
|
|
|
|
/// Struct representing one entry in the JS search index. These are all emitted
|
|
|
|
/// by hand to a large JS file at the end of cache-creation.
|
2018-04-19 17:46:13 +02:00
|
|
|
#[derive(Debug)]
|
2020-11-14 17:59:58 -05:00
|
|
|
crate struct IndexItem {
|
|
|
|
crate ty: ItemType,
|
|
|
|
crate name: String,
|
|
|
|
crate path: String,
|
|
|
|
crate desc: String,
|
2021-05-08 10:04:03 +02:00
|
|
|
crate parent: Option<DefId>,
|
2020-11-14 17:59:58 -05:00
|
|
|
crate parent_idx: Option<usize>,
|
|
|
|
crate search_type: Option<IndexItemFunctionType>,
|
2021-04-03 19:08:14 -07:00
|
|
|
crate aliases: Box<[String]>,
|
2015-02-26 01:03:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// A type used for the search index.
|
2018-04-19 17:46:13 +02:00
|
|
|
#[derive(Debug)]
|
2020-07-27 17:34:17 -05:00
|
|
|
crate struct RenderType {
|
2015-02-26 01:03:06 +02:00
|
|
|
name: Option<String>,
|
2021-06-26 12:00:26 -07:00
|
|
|
generics: Option<Vec<String>>,
|
2020-02-23 02:38:33 +01:00
|
|
|
}
|
|
|
|
|
2015-02-26 01:03:06 +02:00
|
|
|
/// Full type of functions/methods in the search index.
|
2018-04-19 17:46:13 +02:00
|
|
|
#[derive(Debug)]
|
2020-11-14 17:59:58 -05:00
|
|
|
crate struct IndexItemFunctionType {
|
2020-02-23 02:38:33 +01:00
|
|
|
inputs: Vec<TypeWithKind>,
|
|
|
|
output: Option<Vec<TypeWithKind>>,
|
2015-02-26 01:03:06 +02:00
|
|
|
}
|
|
|
|
|
2019-06-29 13:30:45 -04:00
|
|
|
impl Serialize for IndexItemFunctionType {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
2015-02-26 01:03:06 +02:00
|
|
|
// If we couldn't figure out a type, just write `null`.
|
2019-03-07 22:47:43 +01:00
|
|
|
let mut iter = self.inputs.iter();
|
|
|
|
if match self.output {
|
2020-02-23 02:38:33 +01:00
|
|
|
Some(ref output) => iter.chain(output.iter()).any(|ref i| i.ty.name.is_none()),
|
|
|
|
None => iter.any(|ref i| i.ty.name.is_none()),
|
2019-03-07 22:47:43 +01:00
|
|
|
} {
|
2019-06-29 13:30:45 -04:00
|
|
|
serializer.serialize_none()
|
2016-02-16 19:48:28 +01:00
|
|
|
} else {
|
2019-06-29 13:30:45 -04:00
|
|
|
let mut seq = serializer.serialize_seq(None)?;
|
|
|
|
seq.serialize_element(&self.inputs)?;
|
|
|
|
if let Some(output) = &self.output {
|
2019-03-07 22:47:43 +01:00
|
|
|
if output.len() > 1 {
|
2019-06-29 13:30:45 -04:00
|
|
|
seq.serialize_element(&output)?;
|
2019-03-07 22:47:43 +01:00
|
|
|
} else {
|
2019-06-29 13:30:45 -04:00
|
|
|
seq.serialize_element(&output[0])?;
|
2019-03-07 22:47:43 +01:00
|
|
|
}
|
2018-05-05 17:06:08 +02:00
|
|
|
}
|
2019-06-29 13:30:45 -04:00
|
|
|
seq.end()
|
2015-02-26 01:03:06 +02:00
|
|
|
}
|
|
|
|
}
|
2013-09-18 22:18:38 -07:00
|
|
|
}
|
|
|
|
|
2020-02-23 02:38:33 +01:00
|
|
|
#[derive(Debug)]
|
2020-07-27 17:34:17 -05:00
|
|
|
crate struct TypeWithKind {
|
2020-03-03 15:53:16 +01:00
|
|
|
ty: RenderType,
|
2021-04-22 21:27:19 -04:00
|
|
|
kind: ItemType,
|
2020-02-23 02:38:33 +01:00
|
|
|
}
|
|
|
|
|
2021-04-22 21:27:19 -04:00
|
|
|
impl From<(RenderType, ItemType)> for TypeWithKind {
|
|
|
|
fn from(x: (RenderType, ItemType)) -> TypeWithKind {
|
2020-02-23 19:09:00 +01:00
|
|
|
TypeWithKind { ty: x.0, kind: x.1 }
|
2020-02-23 02:38:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serialize for TypeWithKind {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
2021-06-26 12:00:26 -07:00
|
|
|
let mut seq = serializer.serialize_seq(None)?;
|
|
|
|
seq.serialize_element(&self.ty.name)?;
|
|
|
|
seq.serialize_element(&self.kind)?;
|
|
|
|
if let Some(generics) = &self.ty.generics {
|
|
|
|
seq.serialize_element(generics)?;
|
|
|
|
}
|
|
|
|
seq.end()
|
2020-02-23 02:38:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-12 14:37:22 -04:00
|
|
|
#[derive(Debug, Clone)]
|
2020-11-14 17:59:58 -05:00
|
|
|
crate struct StylePath {
|
2020-07-12 14:37:22 -04:00
|
|
|
/// The path to the theme
|
2020-11-14 17:59:58 -05:00
|
|
|
crate path: PathBuf,
|
2020-07-12 14:37:22 -04:00
|
|
|
/// What the `disabled` attribute should be set to in the HTML tag
|
2020-11-14 17:59:58 -05:00
|
|
|
crate disabled: bool,
|
2020-07-12 14:37:22 -04:00
|
|
|
}
|
|
|
|
|
2021-01-12 23:36:04 +01:00
|
|
|
fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
|
|
|
|
if let Some(l) = cx.src_href(item) {
|
2021-01-30 01:02:18 +00:00
|
|
|
write!(buf, "<a class=\"srclink\" href=\"{}\" title=\"goto source code\">[src]</a>", l)
|
2020-11-18 12:48:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-30 11:19:49 +02:00
|
|
|
#[derive(Debug, Eq, PartialEq, Hash)]
|
|
|
|
struct ItemEntry {
|
|
|
|
url: String,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ItemEntry {
|
|
|
|
fn new(mut url: String, name: String) -> ItemEntry {
|
|
|
|
while url.starts_with('/') {
|
|
|
|
url.remove(0);
|
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
ItemEntry { url, name }
|
2018-03-30 11:19:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-12 19:59:14 -04:00
|
|
|
impl ItemEntry {
|
|
|
|
crate fn print(&self) -> impl fmt::Display + '_ {
|
|
|
|
crate::html::format::display_fn(move |f| {
|
2020-10-16 00:52:49 +08:00
|
|
|
write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name))
|
2019-09-12 19:59:14 -04:00
|
|
|
})
|
2018-03-30 11:19:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialOrd for ItemEntry {
|
|
|
|
fn partial_cmp(&self, other: &ItemEntry) -> Option<::std::cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Ord for ItemEntry {
|
|
|
|
fn cmp(&self, other: &ItemEntry) -> ::std::cmp::Ordering {
|
|
|
|
self.name.cmp(&other.name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct AllTypes {
|
2018-08-18 13:55:43 +03:00
|
|
|
structs: FxHashSet<ItemEntry>,
|
|
|
|
enums: FxHashSet<ItemEntry>,
|
|
|
|
unions: FxHashSet<ItemEntry>,
|
|
|
|
primitives: FxHashSet<ItemEntry>,
|
|
|
|
traits: FxHashSet<ItemEntry>,
|
|
|
|
macros: FxHashSet<ItemEntry>,
|
|
|
|
functions: FxHashSet<ItemEntry>,
|
|
|
|
typedefs: FxHashSet<ItemEntry>,
|
2019-08-01 00:41:54 +01:00
|
|
|
opaque_tys: FxHashSet<ItemEntry>,
|
2018-08-18 13:55:43 +03:00
|
|
|
statics: FxHashSet<ItemEntry>,
|
|
|
|
constants: FxHashSet<ItemEntry>,
|
2018-09-27 09:04:38 -05:00
|
|
|
attributes: FxHashSet<ItemEntry>,
|
|
|
|
derives: FxHashSet<ItemEntry>,
|
2019-02-05 14:27:09 +01:00
|
|
|
trait_aliases: FxHashSet<ItemEntry>,
|
2018-03-30 11:19:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AllTypes {
|
|
|
|
fn new() -> AllTypes {
|
2018-08-18 13:55:43 +03:00
|
|
|
let new_set = |cap| FxHashSet::with_capacity_and_hasher(cap, Default::default());
|
2018-03-30 11:19:49 +02:00
|
|
|
AllTypes {
|
2018-08-18 13:55:43 +03:00
|
|
|
structs: new_set(100),
|
|
|
|
enums: new_set(100),
|
|
|
|
unions: new_set(100),
|
|
|
|
primitives: new_set(26),
|
|
|
|
traits: new_set(100),
|
|
|
|
macros: new_set(100),
|
|
|
|
functions: new_set(100),
|
|
|
|
typedefs: new_set(100),
|
2019-08-01 00:41:54 +01:00
|
|
|
opaque_tys: new_set(100),
|
2018-08-18 13:55:43 +03:00
|
|
|
statics: new_set(100),
|
|
|
|
constants: new_set(100),
|
2018-09-27 09:04:38 -05:00
|
|
|
attributes: new_set(100),
|
|
|
|
derives: new_set(100),
|
2019-02-05 14:27:09 +01:00
|
|
|
trait_aliases: new_set(100),
|
2018-03-30 11:19:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-07 13:10:49 +02:00
|
|
|
fn append(&mut self, item_name: String, item_type: &ItemType) {
|
2018-03-30 11:19:49 +02:00
|
|
|
let mut url: Vec<_> = item_name.split("::").skip(1).collect();
|
|
|
|
if let Some(name) = url.pop() {
|
|
|
|
let new_url = format!("{}/{}.{}.html", url.join("/"), item_type, name);
|
|
|
|
url.push(name);
|
|
|
|
let name = url.join("::");
|
2018-04-07 13:10:49 +02:00
|
|
|
match *item_type {
|
|
|
|
ItemType::Struct => self.structs.insert(ItemEntry::new(new_url, name)),
|
|
|
|
ItemType::Enum => self.enums.insert(ItemEntry::new(new_url, name)),
|
|
|
|
ItemType::Union => self.unions.insert(ItemEntry::new(new_url, name)),
|
|
|
|
ItemType::Primitive => self.primitives.insert(ItemEntry::new(new_url, name)),
|
|
|
|
ItemType::Trait => self.traits.insert(ItemEntry::new(new_url, name)),
|
|
|
|
ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)),
|
|
|
|
ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)),
|
|
|
|
ItemType::Typedef => self.typedefs.insert(ItemEntry::new(new_url, name)),
|
2019-08-01 00:41:54 +01:00
|
|
|
ItemType::OpaqueTy => self.opaque_tys.insert(ItemEntry::new(new_url, name)),
|
2018-04-07 13:10:49 +02:00
|
|
|
ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
|
|
|
|
ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
|
2018-09-27 09:04:38 -05:00
|
|
|
ItemType::ProcAttribute => self.attributes.insert(ItemEntry::new(new_url, name)),
|
|
|
|
ItemType::ProcDerive => self.derives.insert(ItemEntry::new(new_url, name)),
|
2019-02-05 14:27:09 +01:00
|
|
|
ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
|
2018-03-30 11:19:49 +02:00
|
|
|
_ => true,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-31 12:31:55 -04:00
|
|
|
impl AllTypes {
|
|
|
|
fn print(self, f: &mut Buffer) {
|
2021-01-30 01:02:18 +00:00
|
|
|
fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: &str) {
|
|
|
|
if !e.is_empty() {
|
|
|
|
let mut e: Vec<&ItemEntry> = e.iter().collect();
|
|
|
|
e.sort();
|
2021-06-03 20:16:47 +02:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">",
|
|
|
|
title.replace(' ', "-"), // IDs cannot contain whitespaces.
|
|
|
|
title,
|
|
|
|
class
|
|
|
|
);
|
2021-01-30 01:02:18 +00:00
|
|
|
|
|
|
|
for s in e.iter() {
|
|
|
|
write!(f, "<li>{}</li>", s.print());
|
|
|
|
}
|
|
|
|
|
|
|
|
f.write_str("</ul>");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f.write_str(
|
2020-10-16 00:52:49 +08:00
|
|
|
"<h1 class=\"fqn\">\
|
2021-01-28 04:42:27 +01:00
|
|
|
<span class=\"in-band\">List of all items</span>\
|
2020-10-16 00:52:49 +08:00
|
|
|
<span class=\"out-of-band\">\
|
|
|
|
<span id=\"render-detail\">\
|
2020-08-31 13:16:50 +02:00
|
|
|
<a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
|
|
|
|
title=\"collapse all docs\">\
|
2020-10-16 00:52:49 +08:00
|
|
|
[<span class=\"inner\">−</span>]\
|
2020-08-31 13:16:50 +02:00
|
|
|
</a>\
|
|
|
|
</span>
|
|
|
|
</span>
|
2021-01-30 01:02:18 +00:00
|
|
|
</h1>",
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2021-01-30 01:02:18 +00:00
|
|
|
// Note: print_entries does not escape the title, because we know the current set of titles
|
2021-06-03 20:16:47 +02:00
|
|
|
// doesn't require escaping.
|
2019-08-31 12:31:55 -04:00
|
|
|
print_entries(f, &self.structs, "Structs", "structs");
|
|
|
|
print_entries(f, &self.enums, "Enums", "enums");
|
|
|
|
print_entries(f, &self.unions, "Unions", "unions");
|
|
|
|
print_entries(f, &self.primitives, "Primitives", "primitives");
|
|
|
|
print_entries(f, &self.traits, "Traits", "traits");
|
|
|
|
print_entries(f, &self.macros, "Macros", "macros");
|
|
|
|
print_entries(f, &self.attributes, "Attribute Macros", "attributes");
|
|
|
|
print_entries(f, &self.derives, "Derive Macros", "derives");
|
|
|
|
print_entries(f, &self.functions, "Functions", "functions");
|
|
|
|
print_entries(f, &self.typedefs, "Typedefs", "typedefs");
|
|
|
|
print_entries(f, &self.trait_aliases, "Trait Aliases", "trait-aliases");
|
|
|
|
print_entries(f, &self.opaque_tys, "Opaque Types", "opaque-types");
|
|
|
|
print_entries(f, &self.statics, "Statics", "statics");
|
|
|
|
print_entries(f, &self.constants, "Constants", "constants")
|
|
|
|
}
|
2018-03-30 11:19:49 +02:00
|
|
|
}
|
|
|
|
|
2019-09-23 00:49:29 +02:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum Setting {
|
2020-10-11 02:53:37 +02:00
|
|
|
Section {
|
|
|
|
description: &'static str,
|
|
|
|
sub_settings: Vec<Setting>,
|
|
|
|
},
|
|
|
|
Toggle {
|
|
|
|
js_data_name: &'static str,
|
|
|
|
description: &'static str,
|
|
|
|
default_value: bool,
|
|
|
|
},
|
|
|
|
Select {
|
|
|
|
js_data_name: &'static str,
|
|
|
|
description: &'static str,
|
|
|
|
default_value: &'static str,
|
|
|
|
options: Vec<(String, String)>,
|
|
|
|
},
|
2019-09-23 00:49:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Setting {
|
2020-10-11 02:53:37 +02:00
|
|
|
fn display(&self, root_path: &str, suffix: &str) -> String {
|
2019-09-23 00:49:29 +02:00
|
|
|
match *self {
|
2020-10-11 17:47:34 +02:00
|
|
|
Setting::Section { description, ref sub_settings } => format!(
|
2020-10-16 00:52:49 +08:00
|
|
|
"<div class=\"setting-line\">\
|
|
|
|
<div class=\"title\">{}</div>\
|
|
|
|
<div class=\"sub-settings\">{}</div>
|
2020-08-31 13:16:50 +02:00
|
|
|
</div>",
|
2019-12-22 17:42:04 -05:00
|
|
|
description,
|
2020-10-11 02:53:37 +02:00
|
|
|
sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>()
|
2019-12-22 17:42:04 -05:00
|
|
|
),
|
2020-10-11 17:47:34 +02:00
|
|
|
Setting::Toggle { js_data_name, description, default_value } => format!(
|
2020-10-16 00:52:49 +08:00
|
|
|
"<div class=\"setting-line\">\
|
|
|
|
<label class=\"toggle\">\
|
|
|
|
<input type=\"checkbox\" id=\"{}\" {}>\
|
|
|
|
<span class=\"slider\"></span>\
|
2020-08-31 13:16:50 +02:00
|
|
|
</label>\
|
|
|
|
<div>{}</div>\
|
|
|
|
</div>",
|
2019-12-22 17:42:04 -05:00
|
|
|
js_data_name,
|
2020-10-11 17:47:34 +02:00
|
|
|
if default_value { " checked" } else { "" },
|
2019-12-22 17:42:04 -05:00
|
|
|
description,
|
|
|
|
),
|
2020-10-11 17:47:34 +02:00
|
|
|
Setting::Select { js_data_name, description, default_value, ref options } => format!(
|
2020-10-11 17:52:47 +02:00
|
|
|
"<div class=\"setting-line\">\
|
2020-10-11 02:53:37 +02:00
|
|
|
<div>{}</div>\
|
2020-10-11 17:52:47 +02:00
|
|
|
<label class=\"select-wrapper\">\
|
|
|
|
<select id=\"{}\" autocomplete=\"off\">{}</select>\
|
|
|
|
<img src=\"{}down-arrow{}.svg\" alt=\"Select item\">\
|
2020-10-11 02:53:37 +02:00
|
|
|
</label>\
|
|
|
|
</div>",
|
|
|
|
description,
|
|
|
|
js_data_name,
|
|
|
|
options
|
|
|
|
.iter()
|
|
|
|
.map(|opt| format!(
|
|
|
|
"<option value=\"{}\" {}>{}</option>",
|
|
|
|
opt.0,
|
2020-12-31 02:49:44 +01:00
|
|
|
if opt.0 == default_value { "selected" } else { "" },
|
2020-10-11 02:53:37 +02:00
|
|
|
opt.1,
|
|
|
|
))
|
|
|
|
.collect::<String>(),
|
|
|
|
root_path,
|
|
|
|
suffix,
|
|
|
|
),
|
2019-09-23 00:49:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<(&'static str, &'static str, bool)> for Setting {
|
|
|
|
fn from(values: (&'static str, &'static str, bool)) -> Setting {
|
2020-10-11 02:53:37 +02:00
|
|
|
Setting::Toggle { js_data_name: values.0, description: values.1, default_value: values.2 }
|
2019-09-23 00:49:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting {
|
|
|
|
fn from(values: (&'static str, Vec<T>)) -> Setting {
|
|
|
|
Setting::Section {
|
|
|
|
description: values.0,
|
|
|
|
sub_settings: values.1.into_iter().map(|v| v.into()).collect::<Vec<_>>(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 02:53:37 +02:00
|
|
|
fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<String, Error> {
|
|
|
|
let theme_names: Vec<(String, String)> = themes
|
|
|
|
.iter()
|
|
|
|
.map(|entry| {
|
|
|
|
let theme =
|
|
|
|
try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path)
|
|
|
|
.to_string();
|
|
|
|
|
|
|
|
Ok((theme.clone(), theme))
|
|
|
|
})
|
|
|
|
.collect::<Result<_, Error>>()?;
|
|
|
|
|
2018-04-13 22:54:09 +02:00
|
|
|
// (id, explanation, default value)
|
2019-09-23 00:49:29 +02:00
|
|
|
let settings: &[Setting] = &[
|
2020-10-11 02:53:37 +02:00
|
|
|
(
|
|
|
|
"Theme preferences",
|
|
|
|
vec![
|
|
|
|
Setting::from(("use-system-theme", "Use system theme", true)),
|
|
|
|
Setting::Select {
|
|
|
|
js_data_name: "preferred-dark-theme",
|
|
|
|
description: "Preferred dark theme",
|
|
|
|
default_value: "dark",
|
|
|
|
options: theme_names.clone(),
|
|
|
|
},
|
|
|
|
Setting::Select {
|
|
|
|
js_data_name: "preferred-light-theme",
|
|
|
|
description: "Preferred light theme",
|
|
|
|
default_value: "light",
|
|
|
|
options: theme_names,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
)
|
|
|
|
.into(),
|
2021-03-20 19:44:55 -07:00
|
|
|
("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
|
2019-09-23 00:49:29 +02:00
|
|
|
("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
|
2021-06-12 22:19:26 -07:00
|
|
|
("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", false)
|
2019-12-22 17:42:04 -05:00
|
|
|
.into(),
|
|
|
|
("go-to-only-result", "Directly go to item in search if there is only one result", false)
|
|
|
|
.into(),
|
2019-09-23 00:49:29 +02:00
|
|
|
("line-numbers", "Show line numbers on code examples", false).into(),
|
|
|
|
("disable-shortcuts", "Disable keyboard shortcuts", false).into(),
|
2019-08-31 12:27:27 -04:00
|
|
|
];
|
2020-10-11 02:53:37 +02:00
|
|
|
|
|
|
|
Ok(format!(
|
2020-10-16 00:52:49 +08:00
|
|
|
"<h1 class=\"fqn\">\
|
|
|
|
<span class=\"in-band\">Rustdoc settings</span>\
|
2020-10-11 02:53:37 +02:00
|
|
|
</h1>\
|
2020-10-16 00:52:49 +08:00
|
|
|
<div class=\"settings\">{}</div>\
|
|
|
|
<script src=\"{}settings{}.js\"></script>",
|
2020-10-11 02:53:37 +02:00
|
|
|
settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
|
2019-12-22 17:42:04 -05:00
|
|
|
root_path,
|
|
|
|
suffix
|
2020-10-11 02:53:37 +02:00
|
|
|
))
|
2018-04-13 22:54:09 +02:00
|
|
|
}
|
|
|
|
|
2021-10-04 21:28:26 -04:00
|
|
|
fn document(
|
2021-10-01 06:17:15 -04:00
|
|
|
w: &mut Buffer,
|
|
|
|
cx: &Context<'_>,
|
|
|
|
item: &clean::Item,
|
|
|
|
parent: Option<&clean::Item>,
|
2021-10-04 21:54:00 -04:00
|
|
|
heading_offset: HeadingOffset,
|
2021-10-01 06:17:15 -04:00
|
|
|
) {
|
2017-09-21 22:37:00 -05:00
|
|
|
if let Some(ref name) = item.name {
|
|
|
|
info!("Documenting {}", name);
|
|
|
|
}
|
2021-04-28 21:19:52 +02:00
|
|
|
document_item_info(w, cx, item, parent);
|
2021-05-13 23:09:24 -07:00
|
|
|
if parent.is_none() {
|
2021-10-04 21:54:00 -04:00
|
|
|
document_full_collapsible(w, item, cx, heading_offset);
|
2021-05-13 23:09:24 -07:00
|
|
|
} else {
|
2021-10-04 21:54:00 -04:00
|
|
|
document_full(w, item, cx, heading_offset);
|
2021-05-13 23:09:24 -07:00
|
|
|
}
|
2013-09-18 22:18:38 -07:00
|
|
|
}
|
|
|
|
|
Remove hoedown from rustdoc
Is it really time? Have our months, no, *years* of suffering come to an end? Are we finally able to cast off the pall of Hoedown? The weight which has dragged us down for so long?
-----
So, timeline for those who need to catch up:
* Way back in December 2016, [we decided we wanted to switch out the markdown renderer](https://github.com/rust-lang/rust/issues/38400). However, this was put on hold because the build system at the time made it difficult to pull in dependencies from crates.io.
* A few months later, in March 2017, [the first PR was done, to switch out the renderers entirely](https://github.com/rust-lang/rust/pull/40338). The PR itself was fraught with CI and build system issues, but eventually landed.
* However, not all was well in the Rustdoc world. During the PR and shortly after, we noticed [some differences in the way the two parsers handled some things](https://github.com/rust-lang/rust/issues/40912), and some of these differences were major enough to break the docs for some crates.
* A couple weeks afterward, [Hoedown was put back in](https://github.com/rust-lang/rust/pull/41290), at this point just to catch tests that Pulldown was "spuriously" running. This would at least provide some warning about spurious tests, rather than just breaking spontaneously.
* However, the problems had created enough noise by this point that just a few days after that, [Hoedown was switched back to the default](https://github.com/rust-lang/rust/pull/41431) while we came up with a solution for properly warning about the differences.
* That solution came a few weeks later, [as a series of warnings when the HTML emitted by the two parsers was semantically different](https://github.com/rust-lang/rust/pull/41991). But that came at a cost, as now rustdoc needed proc-macro support (the new crate needed some custom derives farther down its dependency tree), and the build system was not equipped to handle it at the time. It was worked on for three months as the issue stumped more and more people.
* In that time, [bootstrap was completely reworked](https://github.com/rust-lang/rust/pull/43059) to change how it ordered compilation, and [the method by which it built rustdoc would change](https://github.com/rust-lang/rust/pull/43482), as well. This allowed it to only be built after stage1, when proc-macros would be available, allowing the "rendering differences" PR to finally land.
* The warnings were not perfect, and revealed a few [spurious](https://github.com/rust-lang/rust/pull/44368) [differences](https://github.com/rust-lang/rust/pull/45421) between how we handled the renderers.
* Once these were handled, [we flipped the switch to turn on the "rendering difference" warnings all the time](https://github.com/rust-lang/rust/pull/45324), in October 2017. This began the "warning cycle" for this change, and landed in stable in 1.23, on 2018-01-04.
* Once those warnings hit stable, and after a couple weeks of seeing whether we would get any more reports than what we got from sitting on nightly/beta, [we switched the renderers](https://github.com/rust-lang/rust/pull/47398), making Pulldown the default but still offering the option to use Hoedown.
And that brings us to the present. We haven't received more new issues from this in the meantime, and the "switch by default" is now on beta. Our reasoning is that, at this point, anyone who would have been affected by this has run into it already.
2018-02-16 15:09:19 +01:00
|
|
|
/// Render md_text as markdown.
|
2021-10-01 06:17:15 -04:00
|
|
|
fn render_markdown(
|
|
|
|
w: &mut Buffer,
|
|
|
|
cx: &Context<'_>,
|
|
|
|
md_text: &str,
|
|
|
|
links: Vec<RenderedLink>,
|
2021-10-04 21:54:00 -04:00
|
|
|
heading_offset: HeadingOffset,
|
2021-10-01 06:17:15 -04:00
|
|
|
) {
|
2018-07-22 07:25:00 -06:00
|
|
|
let mut ids = cx.id_map.borrow_mut();
|
2019-12-22 17:42:04 -05:00
|
|
|
write!(
|
|
|
|
w,
|
2021-04-28 21:19:52 +02:00
|
|
|
"<div class=\"docblock\">{}</div>",
|
2021-10-04 21:08:58 -04:00
|
|
|
Markdown {
|
|
|
|
content: md_text,
|
|
|
|
links: &links,
|
|
|
|
ids: &mut ids,
|
|
|
|
error_codes: cx.shared.codes,
|
|
|
|
edition: cx.shared.edition(),
|
|
|
|
playground: &cx.shared.playground,
|
2021-10-04 21:54:00 -04:00
|
|
|
heading_offset,
|
2021-10-04 21:08:58 -04:00
|
|
|
}
|
2020-07-15 10:55:40 +00:00
|
|
|
.into_string()
|
2019-12-22 17:42:04 -05:00
|
|
|
)
|
2017-05-14 15:14:02 +02:00
|
|
|
}
|
|
|
|
|
2020-06-27 16:44:42 -04:00
|
|
|
/// Writes a documentation block containing only the first paragraph of the documentation. If the
|
|
|
|
/// docs are longer, a "Read more" link is appended to the end.
|
2019-02-23 17:02:57 +09:00
|
|
|
fn document_short(
|
2019-08-31 15:47:55 -04:00
|
|
|
w: &mut Buffer,
|
2019-02-23 17:02:57 +09:00
|
|
|
item: &clean::Item,
|
2020-12-16 14:34:08 -05:00
|
|
|
cx: &Context<'_>,
|
2019-02-23 17:02:57 +09:00
|
|
|
link: AssocItemLink<'_>,
|
2021-04-19 23:31:11 +02:00
|
|
|
parent: &clean::Item,
|
2020-11-24 17:36:16 +01:00
|
|
|
show_def_docs: bool,
|
2019-08-31 15:47:55 -04:00
|
|
|
) {
|
2021-04-28 21:19:52 +02:00
|
|
|
document_item_info(w, cx, item, Some(parent));
|
2020-11-24 17:36:16 +01:00
|
|
|
if !show_def_docs {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-17 06:50:39 +05:30
|
|
|
if let Some(s) = item.doc_value() {
|
2021-03-17 11:41:01 -07:00
|
|
|
let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string();
|
2020-06-27 16:44:42 -04:00
|
|
|
|
|
|
|
if s.contains('\n') {
|
2021-03-17 11:41:01 -07:00
|
|
|
let link = format!(r#" <a href="{}">Read more</a>"#, naive_assoc_href(item, link, cx));
|
2020-06-27 16:44:42 -04:00
|
|
|
|
|
|
|
if let Some(idx) = summary_html.rfind("</p>") {
|
|
|
|
summary_html.insert_str(idx, &link);
|
|
|
|
} else {
|
|
|
|
summary_html.push_str(&link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-28 21:19:52 +02:00
|
|
|
write!(w, "<div class='docblock'>{}</div>", summary_html,);
|
2016-05-17 06:50:39 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-04 21:54:00 -04:00
|
|
|
fn document_full_collapsible(
|
|
|
|
w: &mut Buffer,
|
|
|
|
item: &clean::Item,
|
|
|
|
cx: &Context<'_>,
|
|
|
|
heading_offset: HeadingOffset,
|
|
|
|
) {
|
|
|
|
document_full_inner(w, item, cx, true, heading_offset);
|
2021-05-08 14:21:57 +02:00
|
|
|
}
|
|
|
|
|
2021-10-04 21:54:00 -04:00
|
|
|
fn document_full(
|
|
|
|
w: &mut Buffer,
|
|
|
|
item: &clean::Item,
|
|
|
|
cx: &Context<'_>,
|
|
|
|
heading_offset: HeadingOffset,
|
|
|
|
) {
|
|
|
|
document_full_inner(w, item, cx, false, heading_offset);
|
2021-05-08 14:21:57 +02:00
|
|
|
}
|
|
|
|
|
2021-10-01 06:17:15 -04:00
|
|
|
fn document_full_inner(
|
|
|
|
w: &mut Buffer,
|
|
|
|
item: &clean::Item,
|
|
|
|
cx: &Context<'_>,
|
|
|
|
is_collapsible: bool,
|
2021-10-04 21:54:00 -04:00
|
|
|
heading_offset: HeadingOffset,
|
2021-10-01 06:17:15 -04:00
|
|
|
) {
|
2017-09-21 22:37:00 -05:00
|
|
|
if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
|
|
|
|
debug!("Doc block: =====\n{}\n=====", s);
|
2021-05-08 14:21:57 +02:00
|
|
|
if is_collapsible {
|
|
|
|
w.write_str(
|
|
|
|
"<details class=\"rustdoc-toggle top-doc\" open>\
|
|
|
|
<summary class=\"hideme\">\
|
|
|
|
<span>Expand description</span>\
|
|
|
|
</summary>",
|
|
|
|
);
|
2021-10-04 21:54:00 -04:00
|
|
|
render_markdown(w, cx, &s, item.links(cx), heading_offset);
|
2021-05-08 14:21:57 +02:00
|
|
|
w.write_str("</details>");
|
|
|
|
} else {
|
2021-10-04 21:54:00 -04:00
|
|
|
render_markdown(w, cx, &s, item.links(cx), heading_offset);
|
2021-05-08 14:21:57 +02:00
|
|
|
}
|
2016-06-15 23:55:11 +01:00
|
|
|
}
|
2021-05-09 16:22:22 -07:00
|
|
|
|
2021-09-16 18:12:45 -07:00
|
|
|
let kind = match &*item.kind {
|
|
|
|
clean::ItemKind::StrippedItem(box kind) | kind => kind,
|
|
|
|
};
|
|
|
|
|
|
|
|
match kind {
|
2021-05-09 16:22:22 -07:00
|
|
|
clean::ItemKind::FunctionItem(f) | clean::ItemKind::MethodItem(f, _) => {
|
2021-09-16 18:12:45 -07:00
|
|
|
render_call_locations(w, cx, f.def_id, item);
|
2021-05-09 16:22:22 -07:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2016-06-15 23:55:11 +01:00
|
|
|
}
|
|
|
|
|
2020-11-23 13:20:16 +01:00
|
|
|
/// Add extra information about an item such as:
|
|
|
|
///
|
|
|
|
/// * Stability
|
|
|
|
/// * Deprecated
|
|
|
|
/// * Required features (through the `doc_cfg` feature)
|
|
|
|
fn document_item_info(
|
2020-10-06 20:48:01 +02:00
|
|
|
w: &mut Buffer,
|
2020-12-16 14:34:08 -05:00
|
|
|
cx: &Context<'_>,
|
2020-10-06 20:48:01 +02:00
|
|
|
item: &clean::Item,
|
|
|
|
parent: Option<&clean::Item>,
|
|
|
|
) {
|
2020-11-23 13:20:16 +01:00
|
|
|
let item_infos = short_item_info(item, cx, parent);
|
|
|
|
if !item_infos.is_empty() {
|
2021-04-28 21:19:52 +02:00
|
|
|
w.write_str("<div class=\"item-info\">");
|
2020-11-23 13:20:16 +01:00
|
|
|
for info in item_infos {
|
2021-01-30 01:02:18 +00:00
|
|
|
w.write_str(&info);
|
2016-12-12 17:41:39 +00:00
|
|
|
}
|
2021-01-30 01:02:18 +00:00
|
|
|
w.write_str("</div>");
|
2016-06-15 23:55:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-02 19:17:33 +01:00
|
|
|
fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<String> {
|
2021-04-25 18:17:11 +02:00
|
|
|
let cfg = match (&item.cfg, parent.and_then(|p| p.cfg.as_ref())) {
|
2020-11-02 19:17:33 +01:00
|
|
|
(Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
|
|
|
|
(cfg, _) => cfg.as_deref().cloned(),
|
|
|
|
};
|
|
|
|
|
2021-04-25 18:17:11 +02:00
|
|
|
debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.and_then(|p| p.cfg.as_ref()), cfg);
|
2020-11-02 19:17:33 +01:00
|
|
|
|
|
|
|
Some(format!("<div class=\"stab portability\">{}</div>", cfg?.render_long_html()))
|
|
|
|
}
|
|
|
|
|
2020-11-23 13:20:16 +01:00
|
|
|
/// Render the stability, deprecation and portability information that is displayed at the top of
|
|
|
|
/// the item's documentation.
|
2020-12-16 14:34:08 -05:00
|
|
|
fn short_item_info(
|
|
|
|
item: &clean::Item,
|
|
|
|
cx: &Context<'_>,
|
|
|
|
parent: Option<&clean::Item>,
|
|
|
|
) -> Vec<String> {
|
2020-11-23 13:20:16 +01:00
|
|
|
let mut extra_info = vec![];
|
2019-09-13 14:59:08 -04:00
|
|
|
let error_codes = cx.shared.codes;
|
2016-04-22 23:26:08 -04:00
|
|
|
|
2021-09-30 15:15:10 +04:00
|
|
|
if let Some(depr @ Deprecation { note, since, is_since_rustc_version: _, suggestion: _ }) =
|
2020-12-16 15:54:05 -05:00
|
|
|
item.deprecation(cx.tcx())
|
2020-12-14 18:44:59 -05:00
|
|
|
{
|
2019-02-05 22:51:06 +01:00
|
|
|
// We display deprecation messages for #[deprecated] and #[rustc_deprecated]
|
|
|
|
// but only display the future-deprecation messages for #[rustc_deprecated].
|
2018-12-13 23:28:54 -05:00
|
|
|
let mut message = if let Some(since) = since {
|
2020-12-14 18:44:59 -05:00
|
|
|
let since = &since.as_str();
|
2021-09-30 15:15:10 +04:00
|
|
|
if !stability::deprecation_in_effect(&depr) {
|
2020-12-09 18:26:42 -05:00
|
|
|
if *since == "TBD" {
|
2020-12-31 02:49:44 +01:00
|
|
|
String::from("Deprecating in a future Rust version")
|
2020-12-09 18:26:42 -05:00
|
|
|
} else {
|
|
|
|
format!("Deprecating in {}", Escape(since))
|
|
|
|
}
|
2020-07-20 10:44:43 -04:00
|
|
|
} else {
|
2020-12-14 18:44:59 -05:00
|
|
|
format!("Deprecated since {}", Escape(since))
|
2020-07-20 10:44:43 -04:00
|
|
|
}
|
2015-04-13 11:55:00 -07:00
|
|
|
} else {
|
2018-12-13 23:28:54 -05:00
|
|
|
String::from("Deprecated")
|
2015-04-13 11:55:00 -07:00
|
|
|
};
|
2018-12-13 23:28:54 -05:00
|
|
|
|
|
|
|
if let Some(note) = note {
|
2020-12-14 18:44:59 -05:00
|
|
|
let note = note.as_str();
|
2018-07-22 07:25:00 -06:00
|
|
|
let mut ids = cx.id_map.borrow_mut();
|
2019-09-13 09:51:32 -04:00
|
|
|
let html = MarkdownHtml(
|
2019-12-22 17:42:04 -05:00
|
|
|
¬e,
|
|
|
|
&mut ids,
|
|
|
|
error_codes,
|
2021-04-22 19:38:20 -04:00
|
|
|
cx.shared.edition(),
|
2019-12-22 17:42:04 -05:00
|
|
|
&cx.shared.playground,
|
|
|
|
);
|
2020-07-15 10:55:40 +00:00
|
|
|
message.push_str(&format!(": {}", html.into_string()));
|
2018-12-13 23:28:54 -05:00
|
|
|
}
|
2020-11-23 13:20:16 +01:00
|
|
|
extra_info.push(format!(
|
2020-10-16 00:52:49 +08:00
|
|
|
"<div class=\"stab deprecated\"><span class=\"emoji\">👎</span> {}</div>",
|
2020-05-08 15:19:14 +02:00
|
|
|
message,
|
|
|
|
));
|
2018-12-13 23:28:54 -05:00
|
|
|
}
|
2016-04-22 23:26:08 -04:00
|
|
|
|
2020-07-15 04:13:25 +00:00
|
|
|
// Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
|
|
|
|
// Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
|
2020-10-11 09:55:17 -04:00
|
|
|
if let Some((StabilityLevel::Unstable { reason, issue, .. }, feature)) = item
|
2020-12-16 15:54:05 -05:00
|
|
|
.stability(cx.tcx())
|
2020-07-19 18:20:01 -04:00
|
|
|
.as_ref()
|
2020-10-11 09:55:17 -04:00
|
|
|
.filter(|stab| stab.feature != sym::rustc_private)
|
|
|
|
.map(|stab| (stab.level, stab.feature))
|
2020-07-19 18:20:01 -04:00
|
|
|
{
|
2020-07-15 04:13:25 +00:00
|
|
|
let mut message =
|
2020-10-16 00:52:49 +08:00
|
|
|
"<span class=\"emoji\">🔬</span> This is a nightly-only experimental API.".to_owned();
|
2018-12-13 23:28:54 -05:00
|
|
|
|
2020-10-11 09:55:17 -04:00
|
|
|
let mut feature = format!("<code>{}</code>", Escape(&feature.as_str()));
|
|
|
|
if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) {
|
2020-07-19 18:20:01 -04:00
|
|
|
feature.push_str(&format!(
|
|
|
|
" <a href=\"{url}{issue}\">#{issue}</a>",
|
|
|
|
url = url,
|
|
|
|
issue = issue
|
|
|
|
));
|
2018-12-13 23:28:54 -05:00
|
|
|
}
|
|
|
|
|
2020-07-19 18:20:01 -04:00
|
|
|
message.push_str(&format!(" ({})", feature));
|
|
|
|
|
2020-10-11 09:55:17 -04:00
|
|
|
if let Some(unstable_reason) = reason {
|
2018-12-13 23:28:54 -05:00
|
|
|
let mut ids = cx.id_map.borrow_mut();
|
|
|
|
message = format!(
|
|
|
|
"<details><summary>{}</summary>{}</details>",
|
|
|
|
message,
|
2019-08-10 18:07:07 -04:00
|
|
|
MarkdownHtml(
|
2020-10-11 09:55:17 -04:00
|
|
|
&unstable_reason.as_str(),
|
2019-08-10 18:36:04 -04:00
|
|
|
&mut ids,
|
2019-08-10 18:07:07 -04:00
|
|
|
error_codes,
|
2021-04-22 19:38:20 -04:00
|
|
|
cx.shared.edition(),
|
2019-09-13 10:40:22 -04:00
|
|
|
&cx.shared.playground,
|
2019-12-22 17:42:04 -05:00
|
|
|
)
|
2020-07-15 10:55:40 +00:00
|
|
|
.into_string()
|
2018-12-13 23:28:54 -05:00
|
|
|
);
|
|
|
|
}
|
2015-12-12 23:01:27 +03:00
|
|
|
|
2020-11-23 13:20:16 +01:00
|
|
|
extra_info.push(format!("<div class=\"stab unstable\">{}</div>", message));
|
2016-04-22 23:26:08 -04:00
|
|
|
}
|
|
|
|
|
2020-11-02 19:17:33 +01:00
|
|
|
if let Some(portability) = portability(item, parent) {
|
2020-11-23 13:20:16 +01:00
|
|
|
extra_info.push(portability);
|
2017-08-05 14:38:52 +08:00
|
|
|
}
|
|
|
|
|
2020-11-23 13:20:16 +01:00
|
|
|
extra_info
|
2015-04-13 11:55:00 -07:00
|
|
|
}
|
|
|
|
|
2021-06-16 22:48:23 -07:00
|
|
|
// Render the list of items inside one of the sections "Trait Implementations",
|
|
|
|
// "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
|
2020-06-24 08:16:21 -05:00
|
|
|
fn render_impls(
|
2020-12-16 14:34:08 -05:00
|
|
|
cx: &Context<'_>,
|
2020-06-24 08:16:21 -05:00
|
|
|
w: &mut Buffer,
|
|
|
|
traits: &[&&Impl],
|
|
|
|
containing_item: &clean::Item,
|
|
|
|
) {
|
2021-03-07 23:11:12 +01:00
|
|
|
let cache = cx.cache();
|
|
|
|
let tcx = cx.tcx();
|
2019-12-22 17:42:04 -05:00
|
|
|
let mut impls = traits
|
|
|
|
.iter()
|
2019-12-08 13:56:26 +01:00
|
|
|
.map(|i| {
|
2021-03-07 23:11:12 +01:00
|
|
|
let did = i.trait_did_full(cache).unwrap();
|
2021-04-22 21:02:21 -04:00
|
|
|
let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx);
|
2021-04-29 21:36:54 +02:00
|
|
|
let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
|
2019-12-22 17:42:04 -05:00
|
|
|
let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
|
|
|
|
render_impl(
|
|
|
|
&mut buffer,
|
|
|
|
cx,
|
|
|
|
i,
|
2020-11-02 19:17:33 +01:00
|
|
|
containing_item,
|
2019-12-22 17:42:04 -05:00
|
|
|
assoc_link,
|
|
|
|
RenderMode::Normal,
|
|
|
|
None,
|
2020-01-13 23:28:34 +01:00
|
|
|
&[],
|
2021-08-31 12:20:02 +02:00
|
|
|
ImplRenderingParameters {
|
|
|
|
show_def_docs: true,
|
|
|
|
is_on_foreign_type: false,
|
|
|
|
show_default_items: true,
|
|
|
|
show_non_assoc_items: true,
|
|
|
|
toggle_open_by_default: true,
|
|
|
|
},
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2019-12-08 13:56:26 +01:00
|
|
|
buffer.into_inner()
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
impls.sort();
|
|
|
|
w.write_str(&impls.join(""));
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
}
|
|
|
|
|
2021-03-17 11:41:01 -07:00
|
|
|
fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
|
2020-06-24 08:16:21 -05:00
|
|
|
use crate::formats::item_type::ItemType::*;
|
2016-03-25 00:10:15 +01:00
|
|
|
|
|
|
|
let name = it.name.as_ref().unwrap();
|
2016-09-28 22:53:35 -04:00
|
|
|
let ty = match it.type_() {
|
2019-05-19 16:26:08 +08:00
|
|
|
Typedef | AssocType => AssocType,
|
2020-03-05 11:26:51 +01:00
|
|
|
s => s,
|
2016-03-25 00:10:15 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
let anchor = format!("#{}.{}", ty, name);
|
|
|
|
match link {
|
2016-04-16 11:46:52 -04:00
|
|
|
AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
|
|
|
|
AssocItemLink::Anchor(None) => anchor,
|
2016-03-25 00:10:15 +01:00
|
|
|
AssocItemLink::GotoSource(did, _) => {
|
2021-06-26 17:10:52 +02:00
|
|
|
href(did.expect_def_id(), cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
|
2016-03-25 00:10:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
fn assoc_const(
|
|
|
|
w: &mut Buffer,
|
|
|
|
it: &clean::Item,
|
|
|
|
ty: &clean::Type,
|
|
|
|
_default: Option<&String>,
|
|
|
|
link: AssocItemLink<'_>,
|
|
|
|
extra: &str,
|
2020-12-16 18:10:04 -05:00
|
|
|
cx: &Context<'_>,
|
2019-12-22 17:42:04 -05:00
|
|
|
) {
|
|
|
|
write!(
|
|
|
|
w,
|
2021-08-23 10:49:56 -07:00
|
|
|
"{}{}const <a href=\"{}\" class=\"constant\">{}</a>: {}",
|
2019-12-22 17:42:04 -05:00
|
|
|
extra,
|
2021-06-27 09:28:17 +02:00
|
|
|
it.visibility.print_with_space(it.def_id, cx),
|
2021-03-17 11:41:01 -07:00
|
|
|
naive_assoc_href(it, link, cx),
|
2019-12-22 17:42:04 -05:00
|
|
|
it.name.as_ref().unwrap(),
|
2021-03-17 11:41:01 -07:00
|
|
|
ty.print(cx)
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2015-03-15 19:35:25 -06:00
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
fn assoc_type(
|
|
|
|
w: &mut Buffer,
|
|
|
|
it: &clean::Item,
|
|
|
|
bounds: &[clean::GenericBound],
|
|
|
|
default: Option<&clean::Type>,
|
|
|
|
link: AssocItemLink<'_>,
|
|
|
|
extra: &str,
|
2021-03-17 11:41:01 -07:00
|
|
|
cx: &Context<'_>,
|
2019-12-22 17:42:04 -05:00
|
|
|
) {
|
|
|
|
write!(
|
|
|
|
w,
|
2020-10-16 00:52:49 +08:00
|
|
|
"{}type <a href=\"{}\" class=\"type\">{}</a>",
|
2019-12-22 17:42:04 -05:00
|
|
|
extra,
|
2021-03-17 11:41:01 -07:00
|
|
|
naive_assoc_href(it, link, cx),
|
2019-12-22 17:42:04 -05:00
|
|
|
it.name.as_ref().unwrap()
|
|
|
|
);
|
2015-03-24 16:54:09 -07:00
|
|
|
if !bounds.is_empty() {
|
2021-04-16 12:29:35 -07:00
|
|
|
write!(w, ": {}", print_generic_bounds(bounds, cx))
|
2015-01-02 08:26:55 -05:00
|
|
|
}
|
2016-03-25 00:10:15 +01:00
|
|
|
if let Some(default) = default {
|
2021-03-17 11:41:01 -07:00
|
|
|
write!(w, " = {}", default.print(cx))
|
2015-01-02 08:26:55 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-29 21:00:14 -05:00
|
|
|
fn render_stability_since_raw(
|
|
|
|
w: &mut Buffer,
|
|
|
|
ver: Option<&str>,
|
2021-06-20 08:13:23 +08:00
|
|
|
const_stability: Option<&ConstStability>,
|
2020-11-29 21:00:14 -05:00
|
|
|
containing_ver: Option<&str>,
|
|
|
|
containing_const_ver: Option<&str>,
|
|
|
|
) {
|
2021-01-23 18:05:59 +01:00
|
|
|
let ver = ver.filter(|inner| !inner.is_empty());
|
2020-11-29 21:00:14 -05:00
|
|
|
|
2021-06-20 08:13:23 +08:00
|
|
|
match (ver, const_stability) {
|
2021-06-20 08:39:54 +08:00
|
|
|
// stable and const stable
|
2021-06-20 08:13:23 +08:00
|
|
|
(Some(v), Some(ConstStability { level: StabilityLevel::Stable { since }, .. }))
|
|
|
|
if Some(since.as_str()).as_deref() != containing_const_ver =>
|
|
|
|
{
|
2021-01-23 18:05:59 +01:00
|
|
|
write!(
|
|
|
|
w,
|
|
|
|
"<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>",
|
2021-06-20 08:39:54 +08:00
|
|
|
v, since
|
2021-01-23 18:05:59 +01:00
|
|
|
);
|
|
|
|
}
|
2021-06-20 08:39:54 +08:00
|
|
|
// stable and const unstable
|
2021-06-20 08:13:23 +08:00
|
|
|
(
|
|
|
|
Some(v),
|
|
|
|
Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }),
|
|
|
|
) => {
|
|
|
|
write!(
|
|
|
|
w,
|
|
|
|
"<span class=\"since\" title=\"Stable since Rust version {0}, const unstable\">{0} (const: ",
|
|
|
|
v
|
|
|
|
);
|
|
|
|
if let Some(n) = issue {
|
|
|
|
write!(
|
|
|
|
w,
|
|
|
|
"<a href=\"https://github.com/rust-lang/rust/issues/{}\" title=\"Tracking issue for {}\">unstable</a>",
|
|
|
|
n, feature
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
write!(w, "unstable");
|
|
|
|
}
|
|
|
|
write!(w, ")</span>");
|
|
|
|
}
|
2021-06-20 08:39:54 +08:00
|
|
|
// stable
|
2021-01-23 18:05:59 +01:00
|
|
|
(Some(v), _) if ver != containing_ver => {
|
|
|
|
write!(
|
|
|
|
w,
|
|
|
|
"<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
|
|
|
|
v
|
|
|
|
);
|
2016-02-09 21:15:29 -05:00
|
|
|
}
|
2021-01-23 18:05:59 +01:00
|
|
|
_ => {}
|
2016-02-09 21:15:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
fn render_assoc_item(
|
|
|
|
w: &mut Buffer,
|
|
|
|
item: &clean::Item,
|
|
|
|
link: AssocItemLink<'_>,
|
|
|
|
parent: ItemType,
|
2020-12-16 18:10:04 -05:00
|
|
|
cx: &Context<'_>,
|
2019-12-22 17:42:04 -05:00
|
|
|
) {
|
|
|
|
fn method(
|
|
|
|
w: &mut Buffer,
|
|
|
|
meth: &clean::Item,
|
|
|
|
header: hir::FnHeader,
|
|
|
|
g: &clean::Generics,
|
|
|
|
d: &clean::FnDecl,
|
|
|
|
link: AssocItemLink<'_>,
|
|
|
|
parent: ItemType,
|
2020-12-16 18:10:04 -05:00
|
|
|
cx: &Context<'_>,
|
2019-12-22 17:42:04 -05:00
|
|
|
) {
|
2016-03-24 06:10:52 +01:00
|
|
|
let name = meth.name.as_ref().unwrap();
|
2015-04-06 17:56:35 -07:00
|
|
|
let href = match link {
|
2021-06-27 11:10:36 +02:00
|
|
|
AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
|
|
|
|
AssocItemLink::Anchor(None) => Some(format!("#{}.{}", meth.type_(), name)),
|
2016-03-24 06:10:52 +01:00
|
|
|
AssocItemLink::GotoSource(did, provided_methods) => {
|
|
|
|
// We're creating a link from an impl-item to the corresponding
|
|
|
|
// trait-item and need to map the anchored type accordingly.
|
2020-12-18 12:05:51 +01:00
|
|
|
let ty = if provided_methods.contains(&name) {
|
2016-03-24 06:10:52 +01:00
|
|
|
ItemType::Method
|
|
|
|
} else {
|
|
|
|
ItemType::TyMethod
|
|
|
|
};
|
|
|
|
|
2021-07-06 20:19:54 +02:00
|
|
|
match (href(did.expect_def_id(), cx), ty) {
|
|
|
|
(Ok(p), ty) => Some(format!("{}#{}.{}", p.0, ty, name)),
|
|
|
|
(Err(HrefError::DocumentationNotBuilt), ItemType::TyMethod) => None,
|
|
|
|
(Err(_), ty) => Some(format!("#{}.{}", ty, name)),
|
2021-06-27 11:10:36 +02:00
|
|
|
}
|
2015-04-06 17:56:35 -07:00
|
|
|
}
|
|
|
|
};
|
2021-06-27 09:28:17 +02:00
|
|
|
let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
|
2021-06-20 08:39:54 +08:00
|
|
|
let constness =
|
|
|
|
print_constness_with_space(&header.constness, meth.const_stability(cx.tcx()));
|
2021-03-06 23:30:49 -05:00
|
|
|
let asyncness = header.asyncness.print_with_space();
|
|
|
|
let unsafety = header.unsafety.print_with_space();
|
|
|
|
let defaultness = print_default_space(meth.is_default());
|
|
|
|
let abi = print_abi_with_space(header.abi).to_string();
|
2021-06-20 08:39:54 +08:00
|
|
|
|
2021-03-06 23:30:49 -05:00
|
|
|
// NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
|
2021-03-17 11:41:01 -07:00
|
|
|
let generics_len = format!("{:#}", g.print(cx)).len();
|
2021-03-06 23:30:49 -05:00
|
|
|
let mut header_len = "fn ".len()
|
|
|
|
+ vis.len()
|
|
|
|
+ constness.len()
|
|
|
|
+ asyncness.len()
|
|
|
|
+ unsafety.len()
|
|
|
|
+ defaultness.len()
|
|
|
|
+ abi.len()
|
|
|
|
+ name.as_str().len()
|
|
|
|
+ generics_len;
|
|
|
|
|
2021-03-27 12:50:09 -07:00
|
|
|
let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
|
2019-02-06 11:46:41 -05:00
|
|
|
header_len += 4;
|
2021-03-27 12:50:09 -07:00
|
|
|
let indent_str = " ";
|
|
|
|
render_attributes_in_pre(w, meth, indent_str);
|
|
|
|
(4, indent_str, false)
|
2016-10-15 09:46:43 -05:00
|
|
|
} else {
|
2021-03-27 12:50:09 -07:00
|
|
|
render_attributes_in_code(w, meth);
|
|
|
|
(0, "", true)
|
2016-10-15 09:46:43 -05:00
|
|
|
};
|
2021-03-06 23:30:49 -05:00
|
|
|
w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
|
2019-12-22 17:42:04 -05:00
|
|
|
write!(
|
|
|
|
w,
|
2021-06-27 11:10:36 +02:00
|
|
|
"{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a {href} class=\"fnname\">{name}</a>\
|
2021-04-01 13:26:29 -07:00
|
|
|
{generics}{decl}{notable_traits}{where_clause}",
|
2021-06-20 08:39:54 +08:00
|
|
|
indent = indent_str,
|
|
|
|
vis = vis,
|
|
|
|
constness = constness,
|
|
|
|
asyncness = asyncness,
|
|
|
|
unsafety = unsafety,
|
|
|
|
defaultness = defaultness,
|
|
|
|
abi = abi,
|
2021-07-11 02:18:21 +02:00
|
|
|
// links without a href are valid - https://www.w3schools.com/tags/att_a_href.asp
|
2021-06-27 11:10:36 +02:00
|
|
|
href = href.map(|href| format!("href=\"{}\"", href)).unwrap_or_else(|| "".to_string()),
|
2019-12-22 17:42:04 -05:00
|
|
|
name = name,
|
2021-03-17 11:41:01 -07:00
|
|
|
generics = g.print(cx),
|
2021-04-16 12:29:35 -07:00
|
|
|
decl = d.full_print(header_len, indent, header.asyncness, cx),
|
2021-03-17 11:41:01 -07:00
|
|
|
notable_traits = notable_traits_decl(&d, cx),
|
|
|
|
where_clause = print_where_clause(g, cx, indent, end_newline),
|
2019-12-22 17:42:04 -05:00
|
|
|
)
|
2013-09-18 22:18:38 -07:00
|
|
|
}
|
2020-12-13 11:32:57 -05:00
|
|
|
match *item.kind {
|
2019-12-22 17:42:04 -05:00
|
|
|
clean::StrippedItem(..) => {}
|
2020-12-16 18:10:04 -05:00
|
|
|
clean::TyMethodItem(ref m) => {
|
|
|
|
method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
|
|
|
|
}
|
2020-11-16 23:19:58 -05:00
|
|
|
clean::MethodItem(ref m, _) => {
|
2020-12-16 18:10:04 -05:00
|
|
|
method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
|
2020-11-16 23:19:58 -05:00
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
clean::AssocConstItem(ref ty, ref default) => assoc_const(
|
|
|
|
w,
|
|
|
|
item,
|
|
|
|
ty,
|
|
|
|
default.as_ref(),
|
|
|
|
link,
|
|
|
|
if parent == ItemType::Trait { " " } else { "" },
|
2020-12-16 18:10:04 -05:00
|
|
|
cx,
|
2019-12-22 17:42:04 -05:00
|
|
|
),
|
|
|
|
clean::AssocTypeItem(ref bounds, ref default) => assoc_type(
|
|
|
|
w,
|
|
|
|
item,
|
|
|
|
bounds,
|
|
|
|
default.as_ref(),
|
|
|
|
link,
|
|
|
|
if parent == ItemType::Trait { " " } else { "" },
|
2021-03-17 11:41:01 -07:00
|
|
|
cx,
|
2019-12-22 17:42:04 -05:00
|
|
|
),
|
|
|
|
_ => panic!("render_assoc_item called on non-associated-item"),
|
2013-09-18 22:18:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-13 15:38:44 -07:00
|
|
|
const ALLOWED_ATTRIBUTES: &[Symbol] =
|
|
|
|
&[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
|
2016-11-24 01:40:52 +02:00
|
|
|
|
2021-03-27 12:50:09 -07:00
|
|
|
fn attributes(it: &clean::Item) -> Vec<String> {
|
|
|
|
it.attrs
|
2020-06-28 18:20:06 -04:00
|
|
|
.other_attrs
|
|
|
|
.iter()
|
|
|
|
.filter_map(|attr| {
|
|
|
|
if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
|
2021-03-27 12:50:09 -07:00
|
|
|
Some(pprust::attribute_to_string(&attr).replace("\n", "").replace(" ", " "))
|
2020-06-28 18:20:06 -04:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
2021-03-27 12:50:09 -07:00
|
|
|
.collect()
|
|
|
|
}
|
2020-03-03 23:41:32 +00:00
|
|
|
|
2021-03-27 12:50:09 -07:00
|
|
|
// When an attribute is rendered inside a `<pre>` tag, it is formatted using
|
|
|
|
// a whitespace prefix and newline.
|
|
|
|
fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
|
|
|
|
for a in attributes(it) {
|
2021-05-03 02:14:56 -05:00
|
|
|
writeln!(w, "{}{}", prefix, a);
|
2021-03-27 12:50:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// When an attribute is rendered inside a <code> tag, it is formatted using
|
|
|
|
// a div to produce a newline after it.
|
|
|
|
fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
|
|
|
|
for a in attributes(it) {
|
2021-03-27 18:09:31 -07:00
|
|
|
write!(w, "<div class=\"code-attribute\">{}</div>", a);
|
2016-11-06 20:06:01 +01:00
|
|
|
}
|
2015-02-13 00:47:03 +09:00
|
|
|
}
|
|
|
|
|
2021-06-27 09:28:17 +02:00
|
|
|
#[derive(Copy, Clone)]
|
2016-03-24 06:10:52 +01:00
|
|
|
enum AssocItemLink<'a> {
|
2016-04-16 11:46:52 -04:00
|
|
|
Anchor(Option<&'a str>),
|
2021-06-26 13:52:31 +02:00
|
|
|
GotoSource(ItemId, &'a FxHashSet<Symbol>),
|
2015-04-06 17:56:35 -07:00
|
|
|
}
|
|
|
|
|
2016-04-16 11:46:52 -04:00
|
|
|
impl<'a> AssocItemLink<'a> {
|
2020-12-30 12:59:07 +01:00
|
|
|
fn anchor(&self, id: &'a str) -> Self {
|
2016-04-16 11:46:52 -04:00
|
|
|
match *self {
|
2019-12-22 17:42:04 -05:00
|
|
|
AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(&id)),
|
2021-06-27 09:28:17 +02:00
|
|
|
ref other => *other,
|
2016-04-16 11:46:52 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
fn render_assoc_items(
|
|
|
|
w: &mut Buffer,
|
2020-12-16 14:34:08 -05:00
|
|
|
cx: &Context<'_>,
|
2019-12-22 17:42:04 -05:00
|
|
|
containing_item: &clean::Item,
|
|
|
|
it: DefId,
|
2020-01-15 18:52:04 +01:00
|
|
|
what: AssocItemRender<'_>,
|
2019-12-22 17:42:04 -05:00
|
|
|
) {
|
2020-12-14 19:30:36 -05:00
|
|
|
info!("Documenting associated items of {:?}", containing_item.name);
|
2021-08-22 03:36:37 +00:00
|
|
|
let cache = cx.cache();
|
|
|
|
let v = match cache.impls.get(&it) {
|
2015-04-13 16:23:32 -07:00
|
|
|
Some(v) => v,
|
2019-08-31 15:47:55 -04:00
|
|
|
None => return,
|
2015-04-06 19:21:52 -07:00
|
|
|
};
|
2019-12-22 17:42:04 -05:00
|
|
|
let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
|
2015-03-24 16:54:09 -07:00
|
|
|
if !non_trait.is_empty() {
|
2016-09-04 18:35:35 +02:00
|
|
|
let render_mode = match what {
|
2015-03-14 12:05:00 -06:00
|
|
|
AssocItemRender::All => {
|
2021-01-30 01:02:18 +00:00
|
|
|
w.write_str(
|
2020-10-16 00:52:49 +08:00
|
|
|
"<h2 id=\"implementations\" class=\"small-section-header\">\
|
|
|
|
Implementations<a href=\"#implementations\" class=\"anchor\"></a>\
|
2021-01-30 01:02:18 +00:00
|
|
|
</h2>",
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2016-09-04 18:35:35 +02:00
|
|
|
RenderMode::Normal
|
2015-04-13 16:23:32 -07:00
|
|
|
}
|
2016-09-04 18:35:35 +02:00
|
|
|
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
|
2019-12-22 17:42:04 -05:00
|
|
|
write!(
|
|
|
|
w,
|
2021-05-03 09:21:52 -04:00
|
|
|
"<h2 id=\"deref-methods\" class=\"small-section-header\">\
|
2021-07-08 17:49:06 +02:00
|
|
|
<span>Methods from {trait_}<Target = {type_}></span>\
|
2021-05-03 09:21:52 -04:00
|
|
|
<a href=\"#deref-methods\" class=\"anchor\"></a>\
|
2020-08-31 13:16:50 +02:00
|
|
|
</h2>",
|
2021-03-17 11:41:01 -07:00
|
|
|
trait_ = trait_.print(cx),
|
|
|
|
type_ = type_.print(cx),
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2020-01-15 18:52:04 +01:00
|
|
|
RenderMode::ForDeref { mut_: deref_mut_ }
|
2015-04-13 16:23:32 -07:00
|
|
|
}
|
|
|
|
};
|
2015-04-06 19:21:52 -07:00
|
|
|
for i in &non_trait {
|
2019-12-22 17:42:04 -05:00
|
|
|
render_impl(
|
|
|
|
w,
|
|
|
|
cx,
|
|
|
|
i,
|
2020-11-02 19:17:33 +01:00
|
|
|
containing_item,
|
2019-12-22 17:42:04 -05:00
|
|
|
AssocItemLink::Anchor(None),
|
|
|
|
render_mode,
|
|
|
|
None,
|
2020-01-13 23:28:34 +01:00
|
|
|
&[],
|
2021-08-31 12:20:02 +02:00
|
|
|
ImplRenderingParameters {
|
|
|
|
show_def_docs: true,
|
|
|
|
is_on_foreign_type: false,
|
|
|
|
show_default_items: true,
|
|
|
|
show_non_assoc_items: true,
|
|
|
|
toggle_open_by_default: true,
|
|
|
|
},
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2015-04-06 19:21:52 -07:00
|
|
|
}
|
|
|
|
}
|
2021-05-03 09:21:52 -04:00
|
|
|
if let AssocItemRender::DerefFor { .. } = what {
|
|
|
|
return;
|
|
|
|
}
|
2015-03-24 16:54:09 -07:00
|
|
|
if !traits.is_empty() {
|
2021-08-21 20:58:23 -07:00
|
|
|
let deref_impl = traits.iter().find(|t| {
|
|
|
|
t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait()
|
|
|
|
});
|
2015-04-13 16:23:32 -07:00
|
|
|
if let Some(impl_) = deref_impl {
|
2021-08-21 20:58:23 -07:00
|
|
|
let has_deref_mut = traits.iter().any(|t| {
|
|
|
|
t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_mut_trait()
|
|
|
|
});
|
2021-01-12 23:36:04 +01:00
|
|
|
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
|
2015-04-13 16:23:32 -07:00
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
|
|
|
|
traits.iter().partition(|t| t.inner_impl().synthetic);
|
|
|
|
let (blanket_impl, concrete): (Vec<&&Impl>, _) =
|
|
|
|
concrete.into_iter().partition(|t| t.inner_impl().blanket_impl.is_some());
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
|
2019-08-31 15:47:55 -04:00
|
|
|
let mut impls = Buffer::empty_from(&w);
|
2021-01-12 23:36:04 +01:00
|
|
|
render_impls(cx, &mut impls, &concrete, containing_item);
|
2019-08-31 15:47:55 -04:00
|
|
|
let impls = impls.into_inner();
|
2018-03-24 17:22:08 +01:00
|
|
|
if !impls.is_empty() {
|
2019-12-22 17:42:04 -05:00
|
|
|
write!(
|
|
|
|
w,
|
2020-10-16 00:52:49 +08:00
|
|
|
"<h2 id=\"trait-implementations\" class=\"small-section-header\">\
|
|
|
|
Trait Implementations<a href=\"#trait-implementations\" class=\"anchor\"></a>\
|
2020-08-31 13:16:50 +02:00
|
|
|
</h2>\
|
2020-10-16 00:52:49 +08:00
|
|
|
<div id=\"trait-implementations-list\">{}</div>",
|
2019-12-22 17:42:04 -05:00
|
|
|
impls
|
|
|
|
);
|
2018-03-24 17:22:08 +01:00
|
|
|
}
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
|
2018-03-09 22:18:08 +01:00
|
|
|
if !synthetic.is_empty() {
|
2021-01-30 01:02:18 +00:00
|
|
|
w.write_str(
|
2020-10-16 00:52:49 +08:00
|
|
|
"<h2 id=\"synthetic-implementations\" class=\"small-section-header\">\
|
2020-08-31 13:16:50 +02:00
|
|
|
Auto Trait Implementations\
|
2020-10-16 00:52:49 +08:00
|
|
|
<a href=\"#synthetic-implementations\" class=\"anchor\"></a>\
|
2020-08-31 13:16:50 +02:00
|
|
|
</h2>\
|
2021-01-30 01:02:18 +00:00
|
|
|
<div id=\"synthetic-implementations-list\">",
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2021-01-12 23:36:04 +01:00
|
|
|
render_impls(cx, w, &synthetic, containing_item);
|
2021-01-30 01:02:18 +00:00
|
|
|
w.write_str("</div>");
|
2018-03-09 22:18:08 +01:00
|
|
|
}
|
2018-07-27 22:59:16 +02:00
|
|
|
|
|
|
|
if !blanket_impl.is_empty() {
|
2021-01-30 01:02:18 +00:00
|
|
|
w.write_str(
|
2020-10-16 00:52:49 +08:00
|
|
|
"<h2 id=\"blanket-implementations\" class=\"small-section-header\">\
|
2020-08-31 13:16:50 +02:00
|
|
|
Blanket Implementations\
|
2020-10-16 00:52:49 +08:00
|
|
|
<a href=\"#blanket-implementations\" class=\"anchor\"></a>\
|
2020-08-31 13:16:50 +02:00
|
|
|
</h2>\
|
2021-01-30 01:02:18 +00:00
|
|
|
<div id=\"blanket-implementations-list\">",
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2021-01-12 23:36:04 +01:00
|
|
|
render_impls(cx, w, &blanket_impl, containing_item);
|
2021-01-30 01:02:18 +00:00
|
|
|
w.write_str("</div>");
|
2018-07-27 22:59:16 +02:00
|
|
|
}
|
2014-04-28 20:36:08 -07:00
|
|
|
}
|
2013-09-18 22:18:38 -07:00
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
fn render_deref_methods(
|
|
|
|
w: &mut Buffer,
|
2020-12-16 14:34:08 -05:00
|
|
|
cx: &Context<'_>,
|
2019-12-22 17:42:04 -05:00
|
|
|
impl_: &Impl,
|
|
|
|
container_item: &clean::Item,
|
|
|
|
deref_mut: bool,
|
|
|
|
) {
|
2021-08-22 03:36:37 +00:00
|
|
|
let cache = cx.cache();
|
2016-05-03 19:15:59 +02:00
|
|
|
let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
|
2020-01-10 02:07:13 +01:00
|
|
|
let (target, real_target) = impl_
|
2019-12-22 17:42:04 -05:00
|
|
|
.inner_impl()
|
|
|
|
.items
|
|
|
|
.iter()
|
2020-12-13 11:32:57 -05:00
|
|
|
.find_map(|item| match *item.kind {
|
2020-01-10 14:46:28 +01:00
|
|
|
clean::TypedefItem(ref t, true) => Some(match *t {
|
2020-01-15 18:52:04 +01:00
|
|
|
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
|
|
|
|
_ => (&t.type_, &t.type_),
|
2020-01-10 14:46:28 +01:00
|
|
|
}),
|
2015-04-13 16:23:32 -07:00
|
|
|
_ => None,
|
2019-12-22 17:42:04 -05:00
|
|
|
})
|
|
|
|
.expect("Expected associated type binding");
|
2021-01-28 22:03:20 +00:00
|
|
|
debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target);
|
2019-12-22 17:42:04 -05:00
|
|
|
let what =
|
2020-01-15 18:52:04 +01:00
|
|
|
AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
|
2021-08-22 03:36:37 +00:00
|
|
|
if let Some(did) = target.def_id_full(cache) {
|
|
|
|
if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cache) {
|
2020-12-31 02:23:19 +00:00
|
|
|
// `impl Deref<Target = S> for S`
|
|
|
|
if did == type_did {
|
|
|
|
// Avoid infinite cycles
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-01-12 23:36:04 +01:00
|
|
|
render_assoc_items(w, cx, container_item, did, what);
|
2020-01-15 18:52:04 +01:00
|
|
|
} else {
|
|
|
|
if let Some(prim) = target.primitive_type() {
|
2021-08-22 03:36:37 +00:00
|
|
|
if let Some(&did) = cache.primitive_locations.get(&prim) {
|
2021-01-12 23:36:04 +01:00
|
|
|
render_assoc_items(w, cx, container_item, did, what);
|
2020-01-15 18:52:04 +01:00
|
|
|
}
|
|
|
|
}
|
2014-05-03 02:08:58 -07:00
|
|
|
}
|
2015-04-13 16:23:32 -07:00
|
|
|
}
|
|
|
|
|
2021-08-27 16:49:14 -07:00
|
|
|
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
|
2020-12-13 11:32:57 -05:00
|
|
|
let self_type_opt = match *item.kind {
|
2020-11-16 23:19:58 -05:00
|
|
|
clean::MethodItem(ref method, _) => method.decl.self_type(),
|
2017-10-28 01:11:01 +02:00
|
|
|
clean::TyMethodItem(ref method) => method.decl.self_type(),
|
2019-12-22 17:42:04 -05:00
|
|
|
_ => None,
|
2017-10-28 01:11:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(self_ty) = self_type_opt {
|
2017-10-31 02:01:23 +01:00
|
|
|
let (by_mut_ref, by_box, by_value) = match self_ty {
|
2019-12-22 17:42:04 -05:00
|
|
|
SelfTy::SelfBorrowed(_, mutability)
|
|
|
|
| SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
|
2019-12-21 15:47:27 +01:00
|
|
|
(mutability == Mutability::Mut, false, false)
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2017-10-28 01:11:01 +02:00
|
|
|
SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
|
2021-08-27 16:49:14 -07:00
|
|
|
(false, Some(did) == tcx.lang_items().owned_box(), false)
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2017-10-31 02:01:23 +01:00
|
|
|
SelfTy::SelfValue => (false, false, true),
|
|
|
|
_ => (false, false, false),
|
2017-10-28 01:11:01 +02:00
|
|
|
};
|
|
|
|
|
2017-10-31 02:01:23 +01:00
|
|
|
(deref_mut_ || !by_mut_ref) && !by_box && !by_value
|
2017-10-28 01:11:01 +02:00
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-17 11:41:01 -07:00
|
|
|
fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
|
2020-07-06 12:53:44 -07:00
|
|
|
let mut out = Buffer::html();
|
|
|
|
let mut trait_ = String::new();
|
|
|
|
|
2021-03-17 11:41:01 -07:00
|
|
|
if let Some(did) = decl.output.def_id_full(cx.cache()) {
|
|
|
|
if let Some(impls) = cx.cache().impls.get(&did) {
|
2020-07-06 12:53:44 -07:00
|
|
|
for i in impls {
|
|
|
|
let impl_ = i.inner_impl();
|
2021-03-17 11:41:01 -07:00
|
|
|
if impl_.trait_.def_id().map_or(false, |d| {
|
|
|
|
cx.cache().traits.get(&d).map(|t| t.is_notable).unwrap_or(false)
|
|
|
|
}) {
|
2020-07-06 12:53:44 -07:00
|
|
|
if out.is_empty() {
|
2021-01-30 01:02:18 +00:00
|
|
|
write!(
|
|
|
|
&mut out,
|
2021-07-25 21:41:57 +00:00
|
|
|
"<div class=\"notable\">Notable traits for {}</div>\
|
2020-08-31 13:16:50 +02:00
|
|
|
<code class=\"content\">",
|
2021-03-17 11:41:01 -07:00
|
|
|
impl_.for_.print(cx)
|
2021-01-30 01:02:18 +00:00
|
|
|
);
|
2021-03-17 11:41:01 -07:00
|
|
|
trait_.push_str(&impl_.for_.print(cx).to_string());
|
2020-07-06 12:53:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//use the "where" class here to make it small
|
2021-01-30 01:02:18 +00:00
|
|
|
write!(
|
|
|
|
&mut out,
|
2020-07-06 12:53:44 -07:00
|
|
|
"<span class=\"where fmt-newline\">{}</span>",
|
2021-03-17 11:41:01 -07:00
|
|
|
impl_.print(false, cx)
|
2021-01-30 01:02:18 +00:00
|
|
|
);
|
2021-03-17 11:41:01 -07:00
|
|
|
let t_did = impl_.trait_.def_id_full(cx.cache()).unwrap();
|
2020-07-06 12:53:44 -07:00
|
|
|
for it in &impl_.items {
|
2020-12-13 11:32:57 -05:00
|
|
|
if let clean::TypedefItem(ref tydef, _) = *it.kind {
|
2020-07-06 12:53:44 -07:00
|
|
|
out.push_str("<span class=\"where fmt-newline\"> ");
|
|
|
|
assoc_type(
|
|
|
|
&mut out,
|
|
|
|
it,
|
|
|
|
&[],
|
|
|
|
Some(&tydef.type_),
|
2021-04-29 21:36:54 +02:00
|
|
|
AssocItemLink::GotoSource(t_did.into(), &FxHashSet::default()),
|
2020-07-06 12:53:44 -07:00
|
|
|
"",
|
2021-03-17 11:41:01 -07:00
|
|
|
cx,
|
2020-07-06 12:53:44 -07:00
|
|
|
);
|
|
|
|
out.push_str(";</span>");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !out.is_empty() {
|
|
|
|
out.insert_str(
|
|
|
|
0,
|
2020-10-16 00:52:49 +08:00
|
|
|
"<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ\
|
|
|
|
<div class=\"notable-traits-tooltiptext\"><span class=\"docblock\">",
|
2020-07-06 12:53:44 -07:00
|
|
|
);
|
2020-07-06 17:18:04 -07:00
|
|
|
out.push_str("</code></span></div></span></span>");
|
2020-07-06 12:53:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
out.into_inner()
|
|
|
|
}
|
|
|
|
|
2021-08-31 12:20:02 +02:00
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
struct ImplRenderingParameters {
|
|
|
|
show_def_docs: bool,
|
|
|
|
is_on_foreign_type: bool,
|
|
|
|
show_default_items: bool,
|
|
|
|
/// Whether or not to show methods.
|
|
|
|
show_non_assoc_items: bool,
|
|
|
|
toggle_open_by_default: bool,
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
fn render_impl(
|
|
|
|
w: &mut Buffer,
|
2020-12-16 14:34:08 -05:00
|
|
|
cx: &Context<'_>,
|
2019-12-22 17:42:04 -05:00
|
|
|
i: &Impl,
|
2020-11-02 19:17:33 +01:00
|
|
|
parent: &clean::Item,
|
2019-12-22 17:42:04 -05:00
|
|
|
link: AssocItemLink<'_>,
|
|
|
|
render_mode: RenderMode,
|
|
|
|
use_absolute: Option<bool>,
|
2020-01-13 23:28:34 +01:00
|
|
|
aliases: &[String],
|
2021-08-31 12:20:02 +02:00
|
|
|
rendering_params: ImplRenderingParameters,
|
2019-12-22 17:42:04 -05:00
|
|
|
) {
|
2021-03-07 23:11:12 +01:00
|
|
|
let cache = cx.cache();
|
2021-03-17 11:41:01 -07:00
|
|
|
let traits = &cache.traits;
|
2021-03-07 23:11:12 +01:00
|
|
|
let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
|
2021-04-17 23:43:20 -07:00
|
|
|
let mut close_tags = String::new();
|
2020-11-02 19:17:33 +01:00
|
|
|
|
2021-04-28 21:19:52 +02:00
|
|
|
// For trait implementations, the `interesting` output contains all methods that have doc
|
|
|
|
// comments, and the `boring` output contains all methods that do not. The distinction is
|
|
|
|
// used to allow hiding the boring methods.
|
2021-06-16 22:48:23 -07:00
|
|
|
// `containing_item` is used for rendering stability info. If the parent is a trait impl,
|
|
|
|
// `containing_item` will the grandparent, since trait impls can't have stability attached.
|
2019-12-22 17:42:04 -05:00
|
|
|
fn doc_impl_item(
|
2021-04-28 21:19:52 +02:00
|
|
|
boring: &mut Buffer,
|
|
|
|
interesting: &mut Buffer,
|
2020-12-16 14:34:08 -05:00
|
|
|
cx: &Context<'_>,
|
2019-12-22 17:42:04 -05:00
|
|
|
item: &clean::Item,
|
2020-11-02 19:17:33 +01:00
|
|
|
parent: &clean::Item,
|
2021-06-16 22:48:23 -07:00
|
|
|
containing_item: &clean::Item,
|
2019-12-22 17:42:04 -05:00
|
|
|
link: AssocItemLink<'_>,
|
|
|
|
render_mode: RenderMode,
|
|
|
|
is_default_item: bool,
|
|
|
|
trait_: Option<&clean::Trait>,
|
2021-08-31 12:20:02 +02:00
|
|
|
rendering_params: ImplRenderingParameters,
|
2019-12-22 17:42:04 -05:00
|
|
|
) {
|
2016-09-28 22:53:35 -04:00
|
|
|
let item_type = item.type_();
|
2015-12-02 23:49:18 +01:00
|
|
|
let name = item.name.as_ref().unwrap();
|
2016-02-28 12:11:13 +01:00
|
|
|
|
2021-08-31 12:20:02 +02:00
|
|
|
let render_method_item = rendering_params.show_non_assoc_items
|
2021-08-30 16:04:28 +02:00
|
|
|
&& match render_mode {
|
|
|
|
RenderMode::Normal => true,
|
|
|
|
RenderMode::ForDeref { mut_: deref_mut_ } => {
|
2021-08-27 16:49:14 -07:00
|
|
|
should_render_item(&item, deref_mut_, cx.tcx())
|
2021-08-30 16:04:28 +02:00
|
|
|
}
|
|
|
|
};
|
2016-02-28 12:11:13 +01:00
|
|
|
|
2021-03-11 03:32:30 +01:00
|
|
|
let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
|
2021-04-28 21:19:52 +02:00
|
|
|
|
|
|
|
let mut doc_buffer = Buffer::empty_from(boring);
|
|
|
|
let mut info_buffer = Buffer::empty_from(boring);
|
|
|
|
let mut short_documented = true;
|
|
|
|
|
|
|
|
if render_method_item {
|
|
|
|
if !is_default_item {
|
|
|
|
if let Some(t) = trait_ {
|
|
|
|
// The trait item may have been stripped so we might not
|
|
|
|
// find any documentation or stability for it.
|
|
|
|
if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
|
|
|
|
// We need the stability of the item from the trait
|
|
|
|
// because impls can't have a stability.
|
|
|
|
if item.doc_value().is_some() {
|
|
|
|
document_item_info(&mut info_buffer, cx, it, Some(parent));
|
2021-10-04 21:54:00 -04:00
|
|
|
document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
|
2021-04-28 21:19:52 +02:00
|
|
|
short_documented = false;
|
|
|
|
} else {
|
|
|
|
// In case the item isn't documented,
|
|
|
|
// provide short documentation from the trait.
|
2021-08-31 12:20:02 +02:00
|
|
|
document_short(
|
|
|
|
&mut doc_buffer,
|
|
|
|
it,
|
|
|
|
cx,
|
|
|
|
link,
|
|
|
|
parent,
|
|
|
|
rendering_params.show_def_docs,
|
|
|
|
);
|
2021-04-28 21:19:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
document_item_info(&mut info_buffer, cx, item, Some(parent));
|
2021-08-31 12:20:02 +02:00
|
|
|
if rendering_params.show_def_docs {
|
2021-10-04 21:54:00 -04:00
|
|
|
document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
|
2021-04-28 21:19:52 +02:00
|
|
|
short_documented = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-08-31 12:20:02 +02:00
|
|
|
document_short(
|
|
|
|
&mut doc_buffer,
|
|
|
|
item,
|
|
|
|
cx,
|
|
|
|
link,
|
|
|
|
parent,
|
|
|
|
rendering_params.show_def_docs,
|
|
|
|
);
|
2021-04-28 21:19:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
let w = if short_documented && trait_.is_some() { interesting } else { boring };
|
|
|
|
|
2021-05-10 16:41:41 -07:00
|
|
|
let toggled = !doc_buffer.is_empty();
|
|
|
|
if toggled {
|
|
|
|
let method_toggle_class =
|
|
|
|
if item_type == ItemType::Method { " method-toggle" } else { "" };
|
|
|
|
write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
|
2021-04-28 21:19:52 +02:00
|
|
|
}
|
2020-12-13 11:32:57 -05:00
|
|
|
match *item.kind {
|
2020-11-16 23:19:58 -05:00
|
|
|
clean::MethodItem(..) | clean::TyMethodItem(_) => {
|
2015-04-26 21:03:38 +02:00
|
|
|
// Only render when the method is not static or we allow static methods
|
2016-09-04 18:35:35 +02:00
|
|
|
if render_method_item {
|
2018-07-22 07:25:00 -06:00
|
|
|
let id = cx.derive_id(format!("{}.{}", item_type, name));
|
2021-03-13 01:40:13 +01:00
|
|
|
let source_id = trait_
|
2021-03-13 02:33:04 +01:00
|
|
|
.and_then(|trait_| {
|
|
|
|
trait_.items.iter().find(|item| {
|
|
|
|
item.name.map(|n| n.as_str().eq(&name.as_str())).unwrap_or(false)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.map(|item| format!("{}.{}", item.type_(), name));
|
2021-04-23 22:15:57 +02:00
|
|
|
write!(
|
|
|
|
w,
|
2021-06-01 21:43:09 -07:00
|
|
|
"<div id=\"{}\" class=\"{}{} has-srclink\">",
|
2021-04-23 22:15:57 +02:00
|
|
|
id, item_type, in_trait_class,
|
|
|
|
);
|
2021-06-16 22:48:23 -07:00
|
|
|
render_rightside(w, cx, item, containing_item);
|
2021-06-16 22:47:46 -07:00
|
|
|
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
|
2021-07-25 21:41:57 +00:00
|
|
|
w.write_str("<h4 class=\"code-header\">");
|
2021-03-13 01:40:13 +01:00
|
|
|
render_assoc_item(
|
|
|
|
w,
|
|
|
|
item,
|
|
|
|
link.anchor(source_id.as_ref().unwrap_or(&id)),
|
|
|
|
ItemType::Impl,
|
2021-03-13 02:33:04 +01:00
|
|
|
cx,
|
2021-03-13 01:40:13 +01:00
|
|
|
);
|
2021-07-25 21:41:57 +00:00
|
|
|
w.write_str("</h4>");
|
2021-04-23 22:15:57 +02:00
|
|
|
w.write_str("</div>");
|
2015-04-26 21:03:38 +02:00
|
|
|
}
|
2014-11-20 11:22:09 -08:00
|
|
|
}
|
2015-05-21 14:17:37 +02:00
|
|
|
clean::TypedefItem(ref tydef, _) => {
|
2021-03-13 01:40:13 +01:00
|
|
|
let source_id = format!("{}.{}", ItemType::AssocType, name);
|
|
|
|
let id = cx.derive_id(source_id.clone());
|
2021-04-23 22:15:57 +02:00
|
|
|
write!(
|
|
|
|
w,
|
2021-06-16 22:47:46 -07:00
|
|
|
"<div id=\"{}\" class=\"{}{} has-srclink\">",
|
2021-04-23 22:15:57 +02:00
|
|
|
id, item_type, in_trait_class
|
|
|
|
);
|
2021-06-16 22:47:46 -07:00
|
|
|
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
|
2021-07-25 21:41:57 +00:00
|
|
|
w.write_str("<h4 class=\"code-header\">");
|
2021-01-12 23:36:04 +01:00
|
|
|
assoc_type(
|
|
|
|
w,
|
|
|
|
item,
|
|
|
|
&Vec::new(),
|
|
|
|
Some(&tydef.type_),
|
2021-03-13 01:40:13 +01:00
|
|
|
link.anchor(if trait_.is_some() { &source_id } else { &id }),
|
2021-01-12 23:36:04 +01:00
|
|
|
"",
|
2021-03-17 11:41:01 -07:00
|
|
|
cx,
|
2021-01-12 23:36:04 +01:00
|
|
|
);
|
2021-07-25 21:41:57 +00:00
|
|
|
w.write_str("</h4>");
|
2021-04-23 22:15:57 +02:00
|
|
|
w.write_str("</div>");
|
2014-11-20 11:22:09 -08:00
|
|
|
}
|
2019-05-19 16:26:08 +08:00
|
|
|
clean::AssocConstItem(ref ty, ref default) => {
|
2021-03-13 01:40:13 +01:00
|
|
|
let source_id = format!("{}.{}", item_type, name);
|
|
|
|
let id = cx.derive_id(source_id.clone());
|
2021-04-23 22:15:57 +02:00
|
|
|
write!(
|
|
|
|
w,
|
2021-06-16 22:47:46 -07:00
|
|
|
"<div id=\"{}\" class=\"{}{} has-srclink\">",
|
2021-04-23 22:15:57 +02:00
|
|
|
id, item_type, in_trait_class
|
|
|
|
);
|
2021-06-16 22:48:23 -07:00
|
|
|
render_rightside(w, cx, item, containing_item);
|
2021-06-16 22:47:46 -07:00
|
|
|
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
|
2021-07-25 21:41:57 +00:00
|
|
|
w.write_str("<h4 class=\"code-header\">");
|
2021-03-13 01:40:13 +01:00
|
|
|
assoc_const(
|
|
|
|
w,
|
|
|
|
item,
|
|
|
|
ty,
|
|
|
|
default.as_ref(),
|
|
|
|
link.anchor(if trait_.is_some() { &source_id } else { &id }),
|
|
|
|
"",
|
2021-03-13 02:33:04 +01:00
|
|
|
cx,
|
2021-03-13 01:40:13 +01:00
|
|
|
);
|
2021-07-25 21:41:57 +00:00
|
|
|
w.write_str("</h4>");
|
2021-04-23 22:15:57 +02:00
|
|
|
w.write_str("</div>");
|
2015-04-30 09:37:13 -07:00
|
|
|
}
|
2019-05-19 16:26:08 +08:00
|
|
|
clean::AssocTypeItem(ref bounds, ref default) => {
|
2021-03-13 01:40:13 +01:00
|
|
|
let source_id = format!("{}.{}", item_type, name);
|
|
|
|
let id = cx.derive_id(source_id.clone());
|
2021-06-16 22:47:46 -07:00
|
|
|
write!(w, "<div id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
|
|
|
|
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
|
2021-07-25 21:41:57 +00:00
|
|
|
w.write_str("<h4 class=\"code-header\">");
|
2021-03-07 18:09:35 +01:00
|
|
|
assoc_type(
|
|
|
|
w,
|
|
|
|
item,
|
|
|
|
bounds,
|
|
|
|
default.as_ref(),
|
2021-03-13 01:40:13 +01:00
|
|
|
link.anchor(if trait_.is_some() { &source_id } else { &id }),
|
2021-03-07 18:09:35 +01:00
|
|
|
"",
|
2021-03-17 11:41:01 -07:00
|
|
|
cx,
|
2021-03-07 18:09:35 +01:00
|
|
|
);
|
2021-07-25 21:41:57 +00:00
|
|
|
w.write_str("</h4>");
|
2021-04-23 22:15:57 +02:00
|
|
|
w.write_str("</div>");
|
2015-01-02 08:26:55 -05:00
|
|
|
}
|
2019-08-31 15:47:55 -04:00
|
|
|
clean::StrippedItem(..) => return,
|
2019-12-22 17:42:04 -05:00
|
|
|
_ => panic!("can't make docs for trait item with name {:?}", item.name),
|
2014-11-20 11:22:09 -08:00
|
|
|
}
|
2015-04-26 21:03:38 +02:00
|
|
|
|
2021-04-28 21:19:52 +02:00
|
|
|
w.push_buffer(info_buffer);
|
2021-05-10 16:41:41 -07:00
|
|
|
if toggled {
|
2021-04-28 21:19:52 +02:00
|
|
|
w.write_str("</summary>");
|
|
|
|
w.push_buffer(doc_buffer);
|
|
|
|
w.push_str("</details>");
|
2013-10-21 11:33:04 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-27 15:26:14 +02:00
|
|
|
let mut impl_items = Buffer::empty_from(w);
|
2021-04-28 21:19:52 +02:00
|
|
|
let mut default_impl_items = Buffer::empty_from(w);
|
|
|
|
|
2016-05-03 19:15:59 +02:00
|
|
|
for trait_item in &i.inner_impl().items {
|
2019-12-22 17:42:04 -05:00
|
|
|
doc_impl_item(
|
2021-04-28 21:19:52 +02:00
|
|
|
&mut default_impl_items,
|
2021-04-27 15:26:14 +02:00
|
|
|
&mut impl_items,
|
2019-12-22 17:42:04 -05:00
|
|
|
cx,
|
|
|
|
trait_item,
|
2020-11-02 19:17:33 +01:00
|
|
|
if trait_.is_some() { &i.impl_item } else { parent },
|
2021-06-16 22:48:23 -07:00
|
|
|
parent,
|
2021-06-27 09:28:17 +02:00
|
|
|
link,
|
2019-12-22 17:42:04 -05:00
|
|
|
render_mode,
|
|
|
|
false,
|
2021-02-12 14:33:32 +01:00
|
|
|
trait_.map(|t| &t.trait_),
|
2021-08-31 12:20:02 +02:00
|
|
|
rendering_params,
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2013-09-18 22:18:38 -07:00
|
|
|
}
|
2013-10-21 11:33:04 -07:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
fn render_default_items(
|
2021-05-01 20:41:00 +02:00
|
|
|
boring: &mut Buffer,
|
|
|
|
interesting: &mut Buffer,
|
2020-12-16 14:34:08 -05:00
|
|
|
cx: &Context<'_>,
|
2019-12-22 17:42:04 -05:00
|
|
|
t: &clean::Trait,
|
|
|
|
i: &clean::Impl,
|
2020-11-02 19:17:33 +01:00
|
|
|
parent: &clean::Item,
|
2021-06-16 22:48:23 -07:00
|
|
|
containing_item: &clean::Item,
|
2019-12-22 17:42:04 -05:00
|
|
|
render_mode: RenderMode,
|
2021-08-31 12:20:02 +02:00
|
|
|
rendering_params: ImplRenderingParameters,
|
2019-12-22 17:42:04 -05:00
|
|
|
) {
|
2015-01-31 12:20:46 -05:00
|
|
|
for trait_item in &t.items {
|
2020-12-29 19:33:48 +01:00
|
|
|
let n = trait_item.name;
|
2020-03-05 22:01:12 +01:00
|
|
|
if i.items.iter().any(|m| m.name == n) {
|
2016-02-28 12:11:13 +01:00
|
|
|
continue;
|
2014-05-03 02:08:58 -07:00
|
|
|
}
|
2021-01-15 15:36:15 +01:00
|
|
|
let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap();
|
2021-04-22 21:02:21 -04:00
|
|
|
let provided_methods = i.provided_trait_methods(cx.tcx());
|
2021-04-29 21:36:54 +02:00
|
|
|
let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
|
2014-05-03 02:08:58 -07:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
doc_impl_item(
|
2021-05-01 20:41:00 +02:00
|
|
|
boring,
|
|
|
|
interesting,
|
2019-12-22 17:42:04 -05:00
|
|
|
cx,
|
|
|
|
trait_item,
|
2020-10-06 20:48:01 +02:00
|
|
|
parent,
|
2021-06-16 22:48:23 -07:00
|
|
|
containing_item,
|
2019-12-22 17:42:04 -05:00
|
|
|
assoc_link,
|
|
|
|
render_mode,
|
|
|
|
true,
|
2021-03-13 01:40:13 +01:00
|
|
|
Some(t),
|
2021-08-31 12:20:02 +02:00
|
|
|
rendering_params,
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2014-05-03 02:08:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-21 11:33:04 -07:00
|
|
|
// If we've implemented a trait, then also emit documentation for all
|
2016-03-25 00:10:15 +01:00
|
|
|
// default items which weren't overridden in the implementation block.
|
2019-06-03 22:11:57 +01:00
|
|
|
// We don't emit documentation for default items if they appear in the
|
|
|
|
// Implementations on Foreign Types or Implementors sections.
|
2021-08-31 12:20:02 +02:00
|
|
|
if rendering_params.show_default_items {
|
2021-02-12 14:33:32 +01:00
|
|
|
if let Some(t) = trait_ {
|
2019-12-22 17:42:04 -05:00
|
|
|
render_default_items(
|
2021-04-28 21:19:52 +02:00
|
|
|
&mut default_impl_items,
|
2021-04-27 15:26:14 +02:00
|
|
|
&mut impl_items,
|
2019-12-22 17:42:04 -05:00
|
|
|
cx,
|
2021-02-12 14:33:32 +01:00
|
|
|
&t.trait_,
|
2019-12-22 17:42:04 -05:00
|
|
|
&i.inner_impl(),
|
2020-11-02 19:17:33 +01:00
|
|
|
&i.impl_item,
|
2021-06-16 22:48:23 -07:00
|
|
|
parent,
|
2019-12-22 17:42:04 -05:00
|
|
|
render_mode,
|
2021-08-31 12:20:02 +02:00
|
|
|
rendering_params,
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2019-06-03 22:11:57 +01:00
|
|
|
}
|
2013-10-21 11:33:04 -07:00
|
|
|
}
|
2021-06-07 21:16:35 -07:00
|
|
|
if render_mode == RenderMode::Normal {
|
2021-06-08 10:39:57 -07:00
|
|
|
let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
|
2021-05-01 20:41:00 +02:00
|
|
|
if toggled {
|
|
|
|
close_tags.insert_str(0, "</details>");
|
2021-08-30 16:04:28 +02:00
|
|
|
write!(
|
|
|
|
w,
|
|
|
|
"<details class=\"rustdoc-toggle implementors-toggle\"{}>",
|
2021-08-31 12:20:02 +02:00
|
|
|
if rendering_params.toggle_open_by_default { " open" } else { "" }
|
2021-08-30 16:04:28 +02:00
|
|
|
);
|
2021-06-07 21:16:35 -07:00
|
|
|
write!(w, "<summary>")
|
2021-04-27 15:26:14 +02:00
|
|
|
}
|
2021-06-07 21:16:35 -07:00
|
|
|
render_impl_summary(
|
2021-04-27 15:26:14 +02:00
|
|
|
w,
|
2021-06-07 21:16:35 -07:00
|
|
|
cx,
|
|
|
|
i,
|
2021-06-08 11:04:53 -07:00
|
|
|
parent,
|
2021-06-16 22:48:23 -07:00
|
|
|
parent,
|
2021-08-31 12:20:02 +02:00
|
|
|
rendering_params.show_def_docs,
|
2021-06-07 21:16:35 -07:00
|
|
|
use_absolute,
|
2021-08-31 12:20:02 +02:00
|
|
|
rendering_params.is_on_foreign_type,
|
2021-06-07 21:16:35 -07:00
|
|
|
aliases,
|
2021-04-27 15:26:14 +02:00
|
|
|
);
|
2021-06-07 21:16:35 -07:00
|
|
|
if toggled {
|
|
|
|
write!(w, "</summary>")
|
2021-04-27 15:26:14 +02:00
|
|
|
}
|
|
|
|
|
2021-06-08 10:39:57 -07:00
|
|
|
if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
|
|
|
|
let mut ids = cx.id_map.borrow_mut();
|
|
|
|
write!(
|
|
|
|
w,
|
|
|
|
"<div class=\"docblock\">{}</div>",
|
2021-10-04 21:08:58 -04:00
|
|
|
Markdown {
|
|
|
|
content: &*dox,
|
|
|
|
links: &i.impl_item.links(cx),
|
|
|
|
ids: &mut ids,
|
|
|
|
error_codes: cx.shared.codes,
|
|
|
|
edition: cx.shared.edition(),
|
|
|
|
playground: &cx.shared.playground,
|
2021-10-04 21:54:00 -04:00
|
|
|
heading_offset: HeadingOffset::H2
|
2021-10-04 21:08:58 -04:00
|
|
|
}
|
2021-06-08 10:39:57 -07:00
|
|
|
.into_string()
|
|
|
|
);
|
2021-04-27 15:26:14 +02:00
|
|
|
}
|
|
|
|
}
|
2021-06-01 21:36:03 +02:00
|
|
|
if !default_impl_items.is_empty() || !impl_items.is_empty() {
|
|
|
|
w.write_str("<div class=\"impl-items\">");
|
|
|
|
w.push_buffer(default_impl_items);
|
|
|
|
w.push_buffer(impl_items);
|
|
|
|
close_tags.insert_str(0, "</div>");
|
|
|
|
}
|
2021-04-17 23:43:20 -07:00
|
|
|
w.write_str(&close_tags);
|
2013-09-18 22:18:38 -07:00
|
|
|
}
|
|
|
|
|
2021-06-16 22:48:23 -07:00
|
|
|
// Render the items that appear on the right side of methods, impls, and
|
|
|
|
// associated types. For example "1.0.0 (const: 1.39.0) [src]".
|
2021-06-12 00:25:26 -07:00
|
|
|
fn render_rightside(
|
|
|
|
w: &mut Buffer,
|
|
|
|
cx: &Context<'_>,
|
|
|
|
item: &clean::Item,
|
2021-06-16 22:48:23 -07:00
|
|
|
containing_item: &clean::Item,
|
2021-06-12 00:25:26 -07:00
|
|
|
) {
|
|
|
|
let tcx = cx.tcx();
|
|
|
|
|
|
|
|
write!(w, "<div class=\"rightside\">");
|
|
|
|
render_stability_since_raw(
|
|
|
|
w,
|
|
|
|
item.stable_since(tcx).as_deref(),
|
2021-06-20 08:13:23 +08:00
|
|
|
item.const_stability(tcx),
|
2021-06-16 22:48:23 -07:00
|
|
|
containing_item.stable_since(tcx).as_deref(),
|
|
|
|
containing_item.const_stable_since(tcx).as_deref(),
|
2021-06-12 00:25:26 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
write_srclink(cx, item, w);
|
|
|
|
w.write_str("</div>");
|
|
|
|
}
|
|
|
|
|
2021-06-08 10:39:57 -07:00
|
|
|
pub(crate) fn render_impl_summary(
|
2021-06-07 21:16:35 -07:00
|
|
|
w: &mut Buffer,
|
|
|
|
cx: &Context<'_>,
|
|
|
|
i: &Impl,
|
2021-06-08 11:04:53 -07:00
|
|
|
parent: &clean::Item,
|
2021-06-16 22:48:23 -07:00
|
|
|
containing_item: &clean::Item,
|
2021-06-07 21:16:35 -07:00
|
|
|
show_def_docs: bool,
|
|
|
|
use_absolute: Option<bool>,
|
|
|
|
is_on_foreign_type: bool,
|
|
|
|
// This argument is used to reference same type with different paths to avoid duplication
|
|
|
|
// in documentation pages for trait with automatic implementations like "Send" and "Sync".
|
|
|
|
aliases: &[String],
|
|
|
|
) {
|
|
|
|
let id = cx.derive_id(match i.inner_impl().trait_ {
|
|
|
|
Some(ref t) => {
|
|
|
|
if is_on_foreign_type {
|
|
|
|
get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
|
|
|
|
} else {
|
|
|
|
format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => "impl".to_string(),
|
|
|
|
});
|
|
|
|
let aliases = if aliases.is_empty() {
|
|
|
|
String::new()
|
|
|
|
} else {
|
|
|
|
format!(" data-aliases=\"{}\"", aliases.join(","))
|
|
|
|
};
|
2021-06-12 00:25:26 -07:00
|
|
|
write!(w, "<div id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
|
2021-06-16 22:48:23 -07:00
|
|
|
render_rightside(w, cx, &i.impl_item, containing_item);
|
2021-06-16 22:47:46 -07:00
|
|
|
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
|
2021-07-25 21:41:57 +00:00
|
|
|
write!(w, "<h3 class=\"code-header in-band\">");
|
2021-06-12 00:25:26 -07:00
|
|
|
|
2021-06-07 21:16:35 -07:00
|
|
|
if let Some(use_absolute) = use_absolute {
|
|
|
|
write!(w, "{}", i.inner_impl().print(use_absolute, cx));
|
|
|
|
if show_def_docs {
|
|
|
|
for it in &i.inner_impl().items {
|
|
|
|
if let clean::TypedefItem(ref tydef, _) = *it.kind {
|
|
|
|
w.write_str("<span class=\"where fmt-newline\"> ");
|
|
|
|
assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "", cx);
|
|
|
|
w.write_str(";</span>");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-06-12 00:25:26 -07:00
|
|
|
write!(w, "{}", i.inner_impl().print(false, cx));
|
2021-06-07 21:16:35 -07:00
|
|
|
}
|
2021-07-25 21:41:57 +00:00
|
|
|
write!(w, "</h3>");
|
2021-06-08 11:04:53 -07:00
|
|
|
|
|
|
|
let is_trait = i.inner_impl().trait_.is_some();
|
|
|
|
if is_trait {
|
|
|
|
if let Some(portability) = portability(&i.impl_item, Some(parent)) {
|
|
|
|
write!(w, "<div class=\"item-info\">{}</div>", portability);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-07 21:16:35 -07:00
|
|
|
w.write_str("</div>");
|
|
|
|
}
|
|
|
|
|
2021-01-12 23:36:04 +01:00
|
|
|
fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
|
2019-12-22 17:42:04 -05:00
|
|
|
let parentlen = cx.current.len() - if it.is_mod() { 1 } else { 0 };
|
|
|
|
|
|
|
|
if it.is_struct()
|
|
|
|
|| it.is_trait()
|
|
|
|
|| it.is_primitive()
|
|
|
|
|| it.is_union()
|
|
|
|
|| it.is_enum()
|
|
|
|
|| it.is_mod()
|
|
|
|
|| it.is_typedef()
|
|
|
|
{
|
|
|
|
write!(
|
|
|
|
buffer,
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h2 class=\"location\">{}{}</h2>",
|
2020-12-13 11:32:57 -05:00
|
|
|
match *it.kind {
|
2019-08-31 11:34:37 -04:00
|
|
|
clean::StructItem(..) => "Struct ",
|
|
|
|
clean::TraitItem(..) => "Trait ",
|
|
|
|
clean::PrimitiveItem(..) => "Primitive Type ",
|
|
|
|
clean::UnionItem(..) => "Union ",
|
|
|
|
clean::EnumItem(..) => "Enum ",
|
|
|
|
clean::TypedefItem(..) => "Type Definition ",
|
|
|
|
clean::ForeignTypeItem => "Foreign Type ",
|
2019-12-22 17:42:04 -05:00
|
|
|
clean::ModuleItem(..) =>
|
|
|
|
if it.is_crate() {
|
|
|
|
"Crate "
|
|
|
|
} else {
|
|
|
|
"Module "
|
|
|
|
},
|
2019-08-31 11:34:37 -04:00
|
|
|
_ => "",
|
|
|
|
},
|
2019-12-22 17:42:04 -05:00
|
|
|
it.name.as_ref().unwrap()
|
|
|
|
);
|
2019-08-31 11:34:37 -04:00
|
|
|
}
|
2018-09-27 09:12:13 -05:00
|
|
|
|
2019-08-31 11:34:37 -04:00
|
|
|
if it.is_crate() {
|
2021-08-22 03:36:37 +00:00
|
|
|
if let Some(ref version) = cx.cache().crate_version {
|
2019-12-22 17:42:04 -05:00
|
|
|
write!(
|
|
|
|
buffer,
|
2020-10-16 00:52:49 +08:00
|
|
|
"<div class=\"block version\">\
|
2021-06-18 00:33:42 +02:00
|
|
|
<div class=\"narrow-helper\"></div>\
|
2020-08-31 13:16:50 +02:00
|
|
|
<p>Version {}</p>\
|
|
|
|
</div>",
|
2021-05-02 16:35:48 +02:00
|
|
|
Escape(version),
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
2019-08-31 11:34:37 -04:00
|
|
|
}
|
2016-11-21 15:52:51 -06:00
|
|
|
|
2021-01-30 01:02:18 +00:00
|
|
|
buffer.write_str("<div class=\"sidebar-elems\">");
|
2019-08-31 11:34:37 -04:00
|
|
|
if it.is_crate() {
|
2019-12-22 17:42:04 -05:00
|
|
|
write!(
|
|
|
|
buffer,
|
2020-10-16 00:52:49 +08:00
|
|
|
"<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>",
|
2021-05-02 16:35:48 +02:00
|
|
|
it.name.as_ref().expect("crates always have a name"),
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2019-08-31 11:34:37 -04:00
|
|
|
}
|
2021-05-02 16:35:48 +02:00
|
|
|
|
2020-12-13 11:32:57 -05:00
|
|
|
match *it.kind {
|
2020-12-31 02:45:15 +00:00
|
|
|
clean::StructItem(ref s) => sidebar_struct(cx, buffer, it, s),
|
|
|
|
clean::TraitItem(ref t) => sidebar_trait(cx, buffer, it, t),
|
|
|
|
clean::PrimitiveItem(_) => sidebar_primitive(cx, buffer, it),
|
|
|
|
clean::UnionItem(ref u) => sidebar_union(cx, buffer, it, u),
|
|
|
|
clean::EnumItem(ref e) => sidebar_enum(cx, buffer, it, e),
|
|
|
|
clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it),
|
2019-09-13 15:22:00 -04:00
|
|
|
clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
|
2020-12-31 02:45:15 +00:00
|
|
|
clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
|
2021-05-02 16:35:48 +02:00
|
|
|
_ => {}
|
2019-08-31 11:34:37 -04:00
|
|
|
}
|
2015-03-05 23:10:15 +09:00
|
|
|
|
2019-08-31 11:34:37 -04:00
|
|
|
// The sidebar is designed to display sibling functions, modules and
|
|
|
|
// other miscellaneous information. since there are lots of sibling
|
|
|
|
// items (and that causes quadratic growth in large modules),
|
|
|
|
// we refactor common parts into a shared JavaScript file per module.
|
|
|
|
// still, we don't move everything into JS because we want to preserve
|
|
|
|
// as much HTML as possible in order to allow non-JS-enabled browsers
|
|
|
|
// to navigate the documentation (though slightly inefficiently).
|
|
|
|
|
2021-05-02 16:35:48 +02:00
|
|
|
if !it.is_mod() {
|
2021-07-16 21:58:23 -07:00
|
|
|
buffer.write_str("<h2 class=\"location\">Other items in<br>");
|
2021-05-02 16:35:48 +02:00
|
|
|
for (i, name) in cx.current.iter().take(parentlen).enumerate() {
|
|
|
|
if i > 0 {
|
|
|
|
buffer.write_str("::<wbr>");
|
|
|
|
}
|
|
|
|
write!(
|
|
|
|
buffer,
|
|
|
|
"<a href=\"{}index.html\">{}</a>",
|
|
|
|
&cx.root_path()[..(cx.current.len() - i - 1) * 3],
|
|
|
|
*name
|
|
|
|
);
|
2019-08-31 11:34:37 -04:00
|
|
|
}
|
2021-07-16 21:58:23 -07:00
|
|
|
buffer.write_str("</h2>");
|
2013-09-18 22:18:38 -07:00
|
|
|
}
|
2019-08-31 11:34:37 -04:00
|
|
|
|
|
|
|
// Sidebar refers to the enclosing module, not this module.
|
2021-05-02 16:35:48 +02:00
|
|
|
let relpath = if it.is_mod() && parentlen != 0 { "./" } else { "" };
|
2019-12-22 17:42:04 -05:00
|
|
|
write!(
|
|
|
|
buffer,
|
2021-01-18 12:03:53 +01:00
|
|
|
"<div id=\"sidebar-vars\" data-name=\"{name}\" data-ty=\"{ty}\" data-relpath=\"{path}\">\
|
|
|
|
</div>",
|
2020-12-29 20:28:08 -05:00
|
|
|
name = it.name.unwrap_or(kw::Empty),
|
2019-12-22 17:42:04 -05:00
|
|
|
ty = it.type_(),
|
|
|
|
path = relpath
|
|
|
|
);
|
2021-05-02 16:35:48 +02:00
|
|
|
write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
|
2019-08-31 11:34:37 -04:00
|
|
|
// Closes sidebar-elems div.
|
2021-01-30 01:02:18 +00:00
|
|
|
buffer.write_str("</div>");
|
2019-08-31 11:34:37 -04:00
|
|
|
}
|
2013-09-18 22:18:38 -07:00
|
|
|
|
2018-11-04 21:35:09 +01:00
|
|
|
fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String {
|
|
|
|
if used_links.insert(url.clone()) {
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
let mut add = 1;
|
2020-02-24 16:52:40 +01:00
|
|
|
while !used_links.insert(format!("{}-{}", url, add)) {
|
2018-11-04 21:35:09 +01:00
|
|
|
add += 1;
|
|
|
|
}
|
|
|
|
format!("{}-{}", url, add)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_methods(
|
|
|
|
i: &clean::Impl,
|
|
|
|
for_deref: bool,
|
|
|
|
used_links: &mut FxHashSet<String>,
|
2019-07-18 23:38:23 +02:00
|
|
|
deref_mut: bool,
|
2021-08-27 16:49:14 -07:00
|
|
|
tcx: TyCtxt<'_>,
|
2018-11-04 21:35:09 +01:00
|
|
|
) -> Vec<String> {
|
2019-12-22 17:42:04 -05:00
|
|
|
i.items
|
|
|
|
.iter()
|
|
|
|
.filter_map(|item| match item.name {
|
2019-09-12 22:32:12 -04:00
|
|
|
Some(ref name) if !name.is_empty() && item.is_method() => {
|
2021-08-27 16:49:14 -07:00
|
|
|
if !for_deref || should_render_item(item, deref_mut, tcx) {
|
2019-12-22 17:42:04 -05:00
|
|
|
Some(format!(
|
|
|
|
"<a href=\"#{}\">{}</a>",
|
|
|
|
get_next_url(used_links, format!("method.{}", name)),
|
|
|
|
name
|
|
|
|
))
|
2017-10-28 01:11:01 +02:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2017-10-10 23:39:10 +02:00
|
|
|
}
|
|
|
|
_ => None,
|
2019-12-22 17:42:04 -05:00
|
|
|
})
|
|
|
|
.collect::<Vec<_>>()
|
2017-10-10 23:39:10 +02:00
|
|
|
}
|
|
|
|
|
2017-10-27 23:09:10 +02:00
|
|
|
// The point is to url encode any potential character from a type with genericity.
|
2021-01-30 01:02:18 +00:00
|
|
|
fn small_url_encode(s: String) -> String {
|
|
|
|
let mut st = String::new();
|
|
|
|
let mut last_match = 0;
|
|
|
|
for (idx, c) in s.char_indices() {
|
|
|
|
let escaped = match c {
|
|
|
|
'<' => "%3C",
|
|
|
|
'>' => "%3E",
|
|
|
|
' ' => "%20",
|
|
|
|
'?' => "%3F",
|
|
|
|
'\'' => "%27",
|
|
|
|
'&' => "%26",
|
|
|
|
',' => "%2C",
|
|
|
|
':' => "%3A",
|
|
|
|
';' => "%3B",
|
|
|
|
'[' => "%5B",
|
|
|
|
']' => "%5D",
|
|
|
|
'"' => "%22",
|
|
|
|
_ => continue,
|
|
|
|
};
|
|
|
|
|
|
|
|
st += &s[last_match..idx];
|
|
|
|
st += escaped;
|
|
|
|
// NOTE: we only expect single byte characters here - which is fine as long as we
|
|
|
|
// only match single byte characters
|
|
|
|
last_match = idx + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if last_match != 0 {
|
|
|
|
st += &s[last_match..];
|
|
|
|
st
|
|
|
|
} else {
|
|
|
|
s
|
|
|
|
}
|
2017-10-27 23:09:10 +02:00
|
|
|
}
|
|
|
|
|
2021-01-30 01:02:18 +00:00
|
|
|
fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
|
2021-06-26 17:10:52 +02:00
|
|
|
let did = it.def_id.expect_def_id();
|
2021-08-22 03:36:37 +00:00
|
|
|
let cache = cx.cache();
|
|
|
|
if let Some(v) = cache.impls.get(&did) {
|
2018-11-04 21:35:09 +01:00
|
|
|
let mut used_links = FxHashSet::default();
|
|
|
|
|
|
|
|
{
|
2019-09-13 14:25:56 -04:00
|
|
|
let used_links_bor = &mut used_links;
|
2019-12-22 17:42:04 -05:00
|
|
|
let mut ret = v
|
|
|
|
.iter()
|
|
|
|
.filter(|i| i.inner_impl().trait_.is_none())
|
2021-08-27 16:49:14 -07:00
|
|
|
.flat_map(move |i| {
|
|
|
|
get_methods(i.inner_impl(), false, used_links_bor, false, cx.tcx())
|
|
|
|
})
|
2019-12-22 17:42:04 -05:00
|
|
|
.collect::<Vec<_>>();
|
2018-11-04 21:35:09 +01:00
|
|
|
if !ret.is_empty() {
|
2020-05-27 11:46:23 +02:00
|
|
|
// We want links' order to be reproducible so we don't use unstable sort.
|
|
|
|
ret.sort();
|
2021-01-30 01:02:18 +00:00
|
|
|
|
|
|
|
out.push_str(
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#implementations\">Methods</a></h3>\
|
2021-01-30 01:02:18 +00:00
|
|
|
<div class=\"sidebar-links\">",
|
|
|
|
);
|
|
|
|
for line in ret {
|
|
|
|
out.push_str(&line);
|
|
|
|
}
|
|
|
|
out.push_str("</div>");
|
2018-11-04 21:35:09 +01:00
|
|
|
}
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
|
2021-08-21 20:58:23 -07:00
|
|
|
if let Some(impl_) = v.iter().filter(|i| i.inner_impl().trait_.is_some()).find(|i| {
|
|
|
|
i.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait()
|
|
|
|
}) {
|
2021-06-22 18:18:54 -07:00
|
|
|
sidebar_deref_methods(cx, out, impl_, v);
|
|
|
|
}
|
|
|
|
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
let format_impls = |impls: Vec<&Impl>| {
|
2018-08-18 13:55:43 +03:00
|
|
|
let mut links = FxHashSet::default();
|
2018-11-04 21:35:09 +01:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
let mut ret = impls
|
|
|
|
.iter()
|
2021-01-08 22:54:35 +01:00
|
|
|
.filter_map(|it| {
|
|
|
|
if let Some(ref i) = it.inner_impl().trait_ {
|
2021-03-17 11:41:01 -07:00
|
|
|
let i_display = format!("{:#}", i.print(cx));
|
2019-02-04 12:38:26 +01:00
|
|
|
let out = Escape(&i_display);
|
2021-03-17 11:41:01 -07:00
|
|
|
let encoded = small_url_encode(format!("{:#}", i.print(cx)));
|
2019-12-22 17:42:04 -05:00
|
|
|
let generated = format!(
|
|
|
|
"<a href=\"#impl-{}\">{}{}</a>",
|
|
|
|
encoded,
|
2021-01-08 22:54:35 +01:00
|
|
|
if it.inner_impl().negative_polarity { "!" } else { "" },
|
2019-12-22 17:42:04 -05:00
|
|
|
out
|
|
|
|
);
|
|
|
|
if links.insert(generated.clone()) { Some(generated) } else { None }
|
2019-02-04 12:38:26 +01:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<Vec<String>>();
|
|
|
|
ret.sort();
|
2021-01-30 01:02:18 +00:00
|
|
|
ret
|
|
|
|
};
|
|
|
|
|
|
|
|
let write_sidebar_links = |out: &mut Buffer, links: Vec<String>| {
|
|
|
|
out.push_str("<div class=\"sidebar-links\">");
|
|
|
|
for link in links {
|
|
|
|
out.push_str(&link);
|
|
|
|
}
|
|
|
|
out.push_str("</div>");
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
};
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
|
|
|
|
v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().synthetic);
|
2018-07-27 22:59:16 +02:00
|
|
|
let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = concrete
|
|
|
|
.into_iter()
|
|
|
|
.partition::<Vec<_>, _>(|i| i.inner_impl().blanket_impl.is_some());
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
|
|
|
|
let concrete_format = format_impls(concrete);
|
|
|
|
let synthetic_format = format_impls(synthetic);
|
2018-07-27 22:59:16 +02:00
|
|
|
let blanket_format = format_impls(blanket_impl);
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
|
|
|
|
if !concrete_format.is_empty() {
|
2019-12-22 17:42:04 -05:00
|
|
|
out.push_str(
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#trait-implementations\">\
|
|
|
|
Trait Implementations</a></h3>",
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2021-01-30 01:02:18 +00:00
|
|
|
write_sidebar_links(out, concrete_format);
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if !synthetic_format.is_empty() {
|
2019-12-22 17:42:04 -05:00
|
|
|
out.push_str(
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#synthetic-implementations\">\
|
|
|
|
Auto Trait Implementations</a></h3>",
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2021-01-30 01:02:18 +00:00
|
|
|
write_sidebar_links(out, synthetic_format);
|
2017-10-10 23:39:10 +02:00
|
|
|
}
|
2018-07-27 22:59:16 +02:00
|
|
|
|
|
|
|
if !blanket_format.is_empty() {
|
2019-12-22 17:42:04 -05:00
|
|
|
out.push_str(
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#blanket-implementations\">\
|
|
|
|
Blanket Implementations</a></h3>",
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
2021-01-30 01:02:18 +00:00
|
|
|
write_sidebar_links(out, blanket_format);
|
2018-07-27 22:59:16 +02:00
|
|
|
}
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-30 01:02:18 +00:00
|
|
|
fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec<Impl>) {
|
2021-01-12 23:36:04 +01:00
|
|
|
let c = cx.cache();
|
2020-12-29 07:58:32 +00:00
|
|
|
|
|
|
|
debug!("found Deref: {:?}", impl_);
|
|
|
|
if let Some((target, real_target)) =
|
|
|
|
impl_.inner_impl().items.iter().find_map(|item| match *item.kind {
|
|
|
|
clean::TypedefItem(ref t, true) => Some(match *t {
|
|
|
|
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
|
|
|
|
_ => (&t.type_, &t.type_),
|
|
|
|
}),
|
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
{
|
|
|
|
debug!("found target, real_target: {:?} {:?}", target, real_target);
|
2021-03-07 23:11:12 +01:00
|
|
|
if let Some(did) = target.def_id_full(c) {
|
|
|
|
if let Some(type_did) = impl_.inner_impl().for_.def_id_full(c) {
|
2021-01-28 22:03:20 +00:00
|
|
|
// `impl Deref<Target = S> for S`
|
|
|
|
if did == type_did {
|
|
|
|
// Avoid infinite cycles
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-21 20:58:23 -07:00
|
|
|
let deref_mut = v.iter().filter(|i| i.inner_impl().trait_.is_some()).any(|i| {
|
|
|
|
i.inner_impl().trait_.def_id_full(c) == cx.tcx().lang_items().deref_mut_trait()
|
|
|
|
});
|
2020-12-29 07:58:32 +00:00
|
|
|
let inner_impl = target
|
2021-03-07 23:11:12 +01:00
|
|
|
.def_id_full(c)
|
2020-12-29 07:58:32 +00:00
|
|
|
.or_else(|| {
|
|
|
|
target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned())
|
|
|
|
})
|
|
|
|
.and_then(|did| c.impls.get(&did));
|
|
|
|
if let Some(impls) = inner_impl {
|
|
|
|
debug!("found inner_impl: {:?}", impls);
|
|
|
|
let mut used_links = FxHashSet::default();
|
|
|
|
let mut ret = impls
|
|
|
|
.iter()
|
|
|
|
.filter(|i| i.inner_impl().trait_.is_none())
|
2021-08-27 16:49:14 -07:00
|
|
|
.flat_map(|i| {
|
|
|
|
get_methods(i.inner_impl(), true, &mut used_links, deref_mut, cx.tcx())
|
|
|
|
})
|
2020-12-29 07:58:32 +00:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
if !ret.is_empty() {
|
2021-01-30 01:02:18 +00:00
|
|
|
write!(
|
|
|
|
out,
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#deref-methods\">Methods from {}<Target={}></a></h3>",
|
2021-03-17 11:41:01 -07:00
|
|
|
Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
|
|
|
|
Escape(&format!("{:#}", real_target.print(cx))),
|
2021-01-30 01:02:18 +00:00
|
|
|
);
|
2020-12-31 02:45:15 +00:00
|
|
|
// We want links' order to be reproducible so we don't use unstable sort.
|
|
|
|
ret.sort();
|
2021-01-30 01:02:18 +00:00
|
|
|
out.push_str("<div class=\"sidebar-links\">");
|
|
|
|
for link in ret {
|
|
|
|
out.push_str(&link);
|
|
|
|
}
|
|
|
|
out.push_str("</div>");
|
2020-12-29 07:58:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-31 02:45:15 +00:00
|
|
|
fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) {
|
2021-01-30 01:02:18 +00:00
|
|
|
let mut sidebar = Buffer::new();
|
2017-11-04 20:45:12 +01:00
|
|
|
let fields = get_struct_fields_name(&s.fields);
|
2016-11-21 15:52:51 -06:00
|
|
|
|
2017-11-04 20:45:12 +01:00
|
|
|
if !fields.is_empty() {
|
2021-01-20 17:19:46 -05:00
|
|
|
if let CtorKind::Fictive = s.struct_type {
|
2021-01-30 01:02:18 +00:00
|
|
|
sidebar.push_str(
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#fields\">Fields</a></h3>\
|
2021-01-30 01:02:18 +00:00
|
|
|
<div class=\"sidebar-links\">",
|
|
|
|
);
|
|
|
|
|
|
|
|
for field in fields {
|
|
|
|
sidebar.push_str(&field);
|
|
|
|
}
|
|
|
|
|
|
|
|
sidebar.push_str("</div>");
|
2021-07-25 14:48:57 +02:00
|
|
|
} else if let CtorKind::Fn = s.struct_type {
|
|
|
|
sidebar
|
|
|
|
.push_str("<h3 class=\"sidebar-title\"><a href=\"#fields\">Tuple Fields</a></h3>");
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-30 01:02:18 +00:00
|
|
|
sidebar_assoc_items(cx, &mut sidebar, it);
|
2016-11-21 15:52:51 -06:00
|
|
|
|
|
|
|
if !sidebar.is_empty() {
|
2021-01-30 01:02:18 +00:00
|
|
|
write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-12 23:36:04 +01:00
|
|
|
fn get_id_for_impl_on_foreign_type(
|
|
|
|
for_: &clean::Type,
|
|
|
|
trait_: &clean::Type,
|
2021-03-17 11:41:01 -07:00
|
|
|
cx: &Context<'_>,
|
2021-01-12 23:36:04 +01:00
|
|
|
) -> String {
|
2021-03-17 11:41:01 -07:00
|
|
|
small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx),))
|
2019-04-26 17:06:20 +03:00
|
|
|
}
|
|
|
|
|
2021-03-17 11:41:01 -07:00
|
|
|
fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
|
2020-12-13 11:32:57 -05:00
|
|
|
match *item.kind {
|
2020-11-14 03:45:10 -05:00
|
|
|
clean::ItemKind::ImplItem(ref i) => {
|
2017-11-04 20:45:12 +01:00
|
|
|
if let Some(ref trait_) = i.trait_ {
|
2021-03-17 11:41:01 -07:00
|
|
|
// Alternative format produces no URLs,
|
|
|
|
// so this parameter does nothing.
|
2019-09-12 19:59:14 -04:00
|
|
|
Some((
|
2021-03-17 11:41:01 -07:00
|
|
|
format!("{:#}", i.for_.print(cx)),
|
|
|
|
get_id_for_impl_on_foreign_type(&i.for_, trait_, cx),
|
2019-09-12 19:59:14 -04:00
|
|
|
))
|
2017-11-04 20:45:12 +01:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2017-11-04 20:45:12 +01:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-31 02:45:15 +00:00
|
|
|
fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
|
2021-01-30 01:02:18 +00:00
|
|
|
buf.write_str("<div class=\"block items\">");
|
|
|
|
|
|
|
|
fn print_sidebar_section(
|
|
|
|
out: &mut Buffer,
|
|
|
|
items: &[clean::Item],
|
|
|
|
before: &str,
|
|
|
|
filter: impl Fn(&clean::Item) -> bool,
|
2021-03-23 17:36:36 +01:00
|
|
|
write: impl Fn(&mut Buffer, &str),
|
2021-01-30 01:02:18 +00:00
|
|
|
after: &str,
|
|
|
|
) {
|
|
|
|
let mut items = items
|
|
|
|
.iter()
|
|
|
|
.filter_map(|m| match m.name {
|
2021-03-23 17:36:36 +01:00
|
|
|
Some(ref name) if filter(m) => Some(name.as_str()),
|
2021-01-30 01:02:18 +00:00
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
2016-11-21 15:52:51 -06:00
|
|
|
|
2021-01-30 01:02:18 +00:00
|
|
|
if !items.is_empty() {
|
2021-03-12 12:19:31 +01:00
|
|
|
items.sort_unstable();
|
2021-01-30 01:02:18 +00:00
|
|
|
out.push_str(before);
|
|
|
|
for item in items.into_iter() {
|
2021-03-23 17:36:36 +01:00
|
|
|
write(out, &item);
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2021-01-30 01:02:18 +00:00
|
|
|
out.push_str(after);
|
|
|
|
}
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
|
2021-01-30 01:02:18 +00:00
|
|
|
print_sidebar_section(
|
|
|
|
buf,
|
|
|
|
&t.items,
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#associated-types\">\
|
|
|
|
Associated Types</a></h3><div class=\"sidebar-links\">",
|
2021-01-30 01:02:18 +00:00
|
|
|
|m| m.is_associated_type(),
|
|
|
|
|out, sym| write!(out, "<a href=\"#associatedtype.{0}\">{0}</a>", sym),
|
|
|
|
"</div>",
|
|
|
|
);
|
|
|
|
|
|
|
|
print_sidebar_section(
|
|
|
|
buf,
|
|
|
|
&t.items,
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#associated-const\">\
|
|
|
|
Associated Constants</a></h3><div class=\"sidebar-links\">",
|
2021-01-30 01:02:18 +00:00
|
|
|
|m| m.is_associated_const(),
|
|
|
|
|out, sym| write!(out, "<a href=\"#associatedconstant.{0}\">{0}</a>", sym),
|
|
|
|
"</div>",
|
|
|
|
);
|
|
|
|
|
|
|
|
print_sidebar_section(
|
|
|
|
buf,
|
|
|
|
&t.items,
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#required-methods\">\
|
|
|
|
Required Methods</a></h3><div class=\"sidebar-links\">",
|
2021-01-30 01:02:18 +00:00
|
|
|
|m| m.is_ty_method(),
|
|
|
|
|out, sym| write!(out, "<a href=\"#tymethod.{0}\">{0}</a>", sym),
|
|
|
|
"</div>",
|
|
|
|
);
|
|
|
|
|
|
|
|
print_sidebar_section(
|
|
|
|
buf,
|
|
|
|
&t.items,
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#provided-methods\">\
|
|
|
|
Provided Methods</a></h3><div class=\"sidebar-links\">",
|
2021-01-30 01:02:18 +00:00
|
|
|
|m| m.is_method(),
|
|
|
|
|out, sym| write!(out, "<a href=\"#method.{0}\">{0}</a>", sym),
|
|
|
|
"</div>",
|
|
|
|
);
|
|
|
|
|
2021-08-22 03:36:37 +00:00
|
|
|
let cache = cx.cache();
|
|
|
|
if let Some(implementors) = cache.implementors.get(&it.def_id.expect_def_id()) {
|
2019-12-22 17:42:04 -05:00
|
|
|
let mut res = implementors
|
|
|
|
.iter()
|
2021-01-12 23:36:04 +01:00
|
|
|
.filter(|i| {
|
|
|
|
i.inner_impl()
|
|
|
|
.for_
|
2021-03-07 23:11:12 +01:00
|
|
|
.def_id_full(cache)
|
2021-08-22 03:36:37 +00:00
|
|
|
.map_or(false, |d| !cache.paths.contains_key(&d))
|
2021-01-12 23:36:04 +01:00
|
|
|
})
|
2021-03-17 11:41:01 -07:00
|
|
|
.filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
|
2020-05-06 11:13:00 +02:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
2017-11-04 20:45:12 +01:00
|
|
|
if !res.is_empty() {
|
2019-02-04 12:38:26 +01:00
|
|
|
res.sort();
|
2021-01-30 01:02:18 +00:00
|
|
|
buf.push_str(
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#foreign-impls\">\
|
|
|
|
Implementations on Foreign Types</a></h3>\
|
2021-01-30 01:02:18 +00:00
|
|
|
<div class=\"sidebar-links\">",
|
|
|
|
);
|
|
|
|
for (name, id) in res.into_iter() {
|
|
|
|
write!(buf, "<a href=\"#{}\">{}</a>", id, Escape(&name));
|
|
|
|
}
|
|
|
|
buf.push_str("</div>");
|
2017-11-04 20:45:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-30 01:02:18 +00:00
|
|
|
sidebar_assoc_items(cx, buf, it);
|
2020-06-15 15:25:24 +02:00
|
|
|
|
2021-07-16 21:58:23 -07:00
|
|
|
buf.push_str("<h3 class=\"sidebar-title\"><a href=\"#implementors\">Implementors</a></h3>");
|
2020-11-17 00:34:38 -05:00
|
|
|
if t.is_auto {
|
2021-01-30 01:02:18 +00:00
|
|
|
buf.push_str(
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a \
|
|
|
|
href=\"#synthetic-implementors\">Auto Implementors</a></h3>",
|
2019-12-22 17:42:04 -05:00
|
|
|
);
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
}
|
2016-11-21 15:52:51 -06:00
|
|
|
|
2021-01-30 01:02:18 +00:00
|
|
|
buf.push_str("</div>")
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
|
2020-12-31 02:45:15 +00:00
|
|
|
fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
|
2021-01-30 01:02:18 +00:00
|
|
|
let mut sidebar = Buffer::new();
|
|
|
|
sidebar_assoc_items(cx, &mut sidebar, it);
|
2016-11-21 15:52:51 -06:00
|
|
|
|
|
|
|
if !sidebar.is_empty() {
|
2021-01-30 01:02:18 +00:00
|
|
|
write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-31 02:45:15 +00:00
|
|
|
fn sidebar_typedef(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
|
2021-01-30 01:02:18 +00:00
|
|
|
let mut sidebar = Buffer::new();
|
|
|
|
sidebar_assoc_items(cx, &mut sidebar, it);
|
Document direct implementations on type aliases.
This improves #32077, but is not a complete fix. For a type alias `type
NewType = AliasedType`, it will include any `impl NewType` and `impl
Trait for NewType` blocks in the documentation for `NewType`.
A complete fix would include the implementations from the aliased type
in the type alias' documentation, so that users have a complete
picture of methods that are available on the alias. However, to do this
properly would require a fix for #14072, as the alias may affect the
type parameters of the type alias, making the documentation difficult to
understand. (That is, for `type Result = std::result::Result<(), ()>` we
would ideally show documentation for `impl Result<(), ()>`, rather than
generic documentation for `impl<T, E> Result<T, E>`).
I think this improvement is worthwhile, as it exposes implementations
which are not currently documented by rustdoc. The documentation for the
implementations on the aliased type are still accessible by clicking
through to the docs for that type. (Although perhaps it's now less
obvious to the user that they should click-through to get there).
2017-05-16 13:16:44 +07:00
|
|
|
|
|
|
|
if !sidebar.is_empty() {
|
2021-01-30 01:02:18 +00:00
|
|
|
write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
|
Document direct implementations on type aliases.
This improves #32077, but is not a complete fix. For a type alias `type
NewType = AliasedType`, it will include any `impl NewType` and `impl
Trait for NewType` blocks in the documentation for `NewType`.
A complete fix would include the implementations from the aliased type
in the type alias' documentation, so that users have a complete
picture of methods that are available on the alias. However, to do this
properly would require a fix for #14072, as the alias may affect the
type parameters of the type alias, making the documentation difficult to
understand. (That is, for `type Result = std::result::Result<(), ()>` we
would ideally show documentation for `impl Result<(), ()>`, rather than
generic documentation for `impl<T, E> Result<T, E>`).
I think this improvement is worthwhile, as it exposes implementations
which are not currently documented by rustdoc. The documentation for the
implementations on the aliased type are still accessible by clicking
through to the docs for that type. (Although perhaps it's now less
obvious to the user that they should click-through to get there).
2017-05-16 13:16:44 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-30 01:02:18 +00:00
|
|
|
fn get_struct_fields_name(fields: &[clean::Item]) -> Vec<String> {
|
2020-05-27 11:46:23 +02:00
|
|
|
let mut fields = fields
|
2019-12-22 17:42:04 -05:00
|
|
|
.iter()
|
2020-12-13 11:32:57 -05:00
|
|
|
.filter(|f| matches!(*f.kind, clean::StructFieldItem(..)))
|
2021-01-30 01:02:18 +00:00
|
|
|
.filter_map(|f| {
|
|
|
|
f.name.map(|name| format!("<a href=\"#structfield.{name}\">{name}</a>", name = name))
|
2019-12-22 17:42:04 -05:00
|
|
|
})
|
2020-05-27 11:46:23 +02:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
fields.sort();
|
2021-01-30 01:02:18 +00:00
|
|
|
fields
|
2017-11-04 20:45:12 +01:00
|
|
|
}
|
|
|
|
|
2020-12-31 02:45:15 +00:00
|
|
|
fn sidebar_union(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, u: &clean::Union) {
|
2021-01-30 01:02:18 +00:00
|
|
|
let mut sidebar = Buffer::new();
|
2017-11-04 20:45:12 +01:00
|
|
|
let fields = get_struct_fields_name(&u.fields);
|
2016-11-21 15:52:51 -06:00
|
|
|
|
2017-11-04 20:45:12 +01:00
|
|
|
if !fields.is_empty() {
|
2021-01-30 01:02:18 +00:00
|
|
|
sidebar.push_str(
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#fields\">Fields</a></h3>\
|
2021-01-30 01:02:18 +00:00
|
|
|
<div class=\"sidebar-links\">",
|
|
|
|
);
|
|
|
|
|
|
|
|
for field in fields {
|
|
|
|
sidebar.push_str(&field);
|
|
|
|
}
|
|
|
|
|
|
|
|
sidebar.push_str("</div>");
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
|
2021-01-30 01:02:18 +00:00
|
|
|
sidebar_assoc_items(cx, &mut sidebar, it);
|
2016-11-21 15:52:51 -06:00
|
|
|
|
|
|
|
if !sidebar.is_empty() {
|
2021-01-30 01:02:18 +00:00
|
|
|
write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-31 02:45:15 +00:00
|
|
|
fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) {
|
2021-01-30 01:02:18 +00:00
|
|
|
let mut sidebar = Buffer::new();
|
2016-11-21 15:52:51 -06:00
|
|
|
|
2020-05-27 11:46:23 +02:00
|
|
|
let mut variants = e
|
2019-12-22 17:42:04 -05:00
|
|
|
.variants
|
|
|
|
.iter()
|
|
|
|
.filter_map(|v| match v.name {
|
2020-05-27 11:46:23 +02:00
|
|
|
Some(ref name) => Some(format!("<a href=\"#variant.{name}\">{name}</a>", name = name)),
|
2019-12-22 17:42:04 -05:00
|
|
|
_ => None,
|
|
|
|
})
|
2020-05-27 11:46:23 +02:00
|
|
|
.collect::<Vec<_>>();
|
2017-11-04 20:45:12 +01:00
|
|
|
if !variants.is_empty() {
|
2020-05-27 11:46:23 +02:00
|
|
|
variants.sort_unstable();
|
2019-12-22 17:42:04 -05:00
|
|
|
sidebar.push_str(&format!(
|
2021-07-16 21:58:23 -07:00
|
|
|
"<h3 class=\"sidebar-title\"><a href=\"#variants\">Variants</a></h3>\
|
2020-05-27 11:46:23 +02:00
|
|
|
<div class=\"sidebar-links\">{}</div>",
|
|
|
|
variants.join(""),
|
2019-12-22 17:42:04 -05:00
|
|
|
));
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
|
2021-01-30 01:02:18 +00:00
|
|
|
sidebar_assoc_items(cx, &mut sidebar, it);
|
2016-11-21 15:52:51 -06:00
|
|
|
|
|
|
|
if !sidebar.is_empty() {
|
2021-01-30 01:02:18 +00:00
|
|
|
write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-02 16:35:48 +02:00
|
|
|
fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) {
|
|
|
|
match ty {
|
2019-12-22 17:42:04 -05:00
|
|
|
ItemType::ExternCrate | ItemType::Import => ("reexports", "Re-exports"),
|
|
|
|
ItemType::Module => ("modules", "Modules"),
|
|
|
|
ItemType::Struct => ("structs", "Structs"),
|
|
|
|
ItemType::Union => ("unions", "Unions"),
|
|
|
|
ItemType::Enum => ("enums", "Enums"),
|
|
|
|
ItemType::Function => ("functions", "Functions"),
|
|
|
|
ItemType::Typedef => ("types", "Type Definitions"),
|
|
|
|
ItemType::Static => ("statics", "Statics"),
|
|
|
|
ItemType::Constant => ("constants", "Constants"),
|
|
|
|
ItemType::Trait => ("traits", "Traits"),
|
|
|
|
ItemType::Impl => ("impls", "Implementations"),
|
|
|
|
ItemType::TyMethod => ("tymethods", "Type Methods"),
|
|
|
|
ItemType::Method => ("methods", "Methods"),
|
|
|
|
ItemType::StructField => ("fields", "Struct Fields"),
|
|
|
|
ItemType::Variant => ("variants", "Variants"),
|
|
|
|
ItemType::Macro => ("macros", "Macros"),
|
|
|
|
ItemType::Primitive => ("primitives", "Primitive Types"),
|
|
|
|
ItemType::AssocType => ("associated-types", "Associated Types"),
|
|
|
|
ItemType::AssocConst => ("associated-consts", "Associated Constants"),
|
|
|
|
ItemType::ForeignType => ("foreign-types", "Foreign Types"),
|
|
|
|
ItemType::Keyword => ("keywords", "Keywords"),
|
|
|
|
ItemType::OpaqueTy => ("opaque-types", "Opaque Types"),
|
|
|
|
ItemType::ProcAttribute => ("attributes", "Attribute Macros"),
|
|
|
|
ItemType::ProcDerive => ("derives", "Derive Macros"),
|
|
|
|
ItemType::TraitAlias => ("trait-aliases", "Trait aliases"),
|
2018-05-28 21:30:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-13 15:22:00 -04:00
|
|
|
fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
|
2016-11-21 15:52:51 -06:00
|
|
|
let mut sidebar = String::new();
|
|
|
|
|
2021-05-02 16:35:48 +02:00
|
|
|
// Re-exports are handled a bit differently because they can be extern crates or imports.
|
2020-09-29 17:04:40 +02:00
|
|
|
if items.iter().any(|it| {
|
2021-05-02 16:35:48 +02:00
|
|
|
it.name.is_some()
|
|
|
|
&& (it.type_() == ItemType::ExternCrate
|
|
|
|
|| (it.type_() == ItemType::Import && !it.is_stripped()))
|
2020-09-29 17:04:40 +02:00
|
|
|
}) {
|
2021-05-02 16:35:48 +02:00
|
|
|
let (id, name) = item_ty_to_strs(ItemType::Import);
|
|
|
|
sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// ordering taken from item_module, reorder, where it prioritized elements in a certain order
|
|
|
|
// to print its headings
|
2019-12-22 17:42:04 -05:00
|
|
|
for &myty in &[
|
|
|
|
ItemType::Primitive,
|
|
|
|
ItemType::Module,
|
|
|
|
ItemType::Macro,
|
|
|
|
ItemType::Struct,
|
|
|
|
ItemType::Enum,
|
|
|
|
ItemType::Constant,
|
|
|
|
ItemType::Static,
|
|
|
|
ItemType::Trait,
|
|
|
|
ItemType::Function,
|
|
|
|
ItemType::Typedef,
|
|
|
|
ItemType::Union,
|
|
|
|
ItemType::Impl,
|
|
|
|
ItemType::TyMethod,
|
|
|
|
ItemType::Method,
|
|
|
|
ItemType::StructField,
|
|
|
|
ItemType::Variant,
|
|
|
|
ItemType::AssocType,
|
|
|
|
ItemType::AssocConst,
|
|
|
|
ItemType::ForeignType,
|
|
|
|
ItemType::Keyword,
|
|
|
|
] {
|
2021-05-02 16:35:48 +02:00
|
|
|
if items.iter().any(|it| !it.is_stripped() && it.type_() == myty && it.name.is_some()) {
|
|
|
|
let (id, name) = item_ty_to_strs(myty);
|
|
|
|
sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !sidebar.is_empty() {
|
2019-08-31 09:07:29 -04:00
|
|
|
write!(buf, "<div class=\"block items\"><ul>{}</ul></div>", sidebar);
|
2016-11-21 15:52:51 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-31 02:45:15 +00:00
|
|
|
fn sidebar_foreign_type(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
|
2021-01-30 01:02:18 +00:00
|
|
|
let mut sidebar = Buffer::new();
|
|
|
|
sidebar_assoc_items(cx, &mut sidebar, it);
|
|
|
|
|
2017-11-15 17:31:23 +08:00
|
|
|
if !sidebar.is_empty() {
|
2021-01-30 01:02:18 +00:00
|
|
|
write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
|
2017-11-15 17:31:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-05 11:33:05 +01:00
|
|
|
crate const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang";
|
2014-08-04 14:30:06 -07:00
|
|
|
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
/// Returns a list of all paths used in the type.
|
|
|
|
/// This is used to help deduplicate imported impls
|
|
|
|
/// for reexported types. If any of the contained
|
|
|
|
/// types are re-exported, we don't use the corresponding
|
|
|
|
/// entry from the js file, as inlining will have already
|
|
|
|
/// picked up the impl
|
2021-01-12 23:36:04 +01:00
|
|
|
fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
let mut out = Vec::new();
|
2018-10-16 10:44:26 +02:00
|
|
|
let mut visited = FxHashSet::default();
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
let mut work = VecDeque::new();
|
|
|
|
|
|
|
|
work.push_back(first_ty);
|
|
|
|
|
|
|
|
while let Some(ty) = work.pop_front() {
|
|
|
|
if !visited.insert(ty.clone()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
match ty {
|
|
|
|
clean::Type::ResolvedPath { did, .. } => {
|
|
|
|
let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
|
|
|
|
let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
|
|
|
|
|
2020-03-29 20:19:14 +02:00
|
|
|
if let Some(path) = fqp {
|
|
|
|
out.push(path.join("::"));
|
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
clean::Type::Tuple(tys) => {
|
|
|
|
work.extend(tys.into_iter());
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
clean::Type::Slice(ty) => {
|
|
|
|
work.push_back(*ty);
|
|
|
|
}
|
|
|
|
clean::Type::Array(ty, _) => {
|
|
|
|
work.push_back(*ty);
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
clean::Type::RawPointer(_, ty) => {
|
|
|
|
work.push_back(*ty);
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
clean::Type::BorrowedRef { type_, .. } => {
|
|
|
|
work.push_back(*type_);
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
clean::Type::QPath { self_type, trait_, .. } => {
|
|
|
|
work.push_back(*self_type);
|
|
|
|
work.push_back(*trait_);
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
_ => {}
|
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
out
|
|
|
|
}
|
2021-05-09 16:22:22 -07:00
|
|
|
|
2021-06-02 17:21:48 -07:00
|
|
|
const MAX_FULL_EXAMPLES: usize = 5;
|
2021-10-07 09:46:18 -07:00
|
|
|
const NUM_VISIBLE_LINES: usize = 10;
|
2021-06-02 17:21:48 -07:00
|
|
|
|
2021-08-25 20:15:46 -07:00
|
|
|
/// Generates the HTML for example call locations generated via the --scrape-examples flag.
|
2021-09-16 18:12:45 -07:00
|
|
|
fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, def_id: DefId, item: &clean::Item) {
|
|
|
|
let tcx = cx.tcx();
|
2021-09-21 15:49:36 -07:00
|
|
|
let key = tcx.def_path_hash(def_id);
|
2021-09-16 18:12:45 -07:00
|
|
|
let call_locations = match cx.shared.call_locations.get(&key) {
|
|
|
|
Some(call_locations) => call_locations,
|
2021-08-25 20:15:46 -07:00
|
|
|
_ => {
|
2021-05-09 16:22:22 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-08-25 20:15:46 -07:00
|
|
|
// Generate a unique ID so users can link to this section for a given method
|
2021-05-09 16:22:22 -07:00
|
|
|
let id = cx.id_map.borrow_mut().derive("scraped-examples");
|
|
|
|
write!(
|
|
|
|
w,
|
2021-09-21 15:49:36 -07:00
|
|
|
"<div class=\"docblock scraped-example-list\">\
|
2021-10-07 10:27:09 -07:00
|
|
|
<span></span>\
|
2021-10-07 09:46:18 -07:00
|
|
|
<h5 id=\"{id}\" class=\"section-header\">\
|
|
|
|
<a href=\"#{id}\">Examples found in repository</a>\
|
2021-10-06 21:43:40 -07:00
|
|
|
</h5>",
|
2021-10-07 09:46:18 -07:00
|
|
|
id = id
|
2021-05-09 16:22:22 -07:00
|
|
|
);
|
|
|
|
|
2021-08-25 20:15:46 -07:00
|
|
|
// Generate the HTML for a single example, being the title and code block
|
2021-09-13 18:08:14 -07:00
|
|
|
let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool {
|
|
|
|
let contents = match fs::read_to_string(&path) {
|
|
|
|
Ok(contents) => contents,
|
|
|
|
Err(err) => {
|
|
|
|
let span = item.span(tcx).inner();
|
|
|
|
tcx.sess
|
|
|
|
.span_err(span, &format!("failed to read file {}: {}", path.display(), err));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
2021-06-02 17:21:48 -07:00
|
|
|
|
2021-08-25 20:15:46 -07:00
|
|
|
// To reduce file sizes, we only want to embed the source code needed to understand the example, not
|
|
|
|
// the entire file. So we find the smallest byte range that covers all items enclosing examples.
|
2021-09-16 18:12:45 -07:00
|
|
|
assert!(!call_data.locations.is_empty());
|
2021-06-02 17:21:48 -07:00
|
|
|
let min_loc =
|
2021-08-26 14:43:12 -07:00
|
|
|
call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
|
2021-10-07 09:46:18 -07:00
|
|
|
let byte_min = min_loc.enclosing_item.byte_span.0;
|
|
|
|
let line_min = min_loc.enclosing_item.line_span.0;
|
|
|
|
let max_loc =
|
|
|
|
call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap();
|
|
|
|
let byte_max = max_loc.enclosing_item.byte_span.1;
|
|
|
|
let line_max = max_loc.enclosing_item.line_span.1;
|
2021-06-02 17:21:48 -07:00
|
|
|
|
2021-08-25 20:15:46 -07:00
|
|
|
// The output code is limited to that byte range.
|
2021-10-07 09:46:18 -07:00
|
|
|
let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
|
2021-08-25 20:15:46 -07:00
|
|
|
|
|
|
|
// The call locations need to be updated to reflect that the size of the program has changed.
|
2021-10-07 09:46:18 -07:00
|
|
|
// Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
|
2021-10-07 10:27:09 -07:00
|
|
|
let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
|
2021-06-02 17:21:48 -07:00
|
|
|
.locations
|
|
|
|
.iter()
|
2021-08-26 14:43:12 -07:00
|
|
|
.map(|loc| {
|
|
|
|
let (byte_lo, byte_hi) = loc.call_expr.byte_span;
|
|
|
|
let (line_lo, line_hi) = loc.call_expr.line_span;
|
2021-10-07 10:27:09 -07:00
|
|
|
let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
|
|
|
|
let line_range = (line_lo - line_min, line_hi - line_min);
|
|
|
|
let (anchor, line_title) = if line_lo == line_hi {
|
|
|
|
(format!("{}", line_lo + 1), format!("line {}", line_lo + 1))
|
|
|
|
} else {
|
|
|
|
(
|
|
|
|
format!("{}-{}", line_lo + 1, line_hi + 1),
|
|
|
|
format!("lines {}-{}", line_lo + 1, line_hi + 1),
|
|
|
|
)
|
|
|
|
};
|
|
|
|
let line_url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
|
|
|
|
|
|
|
|
(byte_range, (line_range, line_url, line_title))
|
2021-08-26 14:43:12 -07:00
|
|
|
})
|
|
|
|
.unzip();
|
2021-06-02 17:21:48 -07:00
|
|
|
|
2021-10-07 10:27:09 -07:00
|
|
|
let (_, init_url, init_title) = &line_ranges[0];
|
2021-10-07 09:46:18 -07:00
|
|
|
let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
|
2021-10-07 10:27:09 -07:00
|
|
|
let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
|
2021-10-07 09:46:18 -07:00
|
|
|
|
2021-05-09 16:22:22 -07:00
|
|
|
write!(
|
|
|
|
w,
|
2021-10-07 09:46:18 -07:00
|
|
|
"<div class=\"scraped-example {expanded_cls}\" data-locs=\"{locations}\">\
|
2021-09-21 15:49:36 -07:00
|
|
|
<div class=\"scraped-example-title\">\
|
2021-10-07 10:27:09 -07:00
|
|
|
{name} (<a href=\"{url}\">{title}</a>)\
|
2021-09-21 15:49:36 -07:00
|
|
|
</div>\
|
|
|
|
<div class=\"code-wrapper\">",
|
2021-10-07 09:46:18 -07:00
|
|
|
expanded_cls = if needs_expansion { "" } else { "expanded" },
|
2021-10-07 10:27:09 -07:00
|
|
|
name = call_data.display_name,
|
|
|
|
url = init_url,
|
|
|
|
title = init_title,
|
2021-09-13 18:08:14 -07:00
|
|
|
// The locations are encoded as a data attribute, so they can be read
|
2021-08-25 20:15:46 -07:00
|
|
|
// later by the JS for interactions.
|
2021-10-07 10:27:09 -07:00
|
|
|
locations = Escape(&locations_encoded)
|
2021-05-09 16:22:22 -07:00
|
|
|
);
|
2021-10-07 10:27:09 -07:00
|
|
|
|
|
|
|
if line_ranges.len() > 1 {
|
|
|
|
write!(w, r#"<span class="prev">≺</span> <span class="next">≻</span>"#);
|
|
|
|
}
|
2021-10-07 09:46:18 -07:00
|
|
|
|
|
|
|
if needs_expansion {
|
|
|
|
write!(w, r#"<span class="expand">↕</span>"#);
|
|
|
|
}
|
2021-08-25 20:15:46 -07:00
|
|
|
|
2021-09-13 18:08:14 -07:00
|
|
|
// Look for the example file in the source map if it exists, otherwise return a dummy span
|
|
|
|
let file_span = (|| {
|
|
|
|
let source_map = tcx.sess.source_map();
|
|
|
|
let crate_src = tcx.sess.local_crate_source_file.as_ref()?;
|
|
|
|
let abs_crate_src = crate_src.canonicalize().ok()?;
|
|
|
|
let crate_root = abs_crate_src.parent()?.parent()?;
|
|
|
|
let rel_path = path.strip_prefix(crate_root).ok()?;
|
|
|
|
let files = source_map.files();
|
|
|
|
let file = files.iter().find(|file| match &file.name {
|
|
|
|
FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path,
|
|
|
|
_ => false,
|
|
|
|
})?;
|
|
|
|
Some(rustc_span::Span::with_root_ctxt(
|
2021-10-07 09:46:18 -07:00
|
|
|
file.start_pos + BytePos(byte_min),
|
|
|
|
file.start_pos + BytePos(byte_max),
|
2021-09-13 18:08:14 -07:00
|
|
|
))
|
|
|
|
})()
|
|
|
|
.unwrap_or(rustc_span::DUMMY_SP);
|
|
|
|
|
|
|
|
// The root path is the inverse of Context::current
|
|
|
|
let root_path = vec!["../"; cx.current.len() - 1].join("");
|
|
|
|
|
2021-08-26 14:43:12 -07:00
|
|
|
let mut decoration_info = FxHashMap::default();
|
2021-10-07 10:27:09 -07:00
|
|
|
decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
|
2021-08-26 14:43:12 -07:00
|
|
|
decoration_info.insert("highlight", byte_ranges);
|
2021-09-13 18:08:14 -07:00
|
|
|
|
2021-08-26 14:43:12 -07:00
|
|
|
sources::print_src(
|
|
|
|
w,
|
|
|
|
contents_subset,
|
2021-09-16 18:12:45 -07:00
|
|
|
call_data.edition,
|
2021-08-26 14:43:12 -07:00
|
|
|
file_span,
|
|
|
|
cx,
|
|
|
|
&root_path,
|
2021-09-16 18:12:45 -07:00
|
|
|
Some(highlight::DecorationInfo(decoration_info)),
|
2021-10-07 09:46:18 -07:00
|
|
|
sources::SourceContext::Embedded { offset: line_min },
|
2021-08-26 14:43:12 -07:00
|
|
|
);
|
2021-05-09 16:22:22 -07:00
|
|
|
write!(w, "</div></div>");
|
2021-09-13 18:08:14 -07:00
|
|
|
|
|
|
|
true
|
2021-05-09 16:22:22 -07:00
|
|
|
};
|
|
|
|
|
2021-08-25 20:15:46 -07:00
|
|
|
// The call locations are output in sequence, so that sequence needs to be determined.
|
|
|
|
// Ideally the most "relevant" examples would be shown first, but there's no general algorithm
|
|
|
|
// for determining relevance. Instead, we prefer the smallest examples being likely the easiest to
|
|
|
|
// understand at a glance.
|
|
|
|
let ordered_locations = {
|
|
|
|
let sort_criterion = |(_, call_data): &(_, &CallData)| {
|
2021-08-26 14:43:12 -07:00
|
|
|
// Use the first location because that's what the user will see initially
|
|
|
|
let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
|
2021-08-25 20:15:46 -07:00
|
|
|
hi - lo
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut locs = call_locations.into_iter().collect::<Vec<_>>();
|
2021-09-16 18:12:45 -07:00
|
|
|
locs.sort_by_key(sort_criterion);
|
2021-08-25 20:15:46 -07:00
|
|
|
locs
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut it = ordered_locations.into_iter().peekable();
|
2021-09-16 18:12:45 -07:00
|
|
|
|
|
|
|
// An example may fail to write if its source can't be read for some reason, so this method
|
|
|
|
// continues iterating until a write suceeds
|
2021-09-13 18:08:14 -07:00
|
|
|
let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| {
|
|
|
|
while let Some(example) = it.next() {
|
|
|
|
if write_example(&mut *w, example) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-09-16 18:12:45 -07:00
|
|
|
// Write just one example that's visible by default in the method's description.
|
2021-09-13 18:08:14 -07:00
|
|
|
write_and_skip_failure(w, &mut it);
|
2021-05-09 16:22:22 -07:00
|
|
|
|
2021-08-25 20:15:46 -07:00
|
|
|
// Then add the remaining examples in a hidden section.
|
2021-06-02 17:21:48 -07:00
|
|
|
if it.peek().is_some() {
|
2021-06-01 14:02:09 -07:00
|
|
|
write!(
|
|
|
|
w,
|
2021-09-21 15:49:36 -07:00
|
|
|
"<details class=\"rustdoc-toggle more-examples-toggle\">\
|
|
|
|
<summary class=\"hideme\">\
|
|
|
|
<span>More examples</span>\
|
|
|
|
</summary>\
|
|
|
|
<div class=\"more-scraped-examples\">\
|
|
|
|
<div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
|
|
|
|
<div class=\"more-scraped-examples-inner\">"
|
2021-06-01 14:02:09 -07:00
|
|
|
);
|
2021-08-25 20:15:46 -07:00
|
|
|
|
|
|
|
// Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
|
|
|
|
// make the page arbitrarily huge!
|
2021-09-13 18:08:14 -07:00
|
|
|
for _ in 0..MAX_FULL_EXAMPLES {
|
|
|
|
write_and_skip_failure(w, &mut it);
|
|
|
|
}
|
2021-06-02 17:21:48 -07:00
|
|
|
|
2021-09-16 18:12:45 -07:00
|
|
|
// For the remaining examples, generate a <ul> containing links to the source files.
|
2021-06-02 17:21:48 -07:00
|
|
|
if it.peek().is_some() {
|
2021-09-21 15:49:36 -07:00
|
|
|
write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#);
|
2021-06-02 17:21:48 -07:00
|
|
|
it.for_each(|(_, call_data)| {
|
2021-09-14 09:50:47 -07:00
|
|
|
write!(
|
|
|
|
w,
|
2021-10-07 09:46:18 -07:00
|
|
|
r#"<li><a href="{root}{url}">{name}</a></li>"#,
|
2021-09-14 09:50:47 -07:00
|
|
|
root = cx.root_path(),
|
|
|
|
url = call_data.url,
|
|
|
|
name = call_data.display_name
|
|
|
|
);
|
2021-06-02 17:21:48 -07:00
|
|
|
});
|
2021-08-25 20:15:46 -07:00
|
|
|
write!(w, "</ul></div>");
|
2021-06-02 17:21:48 -07:00
|
|
|
}
|
|
|
|
|
2021-08-25 20:15:46 -07:00
|
|
|
write!(w, "</div></div></details>");
|
2021-05-09 16:22:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
write!(w, "</div>");
|
|
|
|
}
|