rust/src/librustdoc/html/static/js/main.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

987 lines
35 KiB
JavaScript
Raw Normal View History

// Local js definitions:
2021-05-14 11:56:15 +00:00
/* global addClass, getSettingValue, hasClass, searchState */
/* global onEach, onEachLazy, removeClass */
2022-05-02 12:32:56 +00:00
"use strict";
2018-11-06 00:40:12 +00:00
if (!String.prototype.startsWith) {
String.prototype.startsWith = function(searchString, position) {
position = position || 0;
return this.indexOf(searchString, position) === position;
};
}
if (!String.prototype.endsWith) {
String.prototype.endsWith = function(suffix, length) {
2022-04-25 12:23:17 +00:00
const l = length || this.length;
2018-11-06 00:40:12 +00:00
return this.indexOf(suffix, l - suffix.length) !== -1;
};
}
if (!DOMTokenList.prototype.add) {
DOMTokenList.prototype.add = function(className) {
if (className && !hasClass(this, className)) {
if (this.className && this.className.length > 0) {
this.className += " " + className;
} else {
this.className = className;
}
}
};
}
if (!DOMTokenList.prototype.remove) {
DOMTokenList.prototype.remove = function(className) {
if (className && this.className) {
this.className = (" " + this.className + " ").replace(" " + className + " ", " ")
.trim();
}
};
}
// Get a value from the rustdoc-vars div, which is used to convey data from
// Rust to the JS. If there is no such element, return null.
function getVar(name) {
2022-04-25 12:23:17 +00:00
const el = document.getElementById("rustdoc-vars");
if (el) {
return el.attributes["data-" + name].value;
} else {
return null;
2021-01-18 11:03:53 +00:00
}
}
// Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL
// for a resource under the root-path, with the resource-suffix.
function resourcePath(basename, extension) {
return getVar("root-path") + basename + getVar("resource-suffix") + extension;
}
2022-01-19 21:36:15 +00:00
function hideMain() {
addClass(document.getElementById(MAIN_ID), "hidden");
}
function showMain() {
removeClass(document.getElementById(MAIN_ID), "hidden");
}
(function() {
window.rootPath = getVar("root-path");
window.currentCrate = getVar("current-crate");
window.searchJS = resourcePath("search", ".js");
window.searchIndexJS = resourcePath("search-index", ".js");
2022-01-19 21:36:15 +00:00
window.settingsJS = resourcePath("settings", ".js");
2022-04-25 12:23:17 +00:00
const sidebarVars = document.getElementById("sidebar-vars");
2021-01-18 11:03:53 +00:00
if (sidebarVars) {
window.sidebarCurrent = {
name: sidebarVars.attributes["data-name"].value,
ty: sidebarVars.attributes["data-ty"].value,
relpath: sidebarVars.attributes["data-relpath"].value,
};
// FIXME: It would be nicer to generate this text content directly in HTML,
// but with the current code it's hard to get the right information in the right place.
2022-04-25 12:23:17 +00:00
const mobileLocationTitle = document.querySelector(".mobile-topbar h2.location");
const locationTitle = document.querySelector(".sidebar h2.location");
if (mobileLocationTitle && locationTitle) {
mobileLocationTitle.innerHTML = locationTitle.innerHTML;
}
2021-01-18 11:03:53 +00:00
}
}());
// Gets the human-readable string for the virtual-key code of the
// given KeyboardEvent, ev.
//
// This function is meant as a polyfill for KeyboardEvent#key,
// since it is not supported in IE 11 or Chrome for Android. We also test for
// KeyboardEvent#keyCode because the handleShortcut handler is
// also registered for the keydown event, because Blink doesn't fire
// keypress on hitting the Escape key.
//
// So I guess you could say things are getting pretty interoperable.
function getVirtualKey(ev) {
2022-05-27 20:30:19 +00:00
if ("key" in ev && typeof ev.key !== "undefined") {
return ev.key;
}
2022-04-25 12:23:17 +00:00
const c = ev.charCode || ev.keyCode;
2022-05-27 20:30:19 +00:00
if (c === 27) {
return "Escape";
}
return String.fromCharCode(c);
}
2022-04-25 12:23:17 +00:00
const MAIN_ID = "main-content";
2022-01-19 21:36:15 +00:00
const SETTINGS_BUTTON_ID = "settings-menu";
const ALTERNATIVE_DISPLAY_ID = "alternative-display";
const NOT_DISPLAYED_ID = "not-displayed";
2021-03-05 15:16:03 +00:00
2022-01-19 21:36:15 +00:00
function getSettingsButton() {
return document.getElementById(SETTINGS_BUTTON_ID);
}
// Returns the current URL without any query parameter or hash.
function getNakedUrl() {
return window.location.href.split("?")[0].split("#")[0];
}
window.hideSettings = () => {
2022-01-19 21:36:15 +00:00
// Does nothing by default.
};
/**
* This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode`
* doesn't have a parent node.
*
* @param {HTMLElement} newNode
* @param {HTMLElement} referenceNode
2022-01-19 21:36:15 +00:00
*/
function insertAfter(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
/**
* This function creates a new `<section>` with the given `id` and `classes` if it doesn't already
* exist.
*
* More information about this in `switchDisplayedElement` documentation.
*
* @param {string} id
* @param {string} classes
*/
function getOrCreateSection(id, classes) {
let el = document.getElementById(id);
if (!el) {
el = document.createElement("section");
el.id = id;
el.className = classes;
insertAfter(el, document.getElementById(MAIN_ID));
}
return el;
}
/**
* Returns the `<section>` element which contains the displayed element.
*
* @return {HTMLElement}
2022-01-19 21:36:15 +00:00
*/
function getAlternativeDisplayElem() {
return getOrCreateSection(ALTERNATIVE_DISPLAY_ID, "content hidden");
}
/**
* Returns the `<section>` element which contains the not-displayed elements.
*
* @return {HTMLElement}
2022-01-19 21:36:15 +00:00
*/
function getNotDisplayedElem() {
return getOrCreateSection(NOT_DISPLAYED_ID, "hidden");
}
/**
* To nicely switch between displayed "extra" elements (such as search results or settings menu)
* and to alternate between the displayed and not displayed elements, we hold them in two different
* `<section>` elements. They work in pair: one holds the hidden elements while the other
2022-01-19 21:36:15 +00:00
* contains the displayed element (there can be only one at the same time!). So basically, we switch
* elements between the two `<section>` elements.
*
* @param {HTMLElement} elemToDisplay
2022-01-19 21:36:15 +00:00
*/
function switchDisplayedElement(elemToDisplay) {
const el = getAlternativeDisplayElem();
if (el.children.length > 0) {
getNotDisplayedElem().appendChild(el.firstElementChild);
}
if (elemToDisplay === null) {
addClass(el, "hidden");
showMain();
return;
}
el.appendChild(elemToDisplay);
hideMain();
removeClass(el, "hidden");
}
function browserSupportsHistoryApi() {
return window.history && typeof window.history.pushState === "function";
}
// eslint-disable-next-line no-unused-vars
function loadCss(cssFileName) {
const link = document.createElement("link");
link.href = resourcePath(cssFileName, ".css");
link.type = "text/css";
link.rel = "stylesheet";
document.getElementsByTagName("head")[0].appendChild(link);
}
(function() {
2022-01-19 21:36:15 +00:00
function loadScript(url) {
2022-05-07 18:18:23 +00:00
const script = document.createElement("script");
2022-01-19 21:36:15 +00:00
script.src = url;
document.head.append(script);
}
getSettingsButton().onclick = event => {
addClass(getSettingsButton(), "rotate");
2022-01-19 21:36:15 +00:00
event.preventDefault();
// Sending request for the CSS and the JS files at the same time so it will
// hopefully be loaded when the JS will generate the settings content.
loadCss("settings");
2022-01-19 21:36:15 +00:00
loadScript(window.settingsJS);
};
window.searchState = {
2021-05-11 09:47:39 +00:00
loadingText: "Loading search results...",
input: document.getElementsByClassName("search-input")[0],
outputElement: () => {
2022-01-19 21:36:15 +00:00
let el = document.getElementById("search");
if (!el) {
el = document.createElement("section");
el.id = "search";
getNotDisplayedElem().appendChild(el);
}
return el;
2021-05-11 09:47:39 +00:00
},
title: document.title,
2021-05-11 09:47:39 +00:00
titleBeforeSearch: document.title,
timeout: null,
// On the search screen, so you remain on the last tab you opened.
//
// 0 for "In Names"
// 1 for "In Parameters"
// 2 for "In Return Types"
currentTab: 0,
2021-05-09 19:56:21 +00:00
// tab and back preserves the element that was focused.
focusedByTab: [null, null, null],
clearInputTimeout: () => {
2021-05-11 09:47:39 +00:00
if (searchState.timeout !== null) {
clearTimeout(searchState.timeout);
searchState.timeout = null;
}
},
isDisplayed: () => searchState.outputElement().parentElement.id === ALTERNATIVE_DISPLAY_ID,
2021-05-11 09:47:39 +00:00
// Sets the focus on the search bar at the top of the page
focus: () => {
2021-05-11 09:47:39 +00:00
searchState.input.focus();
},
// Removes the focus from the search bar.
defocus: () => {
2021-05-11 09:47:39 +00:00
searchState.input.blur();
},
showResults: search => {
2022-05-07 18:18:23 +00:00
if (search === null || typeof search === "undefined") {
2021-05-11 09:47:39 +00:00
search = searchState.outputElement();
}
2022-01-19 21:36:15 +00:00
switchDisplayedElement(search);
2021-05-11 09:47:39 +00:00
searchState.mouseMovedAfterSearch = false;
document.title = searchState.title;
2021-05-11 09:47:39 +00:00
},
hideResults: () => {
2022-01-19 21:36:15 +00:00
switchDisplayedElement(null);
2021-05-11 09:47:39 +00:00
document.title = searchState.titleBeforeSearch;
// We also remove the query parameter from the URL.
2022-01-19 21:36:15 +00:00
if (browserSupportsHistoryApi()) {
2022-01-10 13:57:43 +00:00
history.replaceState(null, window.currentCrate + " - Rust",
2021-05-11 09:47:39 +00:00
getNakedUrl() + window.location.hash);
}
},
getQueryStringParams: () => {
2022-04-25 12:23:17 +00:00
const params = {};
2021-05-11 09:47:39 +00:00
window.location.search.substring(1).split("&").
map(s => {
2022-04-25 12:23:17 +00:00
const pair = s.split("=");
2021-05-11 09:47:39 +00:00
params[decodeURIComponent(pair[0])] =
typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]);
});
return params;
},
setup: () => {
2022-04-25 12:23:17 +00:00
const search_input = searchState.input;
2021-05-11 09:47:39 +00:00
if (!searchState.input) {
return;
}
2022-04-25 12:23:17 +00:00
let searchLoaded = false;
2021-05-11 09:47:39 +00:00
function loadSearch() {
if (!searchLoaded) {
searchLoaded = true;
loadScript(window.searchJS);
loadScript(window.searchIndexJS);
}
}
2017-10-14 14:31:48 +00:00
search_input.addEventListener("focus", () => {
2022-01-10 13:57:43 +00:00
search_input.origPlaceholder = search_input.placeholder;
2021-05-11 09:47:39 +00:00
search_input.placeholder = "Type your search here.";
loadSearch();
});
2022-05-07 18:18:23 +00:00
if (search_input.value !== "") {
loadSearch();
}
2022-04-25 12:23:17 +00:00
const params = searchState.getQueryStringParams();
2021-05-11 09:47:39 +00:00
if (params.search !== undefined) {
2022-04-25 12:23:17 +00:00
const search = searchState.outputElement();
search.innerHTML = "<h3 class=\"search-loading\">" +
searchState.loadingText + "</h3>";
2021-05-11 09:47:39 +00:00
searchState.showResults(search);
loadSearch();
}
},
};
function getPageId() {
2020-03-30 11:59:10 +00:00
if (window.location.hash) {
2022-04-25 12:23:17 +00:00
const tmp = window.location.hash.replace(/^#/, "");
2020-03-30 11:59:10 +00:00
if (tmp.length > 0) {
return tmp;
}
}
return null;
}
2022-04-25 12:23:17 +00:00
const toggleAllDocsId = "toggle-all-docs";
let savedHash = "";
2018-11-26 16:17:38 +00:00
function handleHashes(ev) {
2022-01-19 21:36:15 +00:00
if (ev !== null && searchState.isDisplayed() && ev.newURL) {
// This block occurs when clicking on an element in the navbar while
// in a search.
2022-01-19 21:36:15 +00:00
switchDisplayedElement(null);
2022-04-25 12:23:17 +00:00
const hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
2022-01-19 21:36:15 +00:00
if (browserSupportsHistoryApi()) {
// `window.location.search`` contains all the query parameters, not just `search`.
2022-01-10 13:57:43 +00:00
history.replaceState(null, "",
getNakedUrl() + window.location.search + "#" + hash);
2017-11-10 18:40:46 +00:00
}
2022-01-19 21:36:15 +00:00
const elem = document.getElementById(hash);
2017-11-06 20:14:37 +00:00
if (elem) {
elem.scrollIntoView();
}
}
// This part is used in case an element is not visible.
if (savedHash !== window.location.hash) {
savedHash = window.location.hash;
if (savedHash.length === 0) {
return;
}
2021-05-08 12:21:57 +00:00
expandSection(savedHash.slice(1)); // we remove the '#'
}
}
function onHashChange(ev) {
// If we're in mobile mode, we should hide the sidebar in any case.
2022-04-25 12:23:17 +00:00
const sidebar = document.getElementsByClassName("sidebar")[0];
removeClass(sidebar, "shown");
handleHashes(ev);
}
function openParentDetails(elem) {
while (elem) {
if (elem.tagName === "DETAILS") {
elem.open = true;
}
elem = elem.parentNode;
}
}
function expandSection(id) {
2021-05-08 12:21:57 +00:00
openParentDetails(document.getElementById(id));
}
function getHelpElement(build) {
if (build) {
buildHelperPopup();
}
2019-09-09 15:04:28 +00:00
return document.getElementById("help");
}
/**
* Show the help popup.
*
* @param {boolean} display - Whether to show or hide the popup
* @param {Event} ev - The event that triggered this call
* @param {Element} [help] - The help element if it already exists
*/
2019-02-08 11:38:47 +00:00
function displayHelp(display, ev, help) {
if (display) {
help = help ? help : getHelpElement(true);
2017-10-14 16:43:00 +00:00
if (hasClass(help, "hidden")) {
ev.preventDefault();
removeClass(help, "hidden");
addClass(document.body, "blur");
}
} else {
// No need to build the help popup if we want to hide it in case it hasn't been
// built yet...
help = help ? help : getHelpElement(false);
if (help && !hasClass(help, "hidden")) {
ev.preventDefault();
addClass(help, "hidden");
removeClass(document.body, "blur");
}
2017-10-14 16:43:00 +00:00
}
}
2019-09-09 15:04:28 +00:00
function handleEscape(ev) {
2022-01-19 21:36:15 +00:00
searchState.clearInputTimeout();
2022-04-25 12:23:17 +00:00
const help = getHelpElement(false);
2021-05-18 12:32:20 +00:00
if (help && !hasClass(help, "hidden")) {
2019-02-08 11:38:47 +00:00
displayHelp(false, ev, help);
2022-01-19 21:36:15 +00:00
} else {
switchDisplayedElement(null);
if (browserSupportsHistoryApi()) {
history.replaceState(null, window.currentCrate + " - Rust",
getNakedUrl() + window.location.hash);
}
2018-03-18 15:32:41 +00:00
ev.preventDefault();
}
searchState.defocus();
2022-05-11 21:11:18 +00:00
window.hideSettings();
2018-03-18 15:32:41 +00:00
}
2022-04-25 12:23:17 +00:00
const disableShortcuts = getSettingValue("disable-shortcuts") === "true";
2018-03-18 15:32:41 +00:00
function handleShortcut(ev) {
// Don't interfere with browser shortcuts
if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) {
return;
}
2018-03-18 15:32:41 +00:00
if (document.activeElement.tagName === "INPUT") {
switch (getVirtualKey(ev)) {
case "Escape":
2019-09-09 15:04:28 +00:00
handleEscape(ev);
2018-03-18 15:32:41 +00:00
break;
}
2018-03-18 15:32:41 +00:00
} else {
switch (getVirtualKey(ev)) {
case "Escape":
2019-09-09 15:04:28 +00:00
handleEscape(ev);
2018-03-18 15:32:41 +00:00
break;
2018-03-18 15:32:41 +00:00
case "s":
case "S":
2019-09-09 15:04:28 +00:00
displayHelp(false, ev);
2018-03-18 15:32:41 +00:00
ev.preventDefault();
searchState.focus();
2018-03-18 15:32:41 +00:00
break;
2018-03-18 15:32:41 +00:00
case "+":
case "-":
ev.preventDefault();
toggleAllDocs();
break;
2018-03-18 15:32:41 +00:00
case "?":
2020-08-11 09:30:50 +00:00
displayHelp(true, ev);
2018-03-18 15:32:41 +00:00
break;
default:
2022-05-11 21:11:18 +00:00
break;
}
}
}
document.addEventListener("keypress", handleShortcut);
document.addEventListener("keydown", handleShortcut);
// delayed sidebar rendering.
window.initSidebarItems = items => {
2022-04-25 12:23:17 +00:00
const sidebar = document.getElementsByClassName("sidebar-elems")[0];
let others;
const current = window.sidebarCurrent;
function addSidebarCrates(crates) {
2021-05-31 09:51:22 +00:00
if (!hasClass(document.body, "crate")) {
// We only want to list crates on the crate page.
return;
}
// Draw a convenient sidebar of known crates if we have a listing
2022-04-25 12:23:17 +00:00
const div = document.createElement("div");
div.className = "block crate";
div.innerHTML = "<h3>Crates</h3>";
2022-04-25 12:23:17 +00:00
const ul = document.createElement("ul");
div.appendChild(ul);
2022-04-25 12:23:17 +00:00
for (const crate of crates) {
let klass = "crate";
if (window.rootPath !== "./" && crate === window.currentCrate) {
klass += " current";
}
2022-04-25 12:23:17 +00:00
const link = document.createElement("a");
link.href = window.rootPath + crate + "/index.html";
link.className = klass;
2022-04-25 12:23:17 +00:00
link.textContent = crate;
2022-04-25 12:23:17 +00:00
const li = document.createElement("li");
li.appendChild(link);
ul.appendChild(li);
}
others.appendChild(div);
}
/**
* Append to the sidebar a "block" of links - a heading along with a list (`<ul>`) of items.
*
* @param {string} shortty - A short type name, like "primitive", "mod", or "macro"
* @param {string} id - The HTML id of the corresponding section on the module page.
* @param {string} longty - A long, capitalized, plural name, like "Primitive Types",
* "Modules", or "Macros".
*/
function block(shortty, id, longty) {
2022-04-25 12:23:17 +00:00
const filtered = items[shortty];
if (!filtered) {
return;
}
2022-04-25 12:23:17 +00:00
const div = document.createElement("div");
div.className = "block " + shortty;
2022-04-25 12:23:17 +00:00
const h3 = document.createElement("h3");
h3.innerHTML = `<a href="index.html#${id}">${longty}</a>`;
2017-04-14 14:37:09 +00:00
div.appendChild(h3);
2022-04-25 12:23:17 +00:00
const ul = document.createElement("ul");
2022-04-25 12:23:17 +00:00
for (const item of filtered) {
const name = item[0];
const desc = item[1]; // can be null
2022-04-25 12:23:17 +00:00
let klass = shortty;
if (name === current.name && shortty === current.ty) {
klass += " current";
}
2022-04-25 12:23:17 +00:00
let path;
if (shortty === "mod") {
path = name + "/index.html";
} else {
path = shortty + "." + name + ".html";
}
2022-04-25 12:23:17 +00:00
const link = document.createElement("a");
2017-04-14 14:37:09 +00:00
link.href = current.relpath + path;
link.title = desc;
link.className = klass;
link.textContent = name;
2022-04-25 12:23:17 +00:00
const li = document.createElement("li");
2017-04-14 14:37:09 +00:00
li.appendChild(link);
ul.appendChild(li);
}
2017-04-14 14:37:09 +00:00
div.appendChild(ul);
others.appendChild(div);
}
if (sidebar) {
others = document.createElement("div");
others.className = "others";
sidebar.appendChild(others);
2022-04-25 12:23:17 +00:00
const isModule = hasClass(document.body, "mod");
if (!isModule) {
block("primitive", "primitives", "Primitive Types");
block("mod", "modules", "Modules");
block("macro", "macros", "Macros");
block("struct", "structs", "Structs");
block("enum", "enums", "Enums");
block("union", "unions", "Unions");
block("constant", "constants", "Constants");
block("static", "static", "Statics");
block("trait", "traits", "Traits");
block("fn", "functions", "Functions");
block("type", "types", "Type Definitions");
block("foreigntype", "foreign-types", "Foreign Types");
block("keyword", "keywords", "Keywords");
block("traitalias", "trait-aliases", "Trait Aliases");
}
// `crates{version}.js` should always be loaded before this script, so we can use
// it safely.
addSidebarCrates(window.ALL_CRATES);
}
};
window.register_implementors = imp => {
2022-04-25 12:23:17 +00:00
const implementors = document.getElementById("implementors-list");
const synthetic_implementors = document.getElementById("synthetic-implementors-list");
const inlined_types = new Set();
2018-02-15 23:45:52 +00:00
2020-01-28 12:48:08 +00:00
if (synthetic_implementors) {
// This `inlined_types` variable is used to avoid having the same implementation
// showing up twice. For example "String" in the "Sync" doc page.
//
// By the way, this is only used by and useful for traits implemented automatically
// (like "Send" and "Sync").
onEachLazy(synthetic_implementors.getElementsByClassName("impl"), el => {
2022-04-25 12:23:17 +00:00
const aliases = el.getAttribute("data-aliases");
2020-01-28 12:48:08 +00:00
if (!aliases) {
return;
}
aliases.split(",").forEach(alias => {
2020-01-28 12:48:08 +00:00
inlined_types.add(alias);
});
});
2020-01-28 12:48:08 +00:00
}
2022-04-25 12:23:17 +00:00
let currentNbImpls = implementors.getElementsByClassName("impl").length;
const traitName = document.querySelector("h1.fqn > .in-band > .trait").textContent;
const baseIdName = "impl-" + traitName + "-";
const libs = Object.getOwnPropertyNames(imp);
// We don't want to include impls from this JS file, when the HTML already has them.
// The current crate should always be ignored. Other crates that should also be
// ignored are included in the attribute `data-ignore-extern-crates`.
const ignoreExternCrates = document
.querySelector("script[data-ignore-extern-crates]")
.getAttribute("data-ignore-extern-crates");
2022-04-25 12:23:17 +00:00
for (const lib of libs) {
if (lib === window.currentCrate || ignoreExternCrates.indexOf(lib) !== -1) {
2022-04-25 12:23:17 +00:00
continue;
}
const structs = imp[lib];
2018-02-10 19:34:46 +00:00
struct_loop:
2022-04-25 12:23:17 +00:00
for (const struct of structs) {
const list = struct.synthetic ? synthetic_implementors : implementors;
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 21:16:55 +00:00
2018-02-15 23:45:52 +00:00
if (struct.synthetic) {
2022-04-25 12:23:17 +00:00
for (const struct_type of struct.types) {
if (inlined_types.has(struct_type)) {
2018-02-15 23:45:52 +00:00
continue struct_loop;
}
2022-04-25 12:23:17 +00:00
inlined_types.add(struct_type);
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 21:16:55 +00:00
}
}
2022-04-25 12:23:17 +00:00
const code = document.createElement("h3");
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 21:16:55 +00:00
code.innerHTML = struct.text;
addClass(code, "code-header");
addClass(code, "in-band");
2017-04-14 14:37:09 +00:00
onEachLazy(code.getElementsByTagName("a"), elem => {
2022-04-25 12:23:17 +00:00
const href = elem.getAttribute("href");
if (href && href.indexOf("http") !== 0) {
2021-01-18 11:03:53 +00:00
elem.setAttribute("href", window.rootPath + href);
2014-06-01 17:17:30 +00:00
}
});
2022-04-25 12:23:17 +00:00
const currentId = baseIdName + currentNbImpls;
const anchor = document.createElement("a");
anchor.href = "#" + currentId;
addClass(anchor, "anchor");
2022-04-25 12:23:17 +00:00
const display = document.createElement("div");
display.id = currentId;
2018-07-01 14:11:14 +00:00
addClass(display, "impl");
display.appendChild(anchor);
display.appendChild(code);
2018-07-01 14:11:14 +00:00
list.appendChild(display);
currentNbImpls += 1;
}
}
};
if (window.pending_implementors) {
window.register_implementors(window.pending_implementors);
}
function labelForToggleButton(sectionIsCollapsed) {
if (sectionIsCollapsed) {
// button will expand the section
return "+";
}
// button will collapse the section
// note that this text is also set in the HTML template in ../render/mod.rs
return "\u2212"; // "\u2212" is "" minus sign
}
2021-05-08 12:21:57 +00:00
function toggleAllDocs() {
2022-04-25 12:23:17 +00:00
const innerToggle = document.getElementById(toggleAllDocsId);
2018-11-26 16:17:38 +00:00
if (!innerToggle) {
return;
}
2022-04-25 12:23:17 +00:00
let sectionIsCollapsed = false;
2018-11-26 16:17:38 +00:00
if (hasClass(innerToggle, "will-expand")) {
removeClass(innerToggle, "will-expand");
onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
2021-05-08 12:21:57 +00:00
if (!hasClass(e, "type-contents-toggle")) {
e.open = true;
}
2017-04-14 14:37:09 +00:00
});
2018-11-26 16:17:38 +00:00
innerToggle.title = "collapse all docs";
} else {
2018-11-26 16:17:38 +00:00
addClass(innerToggle, "will-expand");
onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
if (e.parentNode.id !== "implementations-list" ||
2021-05-08 12:21:57 +00:00
(!hasClass(e, "implementors-toggle") &&
2022-05-14 11:50:52 +00:00
!hasClass(e, "type-contents-toggle"))
) {
2021-05-08 12:21:57 +00:00
e.open = false;
}
2017-04-14 14:37:09 +00:00
});
2021-05-08 12:21:57 +00:00
sectionIsCollapsed = true;
2018-11-26 16:17:38 +00:00
innerToggle.title = "expand all docs";
}
2021-05-08 12:21:57 +00:00
innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed);
}
(function() {
2022-04-25 12:23:17 +00:00
const toggles = document.getElementById(toggleAllDocsId);
2020-08-28 11:30:21 +00:00
if (toggles) {
toggles.onclick = toggleAllDocs;
}
2022-04-25 12:23:17 +00:00
const hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
const hideImplementations = getSettingValue("auto-hide-trait-implementations") === "true";
const hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
function setImplementorsTogglesOpen(id, open) {
2022-04-25 12:23:17 +00:00
const list = document.getElementById(id);
if (list !== null) {
onEachLazy(list.getElementsByClassName("implementors-toggle"), e => {
e.open = open;
});
}
}
if (hideImplementations) {
setImplementorsTogglesOpen("trait-implementations-list", false);
setImplementorsTogglesOpen("blanket-implementations-list", false);
}
onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) {
e.open = true;
}
if (hideMethodDocs && hasClass(e, "method-toggle")) {
e.open = false;
}
});
2022-04-25 12:23:17 +00:00
const pageId = getPageId();
if (pageId !== null) {
expandSection(pageId);
}
}());
2017-04-14 14:37:09 +00:00
(function() {
// To avoid checking on "rustdoc-line-numbers" value on every loop...
let lineNumbersFunc = () => {};
if (getSettingValue("line-numbers") === "true") {
lineNumbersFunc = x => {
2022-04-25 12:23:17 +00:00
const count = x.textContent.split("\n").length;
const elems = [];
for (let i = 0; i < count; ++i) {
elems.push(i + 1);
}
2022-04-25 12:23:17 +00:00
const node = document.createElement("pre");
addClass(node, "line-number");
node.innerHTML = elems.join("\n");
x.parentNode.insertBefore(node, x);
};
}
onEachLazy(document.getElementsByClassName("rust-example-rendered"), e => {
if (hasClass(e, "compile_fail")) {
2020-05-17 13:34:59 +00:00
e.addEventListener("mouseover", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
});
2020-05-17 13:34:59 +00:00
e.addEventListener("mouseout", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "";
});
} else if (hasClass(e, "ignore")) {
2020-05-17 13:34:59 +00:00
e.addEventListener("mouseover", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
});
2020-05-17 13:34:59 +00:00
e.addEventListener("mouseout", function() {
this.parentElement.previousElementSibling.childNodes[0].style.color = "";
});
}
lineNumbersFunc(e);
});
}());
2017-11-10 18:40:46 +00:00
function hideSidebar() {
2022-04-25 12:23:17 +00:00
const sidebar = document.getElementsByClassName("sidebar")[0];
removeClass(sidebar, "shown");
}
function handleClick(id, f) {
2022-04-25 12:23:17 +00:00
const elem = document.getElementById(id);
if (elem) {
elem.addEventListener("click", f);
}
}
handleClick("help-button", ev => {
displayHelp(true, ev);
});
handleClick(MAIN_ID, () => {
hideSidebar();
});
onEachLazy(document.getElementsByTagName("a"), el => {
// For clicks on internal links (<A> tags with a hash property), we expand the section we're
// jumping to *before* jumping there. We can't do this in onHashChange, because it changes
// the height of the document so we wind up scrolled to the wrong place.
if (el.hash) {
el.addEventListener("click", () => {
expandSection(el.hash.slice(1));
hideSidebar();
});
}
});
onEachLazy(document.querySelectorAll(".rustdoc-toggle > summary:not(.hideme)"), el => {
el.addEventListener("click", e => {
if (e.target.tagName !== "SUMMARY" && e.target.tagName !== "A") {
e.preventDefault();
}
});
});
onEachLazy(document.getElementsByClassName("notable-traits"), e => {
e.onclick = function() {
2022-05-07 18:18:23 +00:00
this.getElementsByClassName("notable-traits-tooltiptext")[0]
2020-07-15 15:58:10 +00:00
.classList.toggle("force-tooltip");
};
});
2022-04-25 12:23:17 +00:00
const sidebar_menu_toggle = document.getElementsByClassName("sidebar-menu-toggle")[0];
if (sidebar_menu_toggle) {
sidebar_menu_toggle.addEventListener("click", () => {
2022-04-25 12:23:17 +00:00
const sidebar = document.getElementsByClassName("sidebar")[0];
if (!hasClass(sidebar, "shown")) {
addClass(sidebar, "shown");
} else {
removeClass(sidebar, "shown");
}
});
}
let buildHelperPopup = () => {
2022-04-25 12:23:17 +00:00
const popup = document.createElement("aside");
addClass(popup, "hidden");
popup.id = "help";
popup.addEventListener("click", ev => {
if (ev.target === popup) {
// Clicked the blurred zone outside the help popup; dismiss help.
displayHelp(false, ev);
}
});
2022-04-25 12:23:17 +00:00
const book_info = document.createElement("span");
book_info.className = "top";
book_info.innerHTML = "You can find more information in \
<a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
2022-04-25 12:23:17 +00:00
const container = document.createElement("div");
const shortcuts = [
["?", "Show this help dialog"],
["S", "Focus the search field"],
["↑", "Move up in search results"],
["↓", "Move down in search results"],
2021-05-09 19:56:21 +00:00
["← / →", "Switch result tab (when results focused)"],
["&#9166;", "Go to active search result"],
["+", "Expand all sections"],
["-", "Collapse all sections"],
].map(x => "<dt>" +
x[0].split(" ")
2022-06-06 11:57:54 +00:00
.map((y, index) => ((index & 1) === 0 ? "<kbd>" + y + "</kbd>" : " " + y + " "))
.join("") + "</dt><dd>" + x[1] + "</dd>").join("");
2022-04-25 12:23:17 +00:00
const div_shortcuts = document.createElement("div");
addClass(div_shortcuts, "shortcuts");
div_shortcuts.innerHTML = "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts + "</dl></div>";
2022-04-25 12:23:17 +00:00
const infos = [
"Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
2020-08-27 10:56:43 +00:00
restrict the search to a given item kind.",
"Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \
<code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
and <code>const</code>.",
"Search functions by type signature (e.g., <code>vec -&gt; usize</code> or \
<code>* -&gt; vec</code>)",
"Search multiple things at once by splitting your query with comma (e.g., \
<code>str,u8</code> or <code>String,struct:Vec,test</code>)",
"You can look for items with an exact name by putting double quotes around \
your request: <code>\"string\"</code>",
"Look for items inside another one by searching for a path: <code>vec::Vec</code>",
].map(x => "<p>" + x + "</p>").join("");
2022-04-25 12:23:17 +00:00
const div_infos = document.createElement("div");
addClass(div_infos, "infos");
div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;
container.appendChild(book_info);
container.appendChild(div_shortcuts);
container.appendChild(div_infos);
2022-04-25 12:23:17 +00:00
const rustdoc_version = document.createElement("span");
rustdoc_version.className = "bottom";
2022-04-25 12:23:17 +00:00
const rustdoc_version_code = document.createElement("code");
rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version");
rustdoc_version.appendChild(rustdoc_version_code);
container.appendChild(rustdoc_version);
popup.appendChild(container);
insertAfter(popup, document.querySelector("main"));
// So that it's only built once and then it'll do nothing when called!
buildHelperPopup = () => {};
2021-05-14 11:56:15 +00:00
};
onHashChange(null);
window.addEventListener("hashchange", onHashChange);
searchState.setup();
}());
(function() {
2022-04-25 12:23:17 +00:00
let reset_button_timeout = null;
2021-04-30 09:42:07 +00:00
window.copy_path = but => {
2022-04-25 12:23:17 +00:00
const parent = but.parentElement;
const path = [];
2021-04-30 09:42:07 +00:00
onEach(parent.childNodes, child => {
2022-05-07 18:18:23 +00:00
if (child.tagName === "A") {
2021-04-30 09:42:07 +00:00
path.push(child.textContent);
}
});
2022-05-07 18:18:23 +00:00
const el = document.createElement("textarea");
el.value = path.join("::");
el.setAttribute("readonly", "");
2021-04-30 09:42:07 +00:00
// To not make it appear on the screen.
2022-05-07 18:18:23 +00:00
el.style.position = "absolute";
el.style.left = "-9999px";
2021-04-30 09:42:07 +00:00
document.body.appendChild(el);
el.select();
2022-05-07 18:18:23 +00:00
document.execCommand("copy");
2021-04-30 09:42:07 +00:00
document.body.removeChild(el);
// There is always one children, but multiple childNodes.
2022-05-07 18:18:23 +00:00
but.children[0].style.display = "none";
2022-04-25 12:23:17 +00:00
let tmp;
if (but.childNodes.length < 2) {
2022-05-07 18:18:23 +00:00
tmp = document.createTextNode("✓");
but.appendChild(tmp);
} else {
onEachLazy(but.childNodes, e => {
if (e.nodeType === Node.TEXT_NODE) {
tmp = e;
return true;
}
});
2022-05-07 18:18:23 +00:00
tmp.textContent = "✓";
}
2021-04-30 09:42:07 +00:00
if (reset_button_timeout !== null) {
window.clearTimeout(reset_button_timeout);
}
function reset_button() {
2022-05-07 18:18:23 +00:00
tmp.textContent = "";
2021-04-30 09:42:07 +00:00
reset_button_timeout = null;
but.children[0].style.display = "";
}
2021-04-30 09:42:07 +00:00
reset_button_timeout = window.setTimeout(reset_button, 1000);
};
2021-04-30 09:42:07 +00:00
}());