summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/html/static
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html/static')
-rw-r--r--src/librustdoc/html/static/.eslintrc.js96
-rw-r--r--src/librustdoc/html/static/COPYRIGHT.txt46
-rw-r--r--src/librustdoc/html/static/LICENSE-APACHE.txt201
-rw-r--r--src/librustdoc/html/static/LICENSE-MIT.txt23
-rw-r--r--src/librustdoc/html/static/css/normalize.css2
-rw-r--r--src/librustdoc/html/static/css/noscript.css20
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css2335
-rw-r--r--src/librustdoc/html/static/css/settings.css90
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css563
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css409
-rw-r--r--src/librustdoc/html/static/css/themes/light.css395
-rw-r--r--src/librustdoc/html/static/fonts/FiraSans-LICENSE.txt94
-rw-r--r--src/librustdoc/html/static/fonts/FiraSans-Medium.woff2bin0 -> 132780 bytes
-rw-r--r--src/librustdoc/html/static/fonts/FiraSans-Regular.woff2bin0 -> 129188 bytes
-rw-r--r--src/librustdoc/html/static/fonts/NanumBarunGothic-LICENSE.txt99
-rw-r--r--src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2bin0 -> 399468 bytes
-rw-r--r--src/librustdoc/html/static/fonts/SourceCodePro-It.ttf.woff2bin0 -> 44896 bytes
-rw-r--r--src/librustdoc/html/static/fonts/SourceCodePro-LICENSE.txt93
-rw-r--r--src/librustdoc/html/static/fonts/SourceCodePro-Regular.ttf.woff2bin0 -> 52228 bytes
-rw-r--r--src/librustdoc/html/static/fonts/SourceCodePro-Semibold.ttf.woff2bin0 -> 52348 bytes
-rw-r--r--src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff2bin0 -> 81320 bytes
-rw-r--r--src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff2bin0 -> 59860 bytes
-rw-r--r--src/librustdoc/html/static/fonts/SourceSerif4-LICENSE.md93
-rw-r--r--src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff2bin0 -> 76180 bytes
-rw-r--r--src/librustdoc/html/static/images/clipboard.svg1
-rw-r--r--src/librustdoc/html/static/images/down-arrow.svg1
-rw-r--r--src/librustdoc/html/static/images/favicon-16x16.pngbin0 -> 715 bytes
-rw-r--r--src/librustdoc/html/static/images/favicon-32x32.pngbin0 -> 1125 bytes
-rw-r--r--src/librustdoc/html/static/images/favicon.svg24
-rw-r--r--src/librustdoc/html/static/images/rust-logo.svg61
-rw-r--r--src/librustdoc/html/static/images/toggle-minus.svg1
-rw-r--r--src/librustdoc/html/static/images/toggle-plus.svg1
-rw-r--r--src/librustdoc/html/static/images/wheel.svg1
-rw-r--r--src/librustdoc/html/static/js/README.md15
-rw-r--r--src/librustdoc/html/static/js/externs.js142
-rw-r--r--src/librustdoc/html/static/js/main.js974
-rw-r--r--src/librustdoc/html/static/js/scrape-examples.js106
-rw-r--r--src/librustdoc/html/static/js/search.js2297
-rw-r--r--src/librustdoc/html/static/js/settings.js272
-rw-r--r--src/librustdoc/html/static/js/source-script.js241
-rw-r--r--src/librustdoc/html/static/js/storage.js268
-rw-r--r--src/librustdoc/html/static/scrape-examples-help.md34
42 files changed, 8998 insertions, 0 deletions
diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js
new file mode 100644
index 000000000..fcd925bb3
--- /dev/null
+++ b/src/librustdoc/html/static/.eslintrc.js
@@ -0,0 +1,96 @@
+module.exports = {
+ "env": {
+ "browser": true,
+ "es6": true
+ },
+ "extends": "eslint:recommended",
+ "parserOptions": {
+ "ecmaVersion": 2015,
+ "sourceType": "module"
+ },
+ "rules": {
+ "linebreak-style": [
+ "error",
+ "unix"
+ ],
+ "semi": [
+ "error",
+ "always"
+ ],
+ "quotes": [
+ "error",
+ "double"
+ ],
+ "linebreak-style": [
+ "error",
+ "unix"
+ ],
+ "no-trailing-spaces": "error",
+ "no-var": ["error"],
+ "prefer-const": ["error"],
+ "prefer-arrow-callback": ["error"],
+ "brace-style": [
+ "error",
+ "1tbs",
+ { "allowSingleLine": false }
+ ],
+ "keyword-spacing": [
+ "error",
+ { "before": true, "after": true }
+ ],
+ "arrow-spacing": [
+ "error",
+ { "before": true, "after": true }
+ ],
+ "key-spacing": [
+ "error",
+ { "beforeColon": false, "afterColon": true, "mode": "strict" }
+ ],
+ "func-call-spacing": ["error", "never"],
+ "space-infix-ops": "error",
+ "space-before-function-paren": ["error", "never"],
+ "space-before-blocks": "error",
+ "comma-dangle": ["error", "always-multiline"],
+ "comma-style": ["error", "last"],
+ "max-len": ["error", { "code": 100, "tabWidth": 4 }],
+ "eol-last": ["error", "always"],
+ "arrow-parens": ["error", "as-needed"],
+ "no-unused-vars": [
+ "error",
+ {
+ "argsIgnorePattern": "^_",
+ "varsIgnorePattern": "^_"
+ }
+ ],
+ "eqeqeq": "error",
+ "no-const-assign": "error",
+ "no-debugger": "error",
+ "no-dupe-args": "error",
+ "no-dupe-else-if": "error",
+ "no-dupe-keys": "error",
+ "no-duplicate-case": "error",
+ "no-ex-assign": "error",
+ "no-fallthrough": "error",
+ "no-invalid-regexp": "error",
+ "no-import-assign": "error",
+ "no-self-compare": "error",
+ "no-template-curly-in-string": "error",
+ "block-scoped-var": "error",
+ "guard-for-in": "error",
+ "no-alert": "error",
+ "no-confusing-arrow": "error",
+ "no-div-regex": "error",
+ "no-floating-decimal": "error",
+ "no-implicit-globals": "error",
+ "no-implied-eval": "error",
+ "no-label-var": "error",
+ "no-lonely-if": "error",
+ "no-mixed-operators": "error",
+ "no-multi-assign": "error",
+ "no-return-assign": "error",
+ "no-script-url": "error",
+ "no-sequences": "error",
+ "no-throw-literal": "error",
+ "no-div-regex": "error",
+ }
+};
diff --git a/src/librustdoc/html/static/COPYRIGHT.txt b/src/librustdoc/html/static/COPYRIGHT.txt
new file mode 100644
index 000000000..34e48134c
--- /dev/null
+++ b/src/librustdoc/html/static/COPYRIGHT.txt
@@ -0,0 +1,46 @@
+These documentation pages include resources by third parties. This copyright
+file applies only to those resources. The following third party resources are
+included, and carry their own copyright notices and license terms:
+
+* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2):
+
+ Copyright (c) 2014, Mozilla Foundation https://mozilla.org/
+ with Reserved Font Name Fira Sans.
+
+ Copyright (c) 2014, Telefonica S.A.
+
+ Licensed under the SIL Open Font License, Version 1.1.
+ See FiraSans-LICENSE.txt.
+
+* rustdoc.css, main.js, and playpen.js:
+
+ Copyright 2015 The Rust Developers.
+ Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or
+ the MIT license (LICENSE-MIT.txt) at your option.
+
+* normalize.css:
+
+ Copyright (c) Nicolas Gallagher and Jonathan Neal.
+ Licensed under the MIT license (see LICENSE-MIT.txt).
+
+* Source Code Pro (SourceCodePro-Regular.ttf.woff2,
+ SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2):
+
+ Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/),
+ with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark
+ of Adobe Systems Incorporated in the United States and/or other countries.
+
+ Licensed under the SIL Open Font License, Version 1.1.
+ See SourceCodePro-LICENSE.txt.
+
+* Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2,
+ SourceSerif4-It.ttf.woff2):
+
+ Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name
+ 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United
+ States and/or other countries.
+
+ Licensed under the SIL Open Font License, Version 1.1.
+ See SourceSerif4-LICENSE.md.
+
+This copyright file is intended to be distributed with rustdoc output.
diff --git a/src/librustdoc/html/static/LICENSE-APACHE.txt b/src/librustdoc/html/static/LICENSE-APACHE.txt
new file mode 100644
index 000000000..16fe87b06
--- /dev/null
+++ b/src/librustdoc/html/static/LICENSE-APACHE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/src/librustdoc/html/static/LICENSE-MIT.txt b/src/librustdoc/html/static/LICENSE-MIT.txt
new file mode 100644
index 000000000..31aa79387
--- /dev/null
+++ b/src/librustdoc/html/static/LICENSE-MIT.txt
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/src/librustdoc/html/static/css/normalize.css b/src/librustdoc/html/static/css/normalize.css
new file mode 100644
index 000000000..fdb8a8c65
--- /dev/null
+++ b/src/librustdoc/html/static/css/normalize.css
@@ -0,0 +1,2 @@
+/* ignore-tidy-linelength */
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace, monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace, monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type="button"],[type="reset"],[type="submit"],button{-webkit-appearance:button}[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
new file mode 100644
index 000000000..0a19a99ab
--- /dev/null
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -0,0 +1,20 @@
+/*
+This whole CSS file is used only in case rustdoc is rendered with javascript disabled. Since a lot
+of content is hidden by default (depending on the settings too), we have to overwrite some of the
+rules.
+*/
+
+#main-content .attributes {
+ /* Since there is no toggle (the "[-]") when JS is disabled, no need for this margin either. */
+ margin-left: 0 !important;
+}
+
+#copy-path {
+ /* It requires JS to work so no need to display it in this case. */
+ display: none;
+}
+
+.sub {
+ /* The search bar and related controls don't work without JS */
+ display: none;
+}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
new file mode 100644
index 000000000..83fe14550
--- /dev/null
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -0,0 +1,2335 @@
+/* See FiraSans-LICENSE.txt for the Fira Sans license. */
+@font-face {
+ font-family: 'Fira Sans';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Fira Sans'),
+ url("FiraSans-Regular.woff2") format("woff2");
+ font-display: swap;
+}
+@font-face {
+ font-family: 'Fira Sans';
+ font-style: normal;
+ font-weight: 500;
+ src: local('Fira Sans Medium'),
+ url("FiraSans-Medium.woff2") format("woff2");
+ font-display: swap;
+}
+
+/* See SourceSerif4-LICENSE.md for the Source Serif 4 license. */
+@font-face {
+ font-family: 'Source Serif 4';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Source Serif 4'),
+ url("SourceSerif4-Regular.ttf.woff2") format("woff2");
+ font-display: swap;
+}
+@font-face {
+ font-family: 'Source Serif 4';
+ font-style: italic;
+ font-weight: 400;
+ src: local('Source Serif 4 Italic'),
+ url("SourceSerif4-It.ttf.woff2") format("woff2");
+ font-display: swap;
+}
+@font-face {
+ font-family: 'Source Serif 4';
+ font-style: normal;
+ font-weight: 700;
+ src: local('Source Serif 4 Bold'),
+ url("SourceSerif4-Bold.ttf.woff2") format("woff2");
+ font-display: swap;
+}
+
+/* See SourceCodePro-LICENSE.txt for the Source Code Pro license. */
+@font-face {
+ font-family: 'Source Code Pro';
+ font-style: normal;
+ font-weight: 400;
+ /* Avoid using locally installed font because bad versions are in circulation:
+ * see https://github.com/rust-lang/rust/issues/24355 */
+ src: url("SourceCodePro-Regular.ttf.woff2") format("woff2");
+ font-display: swap;
+}
+@font-face {
+ font-family: 'Source Code Pro';
+ font-style: italic;
+ font-weight: 400;
+ src: url("SourceCodePro-It.ttf.woff2") format("woff2");
+ font-display: swap;
+}
+@font-face {
+ font-family: 'Source Code Pro';
+ font-style: normal;
+ font-weight: 600;
+ src: url("SourceCodePro-Semibold.ttf.woff2") format("woff2");
+ font-display: swap;
+}
+
+/* Avoid using legacy CJK serif fonts in Windows like Batang. */
+@font-face {
+ font-family: 'NanumBarunGothic';
+ src: url("NanumBarunGothic.ttf.woff2") format("woff2");
+ font-display: swap;
+ unicode-range: U+AC00-D7AF, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF;
+}
+
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+/* This part handles the "default" theme being used depending on the system one. */
+html {
+ content: "";
+}
+@media (prefers-color-scheme: light) {
+ html {
+ content: "light";
+ }
+}
+@media (prefers-color-scheme: dark) {
+ html {
+ content: "dark";
+ }
+}
+
+/* General structure and fonts */
+
+body {
+ /* Line spacing at least 1.5 per Web Content Accessibility Guidelines
+ https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html */
+ font: 1rem/1.5 "Source Serif 4", NanumBarunGothic, serif;
+ margin: 0;
+ position: relative;
+ /* We use overflow-wrap: break-word for Safari, which doesn't recognize
+ `anywhere`: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap */
+ overflow-wrap: break-word;
+ /* Then override it with `anywhere`, which is required to make non-Safari browsers break
+ more aggressively when we want them to. */
+ overflow-wrap: anywhere;
+
+ -webkit-font-feature-settings: "kern", "liga";
+ -moz-font-feature-settings: "kern", "liga";
+ font-feature-settings: "kern", "liga";
+
+ background-color: var(--main-background-color);
+ color: var(--main-color);
+}
+
+h1 {
+ font-size: 1.5rem; /* 24px */
+}
+h2 {
+ font-size: 1.375rem; /* 22px */
+}
+h3 {
+ font-size: 1.25rem; /* 20px */
+}
+h1, h2, h3, h4, h5, h6 {
+ font-weight: 500;
+}
+h1, h2, h3, h4 {
+ margin: 20px 0 15px 0;
+ padding-bottom: 6px;
+}
+.docblock h3, .docblock h4, h5, h6 {
+ margin: 15px 0 5px 0;
+}
+h1.fqn {
+ margin: 0;
+ padding: 0;
+ border-bottom-color: var(--headings-border-bottom-color);
+}
+h2, h3, h4 {
+ border-bottom-color: var(--headings-border-bottom-color);
+}
+.main-heading {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ padding-bottom: 6px;
+ margin-bottom: 15px;
+}
+.main-heading a:hover {
+ text-decoration: underline;
+}
+#toggle-all-docs {
+ text-decoration: none;
+}
+/* The only headings that get underlines are:
+ Markdown-generated headings within the top-doc
+ Rustdoc-generated h2 section headings (e.g. "Implementations", "Required Methods", etc)
+ Underlines elsewhere in the documentation break up visual flow and tend to invert
+ section hierarchies. */
+h2,
+.top-doc .docblock > h3,
+.top-doc .docblock > h4 {
+ border-bottom: 1px solid var(--headings-border-bottom-color);
+}
+h3.code-header {
+ font-size: 1.125rem; /* 18px */
+}
+h4.code-header {
+ font-size: 1rem;
+}
+.code-header {
+ font-weight: 600;
+ border-bottom-style: none;
+ margin: 0;
+ padding: 0;
+ margin-top: 0.6em;
+ margin-bottom: 0.4em;
+}
+.impl,
+.impl-items .method,
+.methods .method,
+.impl-items .type,
+.methods .type,
+.impl-items .associatedconstant,
+.methods .associatedconstant,
+.impl-items .associatedtype,
+.methods .associatedtype {
+ flex-basis: 100%;
+ font-weight: 600;
+ position: relative;
+}
+
+div.impl-items > div {
+ padding-left: 0;
+}
+
+h1, h2, h3, h4, h5, h6,
+.sidebar,
+.mobile-topbar,
+a.source,
+.search-input,
+.search-results .result-name,
+.content table td:first-child > a,
+.item-left > a,
+.out-of-band,
+span.since,
+#source-sidebar, #sidebar-toggle,
+details.rustdoc-toggle > summary::before,
+div.impl-items > div:not(.docblock):not(.item-info),
+.content ul.crate a.crate,
+a.srclink,
+#main-content > .since,
+#help-button > button,
+details.rustdoc-toggle.top-doc > summary,
+details.rustdoc-toggle.top-doc > summary::before,
+details.rustdoc-toggle.non-exhaustive > summary,
+details.rustdoc-toggle.non-exhaustive > summary::before,
+.scraped-example-title,
+.more-examples-toggle summary, .more-examples-toggle .hide-more,
+.example-links a,
+/* This selector is for the items listed in the "all items" page. */
+#main-content > ul.docblock > li > a {
+ font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
+}
+
+h1, h2, h3, h4,
+a#toggle-all-docs,
+a.anchor,
+.small-section-header a,
+#source-sidebar a,
+pre.rust a,
+.sidebar h2 a,
+.sidebar h3 a,
+.mobile-topbar h2 a,
+.in-band a,
+.search-results a,
+.module-item .stab,
+.import-item .stab,
+.result-name .primitive > i, .result-name .keyword > i,
+.content .method .where,
+.content .fn .where,
+.content .where.fmt-newline {
+ color: var(--main-color);
+}
+
+ol, ul {
+ padding-left: 24px;
+}
+ul ul, ol ul, ul ol, ol ol {
+ margin-bottom: .625em;
+}
+
+p {
+ /* Paragraph spacing at least 1.5 times line spacing per Web Content Accessibility Guidelines.
+ Line-height is 1.5rem, so line spacing is .5rem; .75em is 1.5 times that.
+ https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html */
+ margin: 0 0 .75em 0;
+}
+
+summary {
+ outline: none;
+}
+
+/* Fix some style changes due to normalize.css 8 */
+
+td,
+th {
+ padding: 0;
+}
+
+table {
+ border-collapse: collapse;
+}
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ color: inherit;
+ font: inherit;
+ margin: 0;
+}
+
+button {
+ /* Buttons on Safari have different default padding than other platforms. Make them the same. */
+ padding: 1px 6px;
+}
+
+/* end tweaks for normalize.css 8 */
+
+.rustdoc {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+}
+
+main {
+ position: relative;
+ flex-grow: 1;
+ padding: 10px 15px 40px 45px;
+ min-width: 0;
+}
+
+.source main {
+ padding: 15px;
+}
+
+.width-limiter {
+ max-width: 960px;
+ margin-right: auto;
+}
+
+.source .width-limiter {
+ max-width: unset;
+}
+
+details:not(.rustdoc-toggle) summary {
+ margin-bottom: .6em;
+}
+
+code, pre, a.test-arrow, .code-header {
+ font-family: "Source Code Pro", monospace;
+}
+.docblock code, .docblock-short code {
+ border-radius: 3px;
+ padding: 0 0.125em;
+}
+.docblock pre code, .docblock-short pre code {
+ padding: 0;
+}
+pre {
+ padding: 14px;
+}
+.docblock.item-decl {
+ margin-left: 0;
+}
+.item-decl pre {
+ overflow-x: auto;
+}
+
+.source .content pre {
+ padding: 20px;
+}
+
+img {
+ max-width: 100%;
+}
+
+li {
+ position: relative;
+}
+
+.source .content {
+ max-width: none;
+ overflow: visible;
+ margin-left: 0px;
+}
+
+nav.sub {
+ position: relative;
+ font-size: 1rem;
+}
+
+.sub-container {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+}
+
+.sub-logo-container {
+ display: none;
+ margin-right: 20px;
+}
+
+.source .sub-logo-container {
+ display: block;
+}
+
+.source .sub-logo-container > img {
+ height: 60px;
+ width: 60px;
+ object-fit: contain;
+}
+
+.sidebar, .mobile-topbar, .sidebar-menu-toggle {
+ background-color: var(--sidebar-background-color);
+}
+
+.sidebar {
+ font-size: 0.875rem;
+ width: 250px;
+ min-width: 200px;
+ overflow-y: scroll;
+ position: sticky;
+ height: 100vh;
+ top: 0;
+ left: 0;
+}
+
+.sidebar-elems,
+.sidebar > .location {
+ padding-left: 24px;
+}
+
+.sidebar .location {
+ overflow-wrap: anywhere;
+}
+
+.rustdoc.source .sidebar {
+ width: 50px;
+ min-width: 0px;
+ max-width: 300px;
+ flex-grow: 0;
+ flex-shrink: 0;
+ flex-basis: auto;
+ border-right: 1px solid;
+ overflow-x: hidden;
+ /* The sidebar is by default hidden */
+ overflow-y: hidden;
+}
+
+.rustdoc.source .sidebar .sidebar-logo {
+ display: none;
+}
+
+.source .sidebar, #sidebar-toggle, #source-sidebar {
+ background-color: var(--sidebar-background-color);
+}
+
+#sidebar-toggle > button:hover, #sidebar-toggle > button:focus {
+ background-color: var(--sidebar-background-color-hover);
+}
+
+.source .sidebar > *:not(#sidebar-toggle) {
+ opacity: 0;
+ visibility: hidden;
+}
+
+.source-sidebar-expanded .source .sidebar {
+ overflow-y: auto;
+}
+
+.source-sidebar-expanded .source .sidebar > *:not(#sidebar-toggle) {
+ opacity: 1;
+ visibility: visible;
+}
+
+#all-types {
+ margin-top: 1em;
+}
+
+/* Improve the scrollbar display on firefox */
+* {
+ scrollbar-width: initial;
+ scrollbar-color: var(--scrollbar-color);
+}
+.sidebar {
+ scrollbar-width: thin;
+ scrollbar-color: var(--scrollbar-color);
+}
+
+/* Improve the scrollbar display on webkit-based browsers */
+::-webkit-scrollbar {
+ width: 12px;
+}
+.sidebar::-webkit-scrollbar {
+ width: 8px;
+}
+::-webkit-scrollbar-track {
+ -webkit-box-shadow: inset 0;
+ background-color: var(--scrollbar-track-background-color);
+}
+.sidebar::-webkit-scrollbar-track {
+ background-color: var(--scrollbar-track-background-color);
+}
+::-webkit-scrollbar-thumb, .sidebar::-webkit-scrollbar-thumb {
+ background-color: var(--scrollbar-thumb-background-color);
+}
+
+/* Everything else */
+
+.hidden {
+ display: none !important;
+}
+
+.sidebar .logo-container {
+ display: flex;
+ margin-top: 10px;
+ margin-bottom: 10px;
+ justify-content: center;
+}
+
+.version {
+ overflow-wrap: break-word;
+}
+
+.logo-container > img {
+ height: 100px;
+ width: 100px;
+}
+
+.location:empty {
+ border: none;
+}
+
+.location a:first-of-type {
+ font-weight: 500;
+}
+
+.block {
+ padding: 0;
+}
+.block ul, .block li {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+.block a,
+h2.location a {
+ display: block;
+ padding: 0.25rem;
+ margin-left: -0.25rem;
+
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+
+.sidebar h2 {
+ border-bottom: none;
+ font-weight: 500;
+ padding: 0;
+ margin: 0;
+ margin-top: 0.7rem;
+ margin-bottom: 0.7rem;
+}
+
+.sidebar h3 {
+ font-size: 1.125rem; /* 18px */
+ font-weight: 500;
+ padding: 0;
+ margin: 0;
+}
+
+.sidebar-elems .block {
+ margin-bottom: 2em;
+}
+
+.sidebar-elems .block li a {
+ white-space: nowrap;
+}
+
+.mobile-topbar {
+ display: none;
+}
+
+.source .content pre.rust {
+ white-space: pre;
+ overflow: auto;
+ padding-left: 0;
+}
+
+.rustdoc .example-wrap {
+ display: inline-flex;
+ margin-bottom: 10px;
+}
+
+.example-wrap {
+ position: relative;
+ width: 100%;
+}
+
+.example-wrap > pre.line-number {
+ overflow: initial;
+ border: 1px solid;
+ padding: 13px 8px;
+ text-align: right;
+ border-top-left-radius: 5px;
+ border-bottom-left-radius: 5px;
+}
+
+.example-wrap > pre.rust a:hover {
+ text-decoration: underline;
+}
+
+.line-numbers {
+ text-align: right;
+}
+.rustdoc:not(.source) .example-wrap > pre:not(.line-number) {
+ width: 100%;
+ overflow-x: auto;
+}
+
+.rustdoc:not(.source) .example-wrap > pre.line-numbers {
+ width: auto;
+ overflow-x: visible;
+}
+
+.rustdoc .example-wrap > pre {
+ margin: 0;
+}
+
+#search {
+ position: relative;
+}
+
+.search-loading {
+ text-align: center;
+}
+
+#results > table {
+ width: 100%;
+ table-layout: fixed;
+}
+
+.content > .example-wrap pre.line-numbers {
+ position: relative;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.line-numbers span {
+ cursor: pointer;
+}
+
+.docblock-short {
+ overflow-wrap: break-word;
+ overflow-wrap: anywhere;
+}
+.docblock-short p {
+ display: inline;
+}
+
+.docblock-short p {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ margin: 0;
+}
+/* Wrap non-pre code blocks (`text`) but not (```text```). */
+.docblock > :not(pre) > code,
+.docblock-short > :not(pre) > code {
+ white-space: pre-wrap;
+}
+
+.top-doc .docblock h2 { font-size: 1.375rem; }
+.top-doc .docblock h3 { font-size: 1.25rem; }
+.top-doc .docblock h4,
+.top-doc .docblock h5 {
+ font-size: 1.125rem;
+}
+.top-doc .docblock h6 {
+ font-size: 1rem;
+}
+
+.docblock h5 { font-size: 1rem; }
+.docblock h6 { font-size: 0.875rem; }
+.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
+ border-bottom-color: var(--headings-border-bottom-color);
+}
+
+.docblock {
+ margin-left: 24px;
+ position: relative;
+}
+
+.docblock > :not(.information):not(.more-examples-toggle) {
+ max-width: 100%;
+ overflow-x: auto;
+}
+
+.content .out-of-band {
+ flex-grow: 0;
+ font-size: 1.125rem;
+ font-weight: normal;
+ float: right;
+}
+
+.method > .code-header, .trait-impl > .code-header {
+ max-width: calc(100% - 41px);
+ display: block;
+}
+
+.content .in-band {
+ flex-grow: 1;
+ margin: 0px;
+ padding: 0px;
+ overflow-wrap: break-word;
+ overflow-wrap: anywhere;
+}
+
+.in-band > code, .in-band > .code-header {
+ display: inline-block;
+}
+
+.docblock code, .docblock-short code,
+pre, .rustdoc.source .example-wrap {
+ background-color: var(--code-block-background-color);
+}
+
+#main-content {
+ position: relative;
+}
+#main-content > .since {
+ top: inherit;
+}
+
+.content table:not(.table-display) {
+ border-spacing: 0 5px;
+}
+.content td { vertical-align: top; }
+.content td:first-child { padding-right: 20px; }
+.content td p:first-child { margin-top: 0; }
+.content td h1, .content td h2 { margin-left: 0; font-size: 1.125rem; }
+.content tr:first-child td { border-top: 0; }
+
+.docblock table {
+ margin: .5em 0;
+ width: calc(100% - 2px);
+ overflow-x: auto;
+ display: block;
+}
+
+.docblock table td {
+ padding: .5em;
+ border: 1px dashed;
+}
+
+.docblock table th {
+ padding: .5em;
+ text-align: left;
+ border: 1px solid;
+}
+
+.fields + table {
+ margin-bottom: 1em;
+}
+
+.content .item-list {
+ list-style-type: none;
+ padding: 0;
+}
+
+.content .multi-column {
+ -moz-column-count: 5;
+ -moz-column-gap: 2.5em;
+ -webkit-column-count: 5;
+ -webkit-column-gap: 2.5em;
+ column-count: 5;
+ column-gap: 2.5em;
+}
+.content .multi-column li { width: 100%; display: inline-block; }
+
+.content > .methods > .method {
+ font-size: 1rem;
+ position: relative;
+}
+/* Shift "where ..." part of method or fn definition down a line */
+.content .method .where,
+.content .fn .where,
+.content .where.fmt-newline {
+ display: block;
+ font-size: 0.875rem;
+}
+
+.content .methods > div:not(.notable-traits):not(.method) {
+ margin-left: 40px;
+ margin-bottom: 15px;
+}
+
+.content .docblock > .impl-items {
+ margin-left: 20px;
+ margin-top: -34px;
+}
+.content .docblock >.impl-items .table-display {
+ margin: 0;
+}
+.content .docblock >.impl-items table td {
+ padding: 0;
+}
+.content .docblock > .impl-items .table-display, .impl-items table td {
+ border: none;
+}
+
+.item-info {
+ display: block;
+}
+
+.content .item-info code {
+ font-size: 0.875rem;
+}
+
+.content .item-info {
+ position: relative;
+ margin-left: 24px;
+}
+
+.sub-variant > div > .item-info {
+ margin-top: initial;
+}
+
+.content .impl-items .docblock, .content .impl-items .item-info {
+ margin-bottom: .6em;
+}
+
+.content .impl-items > .item-info {
+ margin-left: 40px;
+}
+
+.methods > .item-info, .content .impl-items > .item-info {
+ margin-top: -8px;
+}
+
+.impl-items {
+ flex-basis: 100%;
+}
+
+#main-content > .item-info {
+ margin-top: 0;
+ margin-left: 0;
+}
+
+nav.sub {
+ flex-grow: 1;
+ margin-bottom: 25px;
+}
+.source nav.sub {
+ margin-left: 32px;
+}
+nav.main {
+ padding: 20px 0;
+ text-align: center;
+}
+nav.main .current {
+ border-top: 1px solid;
+ border-bottom: 1px solid;
+}
+nav.main .separator {
+ border: 1px solid;
+ display: inline-block;
+ height: 23px;
+ margin: 0 20px;
+}
+nav.sum { text-align: right; }
+nav.sub form { display: inline; }
+
+a {
+ text-decoration: none;
+ background: transparent;
+}
+
+.small-section-header {
+ display: flex;
+ justify-content: space-between;
+ position: relative;
+}
+
+.small-section-header:hover > .anchor {
+ display: initial;
+}
+
+.in-band:hover > .anchor, .impl:hover > .anchor, .method.trait-impl:hover > .anchor,
+.type.trait-impl:hover > .anchor, .associatedconstant.trait-impl:hover > .anchor,
+.associatedtype.trait-impl:hover > .anchor {
+ display: inline-block;
+ position: absolute;
+}
+.anchor {
+ display: none;
+ position: absolute;
+ left: -0.5em;
+ background: none !important;
+}
+.anchor.field {
+ left: -5px;
+}
+.small-section-header > .anchor {
+ left: -15px;
+ padding-right: 8px;
+}
+h2.small-section-header > .anchor {
+ padding-right: 6px;
+}
+.anchor::before {
+ content: '§';
+}
+
+.docblock a:not(.srclink):not(.test-arrow):not(.scrape-help):hover,
+.docblock-short a:not(.srclink):not(.test-arrow):not(.scrape-help):hover, .item-info a {
+ text-decoration: underline;
+}
+
+.block a.current.crate { font-weight: 500; }
+
+/* In most contexts we use `overflow-wrap: anywhere` to ensure that we can wrap
+ as much as needed on mobile (see
+ src/test/rustdoc-gui/type-declaration-overflow.goml for an example of why
+ this matters). The `anywhere` value means:
+
+ "Soft wrap opportunities introduced by the word break are considered when
+ calculating min-content intrinsic sizes."
+
+ https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap#values
+
+ For table layouts, that becomes a problem: the browser tries to make each
+ column as narrow as possible, and `overflow-wrap: anywhere` means it can do
+ so by breaking words - even if some other column could be shrunk without
+ breaking words! This shows up, for instance, in the `Structs` / `Modules` /
+ `Functions` (etcetera) sections of a module page, and when a docblock
+ contains a table.
+
+ So, for table layouts, override the default with break-word, which does
+ _not_ affect min-content intrinsic sizes.
+*/
+table,
+.item-table {
+ overflow-wrap: break-word;
+}
+
+.item-table {
+ display: table;
+}
+.item-row {
+ display: table-row;
+}
+.item-left, .item-right {
+ display: table-cell;
+}
+.item-left {
+ padding-right: 1.25rem;
+}
+
+.search-container {
+ position: relative;
+ display: flex;
+ height: 34px;
+}
+.search-container > * {
+ height: 100%;
+}
+.search-results-title {
+ display: inline;
+}
+#search-settings {
+ font-size: 1.5rem;
+ font-weight: 500;
+ margin-bottom: 20px;
+}
+#crate-search {
+ min-width: 115px;
+ margin-top: 5px;
+ padding-left: 0.15em;
+ padding-right: 23px;
+ border: 1px solid;
+ border-radius: 4px;
+ outline: none;
+ cursor: pointer;
+ -moz-appearance: none;
+ -webkit-appearance: none;
+ /* Removes default arrow from firefox */
+ background-repeat: no-repeat;
+ background-color: transparent;
+ background-size: 20px;
+ background-position: calc(100% - 1px) 56%;
+ background-image: /* AUTOREPLACE: */url("down-arrow.svg");
+ max-width: 100%;
+ text-overflow: ellipsis;
+}
+.search-container {
+ margin-top: 4px;
+}
+.search-input {
+ /* Override Normalize.css: it has a rule that sets
+ -webkit-appearance: textfield for search inputs. That
+ causes rounded corners and no border on iOS Safari. */
+ -webkit-appearance: none;
+ /* Override Normalize.css: we have margins and do
+ not want to overflow - the `moz` attribute is necessary
+ until Firefox 29, too early to drop at this point */
+ -moz-box-sizing: border-box !important;
+ box-sizing: border-box !important;
+ outline: none;
+ border: 1px solid;
+ border-radius: 2px;
+ padding: 8px;
+ font-size: 1rem;
+ width: 100%;
+}
+
+.search-results {
+ display: none;
+ padding-bottom: 2em;
+}
+
+.search-results.active {
+ display: block;
+ /* prevent overhanging tabs from moving the first result */
+ clear: both;
+}
+
+.search-results .desc > span {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ display: block;
+}
+
+.search-results > a {
+ display: block;
+ width: 100%;
+ /* A little margin ensures the browser's outlining of focused links has room to display. */
+ margin-left: 2px;
+ margin-right: 2px;
+ border-bottom: 1px solid #aaa3;
+}
+
+.search-results > a > div {
+ display: flex;
+ flex-flow: row wrap;
+}
+
+.search-results .result-name, .search-results div.desc, .search-results .result-description {
+ width: 50%;
+}
+.search-results .result-name {
+ padding-right: 1em;
+}
+
+.search-results .result-name > span {
+ display: inline-block;
+ margin: 0;
+ font-weight: normal;
+}
+
+.popover {
+ font-size: 1rem;
+ position: absolute;
+ right: 0;
+ z-index: 2;
+ display: block;
+ margin-top: 7px;
+ border-radius: 3px;
+ border: 1px solid;
+ font-size: 1rem;
+}
+
+/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */
+.popover::before {
+ content: '';
+ position: absolute;
+ right: 11px;
+ border: solid;
+ border-width: 1px 1px 0 0;
+ display: inline-block;
+ padding: 4px;
+ transform: rotate(-45deg);
+ top: -5px;
+}
+
+.popover, .popover::before {
+ background-color: var(--main-background-color);
+ color: var(--main-color);
+}
+
+#help-button .popover {
+ max-width: 600px;
+}
+
+#help-button .popover::before {
+ right: 48px;
+}
+
+#help-button dt {
+ float: left;
+ clear: left;
+ display: block;
+ margin-right: 0.5rem;
+}
+#help-button span.top, #help-button span.bottom {
+ text-align: center;
+ display: block;
+ font-size: 1.125rem;
+}
+#help-button span.top {
+ text-align: center;
+ display: block;
+ margin: 10px 0;
+ border-bottom: 1px solid;
+ padding-bottom: 4px;
+ margin-bottom: 6px;
+}
+#help-button span.bottom {
+ clear: both;
+ border-top: 1px solid;
+}
+.side-by-side {
+ text-align: initial;
+}
+.side-by-side > div {
+ width: 50%;
+ float: left;
+ padding: 0 20px 20px 17px;
+}
+
+.item-info .stab {
+ width: fit-content;
+ /* This min-height is needed to unify the height of the stab elements because some of them
+ have emojis.
+ */
+ min-height: 36px;
+ display: flex;
+ align-items: center;
+ white-space: pre-wrap;
+}
+.stab {
+ padding: 3px;
+ margin-bottom: 5px;
+ font-size: 0.875rem;
+ font-weight: normal;
+}
+.stab p {
+ display: inline;
+ margin: 0;
+}
+
+.stab .emoji {
+ font-size: 1.25rem;
+}
+
+/* Black one-pixel outline around emoji shapes */
+.emoji {
+ text-shadow:
+ 1px 0 0 black,
+ -1px 0 0 black,
+ 0 1px 0 black,
+ 0 -1px 0 black;
+}
+
+.module-item .stab,
+.import-item .stab {
+ border-radius: 3px;
+ display: inline-block;
+ font-size: 0.875rem;
+ line-height: 1.2;
+ margin-bottom: 0;
+ margin-left: 0.3125em;
+ padding: 2px;
+ vertical-align: text-bottom;
+}
+
+.module-item.unstable,
+.import-item.unstable {
+ opacity: 0.65;
+}
+
+.since {
+ font-weight: normal;
+ font-size: initial;
+}
+
+.rightside {
+ padding-left: 12px;
+ padding-right: 2px;
+ position: initial;
+}
+
+.impl-items .srclink, .impl .srclink, .methods .srclink {
+ /* Override header settings otherwise it's too bold */
+ font-weight: normal;
+ font-size: 1rem;
+}
+
+.rightside {
+ float: right;
+}
+
+.variants_table {
+ width: 100%;
+}
+
+.variants_table tbody tr td:first-child {
+ width: 1%; /* make the variant name as small as possible */
+}
+
+td.summary-column {
+ width: 100%;
+}
+
+.summary {
+ padding-right: 0px;
+}
+
+pre.rust .question-mark {
+ font-weight: bold;
+}
+
+a.test-arrow {
+ display: inline-block;
+ visibility: hidden;
+ position: absolute;
+ padding: 5px 10px 5px 10px;
+ border-radius: 5px;
+ font-size: 1.375rem;
+ top: 5px;
+ right: 5px;
+ z-index: 1;
+}
+.example-wrap:hover .test-arrow {
+ visibility: visible;
+}
+a.test-arrow:hover{
+ text-decoration: none;
+}
+
+.code-attribute {
+ font-weight: 300;
+}
+
+.item-spacer {
+ width: 100%;
+ height: 12px;
+}
+
+.out-of-band > span.since {
+ position: initial;
+ font-size: 1.25rem;
+}
+
+h3.variant {
+ font-weight: 600;
+ font-size: 1.125rem;
+ margin-bottom: 10px;
+ border-bottom: none;
+}
+
+.sub-variant h4 {
+ font-size: 1rem;
+ font-weight: 400;
+ border-bottom: none;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.sub-variant {
+ margin-left: 24px;
+ margin-bottom: 40px;
+}
+
+.sub-variant > .sub-variant-field {
+ margin-left: 24px;
+}
+
+.toggle-label {
+ display: inline-block;
+ margin-left: 4px;
+ margin-top: 3px;
+}
+
+:target > code, :target > .code-header {
+ opacity: 1;
+}
+
+:target {
+ padding-right: 3px;
+}
+
+.information {
+ position: absolute;
+ left: -25px;
+ margin-top: 7px;
+ z-index: 1;
+}
+
+.tooltip {
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+}
+
+.tooltip::after {
+ display: none;
+ text-align: center;
+ padding: 5px 3px 3px 3px;
+ border-radius: 6px;
+ margin-left: 5px;
+ font-size: 1rem;
+}
+
+.tooltip.ignore::after {
+ content: "This example is not tested";
+}
+.tooltip.compile_fail::after {
+ content: "This example deliberately fails to compile";
+}
+.tooltip.should_panic::after {
+ content: "This example panics";
+}
+.tooltip.edition::after {
+ content: "This code runs with edition " attr(data-edition);
+}
+
+.tooltip::before {
+ content: " ";
+ position: absolute;
+ top: 50%;
+ left: 16px;
+ margin-top: -5px;
+ border-width: 5px;
+ border-style: solid;
+ display: none;
+}
+
+.tooltip:hover::before, .tooltip:hover::after {
+ display: inline;
+}
+
+.tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore {
+ font-weight: bold;
+ font-size: 1.25rem;
+}
+
+.notable-traits-tooltip {
+ display: inline-block;
+ cursor: pointer;
+}
+
+.notable-traits:hover .notable-traits-tooltiptext,
+.notable-traits .notable-traits-tooltiptext.force-tooltip {
+ display: inline-block;
+}
+
+.notable-traits .notable-traits-tooltiptext {
+ display: none;
+ padding: 5px 3px 3px 3px;
+ border-radius: 6px;
+ margin-left: 5px;
+ z-index: 10;
+ font-size: 1rem;
+ cursor: default;
+ position: absolute;
+ border: 1px solid;
+}
+
+.notable-traits-tooltip::after {
+ /* The margin on the tooltip does not capture hover events,
+ this extends the area of hover enough so that mouse hover is not
+ lost when moving the mouse to the tooltip */
+ content: "\00a0\00a0\00a0";
+}
+
+.notable-traits .notable, .notable-traits .docblock {
+ margin: 0;
+}
+
+.notable-traits .notable {
+ margin: 0;
+ margin-bottom: 13px;
+ font-size: 1.1875rem;
+ font-weight: 600;
+ display: block;
+}
+
+.notable-traits .docblock code.content{
+ margin: 0;
+ padding: 0;
+ font-size: 1.25rem;
+}
+
+/* Example code has the "Run" button that needs to be positioned relative to the pre */
+pre.rust.rust-example-rendered {
+ position: relative;
+}
+
+pre.rust {
+ tab-size: 4;
+ -moz-tab-size: 4;
+}
+
+.search-failed {
+ text-align: center;
+ margin-top: 20px;
+ display: none;
+}
+
+.search-failed.active {
+ display: block;
+}
+
+.search-failed > ul {
+ text-align: left;
+ max-width: 570px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+#titles {
+ height: 35px;
+}
+
+#titles > button {
+ float: left;
+ width: 33.3%;
+ text-align: center;
+ font-size: 1.125rem;
+ cursor: pointer;
+ border: 0;
+ border-top: 2px solid;
+}
+
+#titles > button:first-child:last-child {
+ margin-right: 1px;
+ width: calc(100% - 1px);
+}
+
+#titles > button:not(:last-child) {
+ margin-right: 1px;
+ width: calc(33.3% - 1px);
+}
+
+#titles > button > div.count {
+ display: inline-block;
+ font-size: 1rem;
+}
+
+.notable-traits {
+ cursor: pointer;
+ z-index: 2;
+ margin-left: 5px;
+}
+
+#sidebar-toggle {
+ position: sticky;
+ top: 0;
+ left: 0;
+ font-weight: bold;
+ font-size: 1.25rem;
+ border-bottom: 1px solid;
+ display: flex;
+ height: 40px;
+ justify-content: center;
+ align-items: center;
+ z-index: 10;
+}
+#source-sidebar {
+ width: 100%;
+ z-index: 1;
+ overflow: auto;
+}
+#source-sidebar > .title {
+ font-size: 1.5rem;
+ text-align: center;
+ border-bottom: 1px solid;
+ margin-bottom: 6px;
+}
+#sidebar-toggle > button {
+ background: none;
+ color: inherit;
+ cursor: pointer;
+ text-align: center;
+ border: none;
+ outline: none;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ /* work around button layout strangeness: https://stackoverflow.com/q/7271561 */
+ width: 100%;
+ /* iOS button gradient: https://stackoverflow.com/q/5438567 */
+ -webkit-appearance: none;
+ opacity: 1;
+}
+#settings-menu, #help-button {
+ margin-left: 4px;
+ outline: none;
+}
+
+#copy-path {
+ height: 34px;
+}
+#settings-menu > a, #help-button > button, #copy-path {
+ padding: 5px;
+ width: 33px;
+ border: 1px solid;
+ border-radius: 2px;
+ cursor: pointer;
+}
+#settings-menu {
+ padding: 0;
+}
+#settings-menu > a, #help-button > button {
+ padding: 5px;
+ height: 100%;
+ display: block;
+}
+
+@keyframes rotating {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+#settings-menu.rotate > a img {
+ animation: rotating 2s linear infinite;
+}
+
+.setting-line .radio-line input:checked {
+ box-shadow: inset 0 0 0 3px var(--main-background-color);
+ background-color: var(--settings-input-color);
+}
+.setting-line .radio-line input:focus {
+ box-shadow: 0 0 1px 1px var(--settings-input-color);
+}
+/* In here we combine both `:focus` and `:checked` properties. */
+.setting-line .radio-line input:checked:focus {
+ box-shadow: inset 0 0 0 3px var(--main-background-color),
+ 0 0 2px 2px var(--settings-input-color);
+}
+.setting-line .radio-line input:hover {
+ border-color: var(--settings-input-color) !important;
+}
+input:checked + .slider {
+ background-color: var(--settings-input-color);
+}
+
+#help-button > button {
+ text-align: center;
+ /* Rare exception to specifying font sizes in rem. Since this is acting
+ as an icon, it's okay to specify their sizes in pixels. */
+ font-size: 20px;
+ padding-top: 2px;
+}
+
+#copy-path {
+ background: initial;
+ margin-left: 10px;
+ padding: 0;
+ padding-left: 2px;
+ border: 0;
+}
+
+#theme-choices {
+ display: none;
+ position: absolute;
+ left: 0;
+ top: 28px;
+ border: 1px solid;
+ border-radius: 3px;
+ z-index: 1;
+ cursor: pointer;
+}
+
+#theme-choices > button {
+ border: none;
+ width: 100%;
+ padding: 4px 8px;
+ text-align: center;
+ background: rgba(0,0,0,0);
+ overflow-wrap: normal;
+}
+
+#theme-choices > button:not(:first-child) {
+ border-top: 1px solid;
+}
+
+kbd {
+ display: inline-block;
+ padding: 3px 5px;
+ font: 15px monospace;
+ line-height: 10px;
+ vertical-align: middle;
+ border: solid 1px;
+ border-radius: 3px;
+ cursor: default;
+}
+
+.hidden-by-impl-hider,
+.hidden-by-usual-hider {
+ /* important because of conflicting rule for small screens */
+ display: none !important;
+}
+
+#implementations-list > h3 > span.in-band {
+ width: 100%;
+}
+
+.table-display {
+ width: 100%;
+ border: 0;
+ border-collapse: collapse;
+ border-spacing: 0;
+ font-size: 1rem;
+}
+
+.table-display tr td:first-child {
+ padding-right: 0;
+}
+
+.table-display tr td:last-child {
+ float: right;
+}
+.table-display .out-of-band {
+ position: relative;
+ font-size: 1.125rem;
+ display: block;
+}
+
+.table-display td:hover .anchor {
+ display: block;
+ top: 2px;
+ left: -5px;
+}
+
+#main-content > ul {
+ padding-left: 10px;
+}
+#main-content > ul > li {
+ list-style: none;
+}
+
+.non-exhaustive {
+ margin-bottom: 1em;
+}
+
+details.dir-entry {
+ padding-left: 4px;
+}
+
+details.dir-entry > summary {
+ margin: 0 0 0 13px;
+ list-style-position: outside;
+ cursor: pointer;
+}
+
+details.dir-entry div.folders, details.dir-entry div.files {
+ padding-left: 23px;
+}
+
+details.dir-entry a {
+ display: block;
+}
+
+/* The hideme class is used on summary tags that contain a span with
+ placeholder text shown only when the toggle is closed. For instance,
+ "Expand description" or "Show methods". */
+details.rustdoc-toggle > summary.hideme {
+ cursor: pointer;
+}
+
+details.rustdoc-toggle > summary {
+ list-style: none;
+}
+details.rustdoc-toggle > summary::-webkit-details-marker,
+details.rustdoc-toggle > summary::marker {
+ display: none;
+}
+
+details.rustdoc-toggle > summary.hideme > span {
+ margin-left: 9px;
+}
+
+details.rustdoc-toggle > summary::before {
+ content: "";
+ cursor: pointer;
+ width: 16px;
+ height: 16px;
+ background-repeat: no-repeat;
+ background-position: top left;
+ display: inline-block;
+ vertical-align: middle;
+ opacity: .5;
+}
+
+/* Screen readers see the text version at the end the line.
+ Visual readers see the icon at the start of the line, but small and transparent. */
+details.rustdoc-toggle > summary::after {
+ content: "Expand";
+ overflow: hidden;
+ width: 0;
+ height: 0;
+ position: absolute;
+}
+
+details.rustdoc-toggle > summary.hideme::after {
+ /* "hideme" toggles already have a description when they're contracted */
+ content: "";
+}
+
+details.rustdoc-toggle > summary:focus::before,
+details.rustdoc-toggle > summary:hover::before {
+ opacity: 1;
+}
+
+details.rustdoc-toggle.top-doc > summary,
+details.rustdoc-toggle.top-doc > summary::before,
+details.rustdoc-toggle.non-exhaustive > summary,
+details.rustdoc-toggle.non-exhaustive > summary::before {
+ font-size: 1rem;
+}
+
+details.non-exhaustive {
+ margin-bottom: 8px;
+}
+
+details.rustdoc-toggle > summary.hideme::before {
+ position: relative;
+}
+
+details.rustdoc-toggle > summary:not(.hideme)::before {
+ position: absolute;
+ left: -24px;
+ top: 4px;
+}
+
+.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before {
+ position: absolute;
+ left: -24px;
+}
+
+/* When a "hideme" summary is open and the "Expand description" or "Show
+ methods" text is hidden, we want the [-] toggle that remains to not
+ affect the layout of the items to its right. To do that, we use
+ absolute positioning. Note that we also set position: relative
+ on the parent <details> to make this work properly. */
+details.rustdoc-toggle[open] > summary.hideme {
+ position: absolute;
+}
+
+details.rustdoc-toggle {
+ position: relative;
+}
+
+details.rustdoc-toggle[open] > summary.hideme > span {
+ display: none;
+}
+
+details.rustdoc-toggle[open] > summary::before,
+details.rustdoc-toggle[open] > summary.hideme::before {
+ background-image: /* AUTOREPLACE: */url("toggle-minus.svg");
+}
+
+details.rustdoc-toggle > summary::before {
+ background-image: /* AUTOREPLACE: */url("toggle-plus.svg");
+}
+
+details.rustdoc-toggle[open] > summary::before,
+details.rustdoc-toggle[open] > summary.hideme::before {
+ width: 16px;
+ height: 16px;
+ background-repeat: no-repeat;
+ background-position: top left;
+ display: inline-block;
+ content: "";
+}
+
+details.rustdoc-toggle[open] > summary::after,
+details.rustdoc-toggle[open] > summary.hideme::after {
+ content: "Collapse";
+}
+
+/* This is needed in docblocks to have the "▶" element to be on the same line. */
+.docblock summary > * {
+ display: inline-block;
+}
+
+/* Media Queries */
+
+/*
+WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY;
+If you update this line, then you also need to update the line with the same warning
+in storage.js plus the media query with (max-width: 700px)
+*/
+@media (min-width: 701px) {
+ /* In case there is no documentation before a code block, we need to add some margin at the top
+ to prevent an overlay between the "collapse toggle" and the information tooltip.
+ However, it's not needed with smaller screen width because the doc/code block is always put
+ "one line" below. */
+ .docblock > .information:first-child > .tooltip {
+ margin-top: 16px;
+ }
+
+ /* When we expand the sidebar on the source code page, we hide the logo on the left of the
+ search bar to have more space. */
+ .source-sidebar-expanded .source .sidebar + main .width-limiter .sub-logo-container.rust-logo {
+ display: none;
+ }
+
+ .source-sidebar-expanded .source .sidebar {
+ width: 300px;
+ }
+}
+
+/*
+WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
+If you update this line, then you also need to update the line with the same warning
+in storage.js plus the media query with (min-width: 701px)
+*/
+@media (max-width: 700px) {
+ /* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,
+ or visiting a URL with a fragment like `#method.new`, we don't want the item to be obscured
+ by the topbar. Anything with an `id` gets scroll-margin-top equal to .mobile-topbar's size.
+ */
+ *[id] {
+ scroll-margin-top: 45px;
+ }
+
+ .rustdoc {
+ padding-top: 0px;
+ /* Sidebar should overlay main content, rather than pushing main content to the right.
+ Turn off `display: flex` on the body element. */
+ display: block;
+ }
+
+ main {
+ padding-left: 15px;
+ padding-top: 0px;
+ }
+
+ .rustdoc,
+ .main-heading {
+ flex-direction: column;
+ }
+
+ .content .out-of-band {
+ text-align: left;
+ margin-left: initial;
+ padding: initial;
+ }
+
+ .content .out-of-band .since::before {
+ content: "Since ";
+ }
+
+ #copy-path {
+ display: none;
+ }
+
+ /* Hide the logo and item name from the sidebar. Those are displayed
+ in the mobile-topbar instead. */
+ .sidebar .sidebar-logo,
+ .sidebar .location {
+ display: none;
+ }
+
+ .sidebar-elems {
+ margin-top: 1em;
+ }
+
+ .sidebar {
+ position: fixed;
+ top: 45px;
+ /* Hide the sidebar offscreen while not in use. Doing this instead of display: none means
+ the sidebar stays visible for screen readers, which is useful for navigation. */
+ left: -1000px;
+ margin-left: 0;
+ margin: 0;
+ padding: 0;
+ z-index: 11;
+ /* Reduce height slightly to account for mobile topbar. */
+ height: calc(100vh - 45px);
+ }
+
+ /* The source view uses a different design for the sidebar toggle, and doesn't have a topbar,
+ so don't bump down the main content or the sidebar. */
+ .source main,
+ .rustdoc.source .sidebar {
+ top: 0;
+ padding: 0;
+ height: 100vh;
+ border: 0;
+ }
+
+ .sidebar.shown,
+ .source-sidebar-expanded .source .sidebar,
+ .sidebar:focus-within {
+ left: 0;
+ }
+
+ .rustdoc.source > .sidebar {
+ position: fixed;
+ margin: 0;
+ z-index: 11;
+ width: 0;
+ }
+
+ .mobile-topbar .location a {
+ padding: 0;
+ margin: 0;
+ }
+
+ .mobile-topbar .location {
+ border: none;
+ padding: 0;
+ margin: auto 0.5em auto auto;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ /* Rare exception to specifying font sizes in rem. Since the topbar
+ height is specified in pixels, this also has to be specified in
+ pixels to avoid overflowing the topbar when the user sets a bigger
+ font size. */
+ font-size: 24px;
+ }
+
+ .mobile-topbar .logo-container {
+ max-height: 45px;
+ }
+
+ .mobile-topbar .logo-container > img {
+ max-width: 35px;
+ max-height: 35px;
+ margin-left: 20px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+ }
+
+ .mobile-topbar {
+ display: flex;
+ flex-direction: row;
+ position: sticky;
+ z-index: 10;
+ font-size: 2rem;
+ height: 45px;
+ width: 100%;
+ left: 0;
+ top: 0;
+ }
+
+ .source .mobile-topbar {
+ display: none;
+ }
+
+ .sidebar-menu-toggle {
+ width: 45px;
+ /* Rare exception to specifying font sizes in rem. Since this is acting
+ as an icon, it's okay to specify its sizes in pixels. */
+ font-size: 32px;
+ border: none;
+ }
+
+ .sidebar-elems {
+ background-color: var(--sidebar-background-color);
+ }
+
+ .source nav:not(.sidebar).sub {
+ margin-left: 32px;
+ }
+
+ .content {
+ margin-left: 0px;
+ }
+
+ .source .content {
+ margin-top: 10px;
+ }
+
+ #search {
+ margin-left: 0;
+ padding: 0;
+ }
+
+ .anchor {
+ display: none !important;
+ }
+
+ .notable-traits {
+ position: absolute;
+ left: -22px;
+ top: 24px;
+ }
+
+ #titles > button > div.count {
+ float: left;
+ width: 100%;
+ }
+
+ #titles {
+ height: 50px;
+ }
+
+ /* Because of ios, we need to actually have a full height sidebar title so the
+ * actual sidebar can show up. But then we need to make it transparent so we don't
+ * hide content. The filler just allows to create the background for the sidebar
+ * title. But because of the absolute position, I had to lower the z-index.
+ */
+ #sidebar-filler {
+ position: fixed;
+ left: 45px;
+ width: calc(100% - 45px);
+ top: 0;
+ height: 45px;
+ z-index: -1;
+ border-bottom: 1px solid;
+ }
+
+ #main-content > details.rustdoc-toggle > summary::before,
+ #main-content > div > details.rustdoc-toggle > summary::before {
+ left: -11px;
+ }
+
+ #sidebar-toggle {
+ position: fixed;
+ left: 1px;
+ top: 100px;
+ width: 30px;
+ font-size: 1.5rem;
+ text-align: center;
+ padding: 0;
+ z-index: 10;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ cursor: pointer;
+ font-weight: bold;
+ border: 1px solid;
+ border-left: 0;
+ }
+
+ .source-sidebar-expanded #sidebar-toggle {
+ left: unset;
+ top: unset;
+ width: unset;
+ border-top-right-radius: unset;
+ border-bottom-right-radius: unset;
+ position: sticky;
+ border: 0;
+ border-bottom: 1px solid;
+ }
+
+ #source-sidebar {
+ z-index: 11;
+ }
+
+ #main-content > .line-numbers {
+ margin-top: 0;
+ }
+
+ .notable-traits .notable-traits-tooltiptext {
+ left: 0;
+ top: 100%;
+ }
+
+ /* We don't display the help button on mobile devices. */
+ #help-button {
+ display: none;
+ }
+
+ /* Display an alternating layout on tablets and phones */
+ .item-table {
+ display: block;
+ }
+ .item-row {
+ display: flex;
+ flex-flow: column wrap;
+ }
+ .item-left, .item-right {
+ width: 100%;
+ }
+
+ /* Display an alternating layout on tablets and phones */
+ .search-results > a {
+ border-bottom: 1px solid #aaa9;
+ padding: 5px 0px;
+ }
+ .search-results .result-name, .search-results div.desc, .search-results .result-description {
+ width: 100%;
+ }
+ .search-results div.desc, .search-results .result-description, .item-right {
+ padding-left: 2em;
+ }
+
+ .source-sidebar-expanded .source .sidebar {
+ max-width: 100vw;
+ width: 100vw;
+ }
+
+ /* Position of the "[-]" element. */
+ details.rustdoc-toggle:not(.top-doc) > summary {
+ margin-left: 10px;
+ }
+ .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
+ #main-content > details.rustdoc-toggle:not(.top-doc) > summary::before,
+ #main-content > div > details.rustdoc-toggle > summary::before {
+ left: -11px;
+ }
+}
+
+@media print {
+ nav.sidebar, nav.sub, .content .out-of-band, a.srclink, #copy-path,
+ details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before,
+ details.rustdoc-toggle.top-doc > summary {
+ display: none;
+ }
+
+ .docblock {
+ margin-left: 0;
+ }
+
+ main {
+ padding: 10px;
+ }
+}
+
+@media (max-width: 464px) {
+ #titles, #titles > button {
+ height: 73px;
+ }
+
+ #main-content > table:not(.table-display) td {
+ word-break: break-word;
+ width: 50%;
+ }
+
+ #crate-search {
+ border-radius: 4px;
+ }
+
+ .docblock {
+ margin-left: 12px;
+ }
+
+ .docblock code {
+ overflow-wrap: break-word;
+ overflow-wrap: anywhere;
+ }
+
+ .sub-container {
+ flex-direction: column;
+ }
+
+ .sub-logo-container {
+ align-self: center;
+ }
+
+ .source .sub-logo-container > img {
+ height: 35px;
+ width: 35px;
+ }
+
+ #sidebar-toggle {
+ top: 10px;
+ }
+ .source-sidebar-expanded #sidebar-toggle {
+ top: unset;
+ }
+}
+
+.method-toggle summary,
+.implementors-toggle summary,
+.impl {
+ margin-bottom: 0.75em;
+}
+
+.method-toggle[open] {
+ margin-bottom: 2em;
+}
+
+.implementors-toggle[open] {
+ margin-bottom: 2em;
+}
+
+#trait-implementations-list .method-toggle,
+#synthetic-implementations-list .method-toggle,
+#blanket-implementations-list .method-toggle {
+ margin-bottom: 1em;
+}
+
+/* Begin: styles for --scrape-examples feature */
+
+.scraped-example-list .scrape-help {
+ margin-left: 10px;
+ padding: 0 4px;
+ font-weight: normal;
+ font-size: 12px;
+ position: relative;
+ bottom: 1px;
+ background: transparent;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 50px;
+}
+
+.scraped-example .code-wrapper {
+ position: relative;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ width: 100%;
+}
+
+.scraped-example:not(.expanded) .code-wrapper {
+ max-height: 240px;
+}
+
+.scraped-example:not(.expanded) .code-wrapper pre {
+ overflow-y: hidden;
+ max-height: 240px;
+ padding-bottom: 0;
+}
+
+.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
+ overflow-x: hidden;
+}
+
+.scraped-example .code-wrapper .prev {
+ position: absolute;
+ top: 0.25em;
+ right: 2.25em;
+ z-index: 100;
+ cursor: pointer;
+}
+
+.scraped-example .code-wrapper .next {
+ position: absolute;
+ top: 0.25em;
+ right: 1.25em;
+ z-index: 100;
+ cursor: pointer;
+}
+
+.scraped-example .code-wrapper .expand {
+ position: absolute;
+ top: 0.25em;
+ right: 0.25em;
+ z-index: 100;
+ cursor: pointer;
+}
+
+.scraped-example:not(.expanded) .code-wrapper:before {
+ content: " ";
+ width: 100%;
+ height: 5px;
+ position: absolute;
+ z-index: 100;
+ top: 0;
+}
+
+.scraped-example:not(.expanded) .code-wrapper:after {
+ content: " ";
+ width: 100%;
+ height: 5px;
+ position: absolute;
+ z-index: 100;
+ bottom: 0;
+}
+
+.scraped-example .code-wrapper .line-numbers {
+ margin: 0;
+ padding: 14px 0;
+}
+
+.scraped-example .code-wrapper .line-numbers span {
+ padding: 0 14px;
+}
+
+.scraped-example .code-wrapper .example-wrap {
+ flex: 1;
+ overflow-x: auto;
+ overflow-y: hidden;
+ margin-bottom: 0;
+}
+
+.scraped-example:not(.expanded) .code-wrapper .example-wrap {
+ overflow-x: hidden;
+}
+
+.scraped-example .code-wrapper .example-wrap pre.rust {
+ overflow-x: inherit;
+ width: inherit;
+ overflow-y: hidden;
+}
+
+
+.more-examples-toggle {
+ max-width: calc(100% + 25px);
+ margin-top: 10px;
+ margin-left: -25px;
+}
+
+.more-examples-toggle .hide-more {
+ margin-left: 25px;
+ margin-bottom: 5px;
+ cursor: pointer;
+}
+
+.more-scraped-examples {
+ margin-left: 5px;
+ display: flex;
+ flex-direction: row;
+}
+
+.more-scraped-examples-inner {
+ /* 20px is width of toggle-line + toggle-line-inner */
+ width: calc(100% - 20px);
+}
+
+.toggle-line {
+ align-self: stretch;
+ margin-right: 10px;
+ margin-top: 5px;
+ padding: 0 4px;
+ cursor: pointer;
+}
+
+.toggle-line-inner {
+ min-width: 2px;
+ height: 100%;
+}
+
+.more-scraped-examples .scraped-example {
+ margin-bottom: 20px;
+}
+
+.more-scraped-examples .scraped-example:last-child {
+ margin-bottom: 0;
+}
+
+.example-links a {
+ margin-top: 20px;
+}
+
+.example-links ul {
+ margin-bottom: 0;
+}
+
+/* End: styles for --scrape-examples feature */
diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css
new file mode 100644
index 000000000..e82ec0426
--- /dev/null
+++ b/src/librustdoc/html/static/css/settings.css
@@ -0,0 +1,90 @@
+.setting-line {
+ margin: 0.6em 0 0.6em 0.3em;
+ position: relative;
+}
+
+.setting-line .choices {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.setting-line .radio-line input {
+ margin-right: 0.3em;
+ height: 1.2rem;
+ width: 1.2rem;
+ border: 1px solid;
+ outline: none;
+ -webkit-appearance: none;
+ cursor: pointer;
+ border-radius: 50%;
+}
+.setting-line .radio-line input + span {
+ padding-bottom: 1px;
+}
+
+.radio-line .setting-name {
+ width: 100%;
+}
+
+.radio-line .choice {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+ min-width: 3.8em;
+ padding: 0.3em;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+}
+.radio-line .choice + .choice {
+ margin-left: 0.5em;
+}
+
+.toggle {
+ position: relative;
+ width: 100%;
+ margin-right: 20px;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+}
+
+.toggle input {
+ opacity: 0;
+ position: absolute;
+}
+
+.slider {
+ position: relative;
+ width: 45px;
+ min-width: 45px;
+ display: block;
+ height: 28px;
+ margin-right: 20px;
+ cursor: pointer;
+ background-color: #ccc;
+ transition: .3s;
+}
+
+.slider:before {
+ position: absolute;
+ content: "";
+ height: 19px;
+ width: 19px;
+ left: 4px;
+ bottom: 4px;
+ transition: .3s;
+}
+
+input:checked + .slider:before {
+ transform: translateX(19px);
+}
+
+.setting-line > .sub-settings {
+ padding-left: 42px;
+ width: 100%;
+ display: block;
+}
+
+#settings .setting-line {
+ margin: 1.2em 0.6em;
+}
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
new file mode 100644
index 000000000..c42cac59b
--- /dev/null
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -0,0 +1,563 @@
+/*
+Based off of the Ayu theme
+Original by Dempfi (https://github.com/dempfi/ayu)
+*/
+
+:root {
+ --main-background-color: #0f1419;
+ --main-color: #c5c5c5;
+ --settings-input-color: #ffb454;
+ --sidebar-background-color: #14191f;
+ --sidebar-background-color-hover: rgba(70, 70, 70, 0.33);
+ --code-block-background-color: #191f26;
+ --scrollbar-track-background-color: transparent;
+ --scrollbar-thumb-background-color: #5c6773;
+ --scrollbar-color: #5c6773 #24292f;
+ --headings-border-bottom-color: #5c6773;
+}
+
+.slider {
+ background-color: #ccc;
+}
+.slider:before {
+ background-color: white;
+}
+input:focus + .slider {
+ box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+}
+
+h1, h2, h3, h4 {
+ color: white;
+}
+h1.fqn a {
+ color: #fff;
+}
+h4 {
+ border: none;
+}
+
+.in-band {
+ background-color: #0f1419;
+}
+
+.docblock code {
+ color: #ffb454;
+}
+.code-header {
+ color: #e6e1cf;
+}
+.docblock pre > code, pre > code {
+ color: #e6e1cf;
+}
+span code {
+ color: #e6e1cf;
+}
+.docblock a > code {
+ color: #39AFD7 !important;
+}
+pre, .rustdoc.source .example-wrap {
+ color: #e6e1cf;
+}
+
+.rust-logo {
+ filter: drop-shadow(1px 0 0px #fff)
+ drop-shadow(0 1px 0 #fff)
+ drop-shadow(-1px 0 0 #fff)
+ drop-shadow(0 -1px 0 #fff);
+}
+
+.sidebar .current,
+.sidebar a:hover {
+ background-color: transparent;
+ color: #ffb44c;
+}
+
+.sidebar-elems .location {
+ color: #ff7733;
+}
+
+.line-numbers span { color: #5c6773; }
+.line-numbers .line-highlighted {
+ color: #708090;
+ background-color: rgba(255, 236, 164, 0.06);
+ padding-right: 4px;
+ border-right: 1px solid #ffb44c;
+}
+
+.docblock table td, .docblock table th {
+ border-color: #5c6773;
+}
+
+.search-results a:hover {
+ background-color: #777;
+}
+
+.search-results a:focus {
+ color: #000 !important;
+ background-color: #c6afb3;
+}
+.search-results a {
+ color: #0096cf;
+}
+.search-results a div.desc {
+ color: #c5c5c5;
+}
+
+.content .item-info::before { color: #ccc; }
+
+.content span.foreigntype, .content a.foreigntype { color: #ffa0a5; }
+.content span.union, .content a.union { color: #ffa0a5; }
+.content span.constant, .content a.constant,
+.content span.static, .content a.static { color: #39AFD7; }
+.content span.primitive, .content a.primitive { color: #ffa0a5; }
+.content span.traitalias, .content a.traitalias { color: #39AFD7; }
+.content span.keyword, .content a.keyword { color: #39AFD7; }
+
+.content span.externcrate, .content span.mod, .content a.mod {
+ color: #39AFD7;
+}
+.content span.struct, .content a.struct {
+ color: #ffa0a5;
+}
+.content span.enum, .content a.enum {
+ color: #ffa0a5;
+}
+.content span.trait, .content a.trait {
+ color: #39AFD7;
+}
+.content span.type, .content a.type {
+ color: #39AFD7;
+}
+.content span.type,
+.content a.type,
+.block a.current.type { color: #39AFD7; }
+.content span.associatedtype,
+.content a.associatedtype,
+.block a.current.associatedtype { color: #39AFD7; }
+.content span.fn, .content a.fn, .content span.method,
+.content a.method, .content span.tymethod,
+.content a.tymethod, .content .fnname {
+ color: #fdd687;
+}
+.content span.attr, .content a.attr, .content span.derive,
+.content a.derive, .content span.macro, .content a.macro {
+ color: #a37acc;
+}
+
+.sidebar a { color: #53b1db; }
+.sidebar a.current.type { color: #53b1db; }
+.sidebar a.current.associatedtype { color: #53b1db; }
+
+pre.rust .comment { color: #788797; }
+pre.rust .doccomment { color: #a1ac88; }
+
+nav.main .current {
+ border-top-color: #5c6773;
+ border-bottom-color: #5c6773;
+}
+nav.main .separator {
+ border: 1px solid #5c6773;
+}
+a {
+ color: #39AFD7;
+}
+
+.sidebar h2 a,
+.sidebar h3 a {
+ color: white;
+}
+.search-results a {
+ color: #0096cf;
+}
+body.source .example-wrap pre.rust a {
+ background: #333;
+}
+
+details.rustdoc-toggle > summary.hideme > span,
+details.rustdoc-toggle > summary::before {
+ color: #999;
+}
+
+details.rustdoc-toggle > summary::before {
+ filter: invert(100%);
+}
+
+#crate-search, .search-input {
+ background-color: #141920;
+ border-color: #424c57;
+}
+
+#crate-search {
+ /* Without the `!important`, the border-color is ignored for `<select>`...
+ It cannot be in the group above because `.search-input` has a different border color on
+ hover. */
+ border-color: #424c57 !important;
+}
+
+.search-input {
+ color: #ffffff;
+}
+
+.module-item .stab,
+.import-item .stab {
+ color: #000;
+}
+
+/* Created this empty rule to satisfy the theme checks. */
+.stab.empty-impl {}
+.stab.must_implement {}
+
+.stab.unstable,
+.stab.deprecated,
+.stab.portability,
+.stab.empty-impl,
+.stab.must_implement {
+ color: #c5c5c5;
+ background: #314559 !important;
+ border-style: none !important;
+ border-radius: 4px;
+ padding: 3px 6px 3px 6px;
+}
+
+.stab.portability > code {
+ color: #e6e1cf;
+ background: none;
+}
+
+.rightside,
+.out-of-band {
+ color: grey;
+}
+
+.result-name .primitive > i, .result-name .keyword > i {
+ color: #788797;
+}
+
+.line-numbers :target { background-color: transparent; }
+
+/* Code highlighting */
+pre.rust .number, pre.rust .string { color: #b8cc52; }
+pre.rust .kw, pre.rust .kw-2, pre.rust .prelude-ty,
+pre.rust .bool-val, pre.rust .prelude-val,
+pre.rust .op, pre.rust .lifetime { color: #ff7733; }
+pre.rust .macro, pre.rust .macro-nonterminal { color: #a37acc; }
+pre.rust .question-mark {
+ color: #ff9011;
+}
+pre.rust .self {
+ color: #36a3d9;
+ font-style: italic;
+}
+pre.rust .attribute {
+ color: #e6e1cf;
+}
+pre.rust .attribute .ident, pre.rust .attribute .op {
+ color: #e6e1cf;
+}
+
+.example-wrap > pre.line-number {
+ color: #5c67736e;
+ border: none;
+}
+
+a.test-arrow {
+ font-size: 100%;
+ color: #788797;
+ border-radius: 4px;
+ background-color: rgba(57, 175, 215, 0.09);
+}
+
+a.test-arrow:hover {
+ background-color: rgba(57, 175, 215, 0.368);
+ color: #c5c5c5;
+}
+
+.toggle-label,
+.code-attribute {
+ color: #999;
+}
+
+:target {
+ background: rgba(255, 236, 164, 0.06);
+ border-right: 3px solid rgba(255, 180, 76, 0.85);
+}
+
+pre.compile_fail {
+ border-left: 2px solid rgba(255,0,0,.4);
+}
+
+pre.compile_fail:hover, .information:hover + pre.compile_fail {
+ border-left: 2px solid #f00;
+}
+
+pre.should_panic {
+ border-left: 2px solid rgba(255,0,0,.4);
+}
+
+pre.should_panic:hover, .information:hover + pre.should_panic {
+ border-left: 2px solid #f00;
+}
+
+pre.ignore {
+ border-left: 2px solid rgba(255,142,0,.6);
+}
+
+pre.ignore:hover, .information:hover + pre.ignore {
+ border-left: 2px solid #ff9200;
+}
+
+.tooltip.compile_fail {
+ color: rgba(255,0,0,.5);
+}
+
+.information > .compile_fail:hover {
+ color: #f00;
+}
+
+.tooltip.should_panic {
+ color: rgba(255,0,0,.5);
+}
+
+.information > .should_panic:hover {
+ color: #f00;
+}
+
+.tooltip.ignore {
+ color: rgba(255,142,0,.6);
+}
+
+.information > .ignore:hover {
+ color: #ff9200;
+}
+
+.search-failed a {
+ color: #39AFD7;
+}
+
+.tooltip::after {
+ background-color: #314559;
+ color: #c5c5c5;
+ border: 1px solid #5c6773;
+}
+
+.tooltip::before {
+ border-color: transparent #314559 transparent transparent;
+}
+
+.notable-traits-tooltiptext {
+ background-color: #314559;
+ border-color: #5c6773;
+}
+
+.notable-traits-tooltiptext .notable {
+ border-bottom-color: #5c6773;
+}
+
+#titles > button.selected {
+ background-color: #141920 !important;
+ border-bottom: 1px solid #ffb44c !important;
+ border-top: none;
+}
+
+#titles > button:not(.selected) {
+ background-color: transparent !important;
+ border: none;
+}
+
+#titles > button:hover {
+ border-bottom: 1px solid rgba(242, 151, 24, 0.3);
+}
+
+#titles > button > div.count {
+ color: #888;
+}
+
+/* rules that this theme does not need to set, here to satisfy the rule checker */
+/* note that a lot of these are partially set in some way (meaning they are set
+individually rather than as a group) */
+/* FIXME: these rules should be at the bottom of the file but currently must be
+above the `@media (max-width: 700px)` rules due to a bug in the css checker */
+/* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */
+.search-input:focus {}
+.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,
+.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro {}
+.content span.struct,.content a.struct,.block a.current.struct {}
+#titles>button:hover,#titles>button.selected {}
+.content span.typedef,.content a.typedef,.block a.current.typedef {}
+.content span.union,.content a.union,.block a.current.union {}
+pre.rust .lifetime {}
+.stab.unstable {}
+h2,
+h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {}
+.content span.enum,.content a.enum,.block a.current.enum {}
+.content span.constant,.content a.constant,.block a.current.constant,.content span.static,
+.content a.static, .block a.current.static {}
+.content span.keyword,.content a.keyword,.block a.current.keyword {}
+pre.rust .comment {}
+.content span.traitalias,.content a.traitalias,.block a.current.traitalias {}
+.content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,
+.block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,
+.content .fnname {}
+pre.rust .kw {}
+pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,
+pre.rust .attribute .ident {}
+.content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype {}
+pre.rust .doccomment {}
+.stab.deprecated {}
+.content a.attr,.content a.derive,.content a.macro {}
+.stab.portability {}
+.content span.primitive,.content a.primitive,.block a.current.primitive {}
+.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod {}
+pre.rust .kw-2,pre.rust .prelude-ty {}
+.content span.trait,.content a.trait,.block a.current.trait {}
+
+.search-results a:focus span {}
+a.result-trait:focus {}
+a.result-traitalias:focus {}
+a.result-mod:focus,
+a.result-externcrate:focus {}
+a.result-mod:focus {}
+a.result-externcrate:focus {}
+a.result-enum:focus {}
+a.result-struct:focus {}
+a.result-union:focus {}
+a.result-fn:focus,
+a.result-method:focus,
+a.result-tymethod:focus {}
+a.result-type:focus {}
+a.result-associatedtype:focus {}
+a.result-foreigntype:focus {}
+a.result-attr:focus,
+a.result-derive:focus,
+a.result-macro:focus {}
+a.result-constant:focus,
+a.result-static:focus {}
+a.result-primitive:focus {}
+a.result-keyword:focus {}
+
+.sidebar a.current.enum {}
+.sidebar a.current.struct {}
+.sidebar a.current.foreigntype {}
+.sidebar a.current.attr,
+.sidebar a.current.derive,
+.sidebar a.current.macro {}
+.sidebar a.current.union {}
+.sidebar a.current.constant
+.sidebar a.current.static {}
+.sidebar a.current.primitive {}
+.sidebar a.current.externcrate
+.sidebar a.current.mod {}
+.sidebar a.current.trait {}
+.sidebar a.current.traitalias {}
+.sidebar a.current.fn,
+.sidebar a.current.method,
+.sidebar a.current.tymethod {}
+.sidebar a.current.keyword {}
+
+@media (max-width: 700px) {
+ .sidebar-elems {
+ border-right-color: #5c6773;
+ }
+}
+
+kbd {
+ color: #c5c5c5;
+ background-color: #314559;
+ border-color: #5c6773;
+ border-bottom-color: #5c6773;
+ box-shadow: inset 0 -1px 0 #5c6773;
+}
+
+#settings-menu > a, #help-button > button {
+ border-color: #5c6773;
+ background-color: #0f1419;
+ color: #fff;
+}
+
+#settings-menu > a img {
+ filter: invert(100);
+}
+
+.popover, .popover::before,
+#help-button span.top, #help-button span.bottom {
+ border-color: #5c6773;
+}
+
+#copy-path {
+ color: #fff;
+}
+#copy-path > img {
+ filter: invert(70%);
+}
+#copy-path:hover > img {
+ filter: invert(100%);
+}
+
+#settings-menu > a:hover, #settings-menu > a:focus,
+#help-button > button:hover, #help-button > button:focus {
+ border-color: #e0e0e0;
+}
+
+#theme-choices {
+ border-color: #5c6773;
+ background-color: #0f1419;
+}
+
+#theme-choices > button:not(:first-child) {
+ border-top-color: #5c6773;
+}
+
+#theme-choices > button:hover, #theme-choices > button:focus {
+ background-color: rgba(110, 110, 110, 0.33);
+}
+
+.search-results .result-name span.alias {
+ color: #c5c5c5;
+}
+.search-results .result-name span.grey {
+ color: #999;
+}
+
+#source-sidebar > .title {
+ color: #fff;
+ border-bottom-color: #5c6773;
+}
+#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
+ background-color: #14191f;
+ color: #ffb44c;
+}
+#source-sidebar div.files > a.selected {
+ background-color: #14191f;
+ color: #ffb44c;
+}
+
+.scraped-example-list .scrape-help {
+ border-color: #aaa;
+ color: #eee;
+}
+.scraped-example-list .scrape-help:hover {
+ border-color: white;
+ color: white;
+}
+.more-examples-toggle summary, .more-examples-toggle .hide-more {
+ color: #999;
+}
+.scraped-example .example-wrap .rust span.highlight {
+ background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+ background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+ background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+ background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.toggle-line-inner {
+ background: #999;
+}
+.toggle-line:hover .toggle-line-inner {
+ background: #c5c5c5;
+}
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
new file mode 100644
index 000000000..a550eb1c1
--- /dev/null
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -0,0 +1,409 @@
+:root {
+ --main-background-color: #353535;
+ --main-color: #ddd;
+ --settings-input-color: #2196f3;
+ --sidebar-background-color: #505050;
+ --sidebar-background-color-hover: #676767;
+ --code-block-background-color: #2A2A2A;
+ --scrollbar-track-background-color: #717171;
+ --scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
+ --scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
+ --headings-border-bottom-color: #d2d2d2;
+}
+
+.slider {
+ background-color: #ccc;
+}
+.slider:before {
+ background-color: white;
+}
+input:focus + .slider {
+ box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+}
+
+.in-band {
+ background-color: #353535;
+}
+
+.rust-logo {
+ filter: drop-shadow(1px 0 0px #fff)
+ drop-shadow(0 1px 0 #fff)
+ drop-shadow(-1px 0 0 #fff)
+ drop-shadow(0 -1px 0 #fff)
+}
+
+.sidebar .current,
+.sidebar a:hover {
+ background: #444;
+}
+
+.line-numbers span { color: #3B91E2; }
+.line-numbers .line-highlighted {
+ background-color: #0a042f !important;
+}
+
+.docblock table td, .docblock table th {
+ border-color: #ddd;
+}
+
+.search-results a:hover {
+ background-color: #777;
+}
+
+.search-results a:focus {
+ color: #eee !important;
+ background-color: #616161;
+}
+.search-results a:focus span { color: #eee !important; }
+a.result-trait:focus { background-color: #013191; }
+a.result-traitalias:focus { background-color: #013191; }
+a.result-mod:focus,
+a.result-externcrate:focus { background-color: #884719; }
+a.result-enum:focus { background-color: #194e9f; }
+a.result-struct:focus { background-color: #194e9f; }
+a.result-union:focus { background-color: #194e9f; }
+a.result-fn:focus,
+a.result-method:focus,
+a.result-tymethod:focus { background-color: #4950ed; }
+a.result-type:focus { background-color: #194e9f; }
+a.result-associatedtype:focus { background-color: #884719; }
+a.result-foreigntype:focus { background-color: #194e9f; }
+a.result-attr:focus,
+a.result-derive:focus,
+a.result-macro:focus { background-color: #217d1c; }
+a.result-constant:focus,
+a.result-static:focus { background-color: #884719; }
+a.result-primitive:focus { background-color: #194e9f; }
+a.result-keyword:focus { background-color: #884719; }
+
+.content .item-info::before { color: #ccc; }
+
+.content span.enum, .content a.enum, .block a.current.enum { color: #2dbfb8; }
+.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; }
+.content span.type, .content a.type, .block a.current.type { color: #2dbfb8; }
+.content span.associatedtype,
+.content a.associatedtype,
+.block a.current.associatedtype { color: #D2991D; }
+.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #2dbfb8; }
+.content span.attr, .content a.attr, .block a.current.attr,
+.content span.derive, .content a.derive, .block a.current.derive,
+.content span.macro, .content a.macro, .block a.current.macro { color: #09bd00; }
+.content span.union, .content a.union, .block a.current.union { color: #2dbfb8; }
+.content span.constant, .content a.constant, .block a.current.constant,
+.content span.static, .content a.static, .block a.current.static { color: #D2991D; }
+.content span.primitive, .content a.primitive, .block a.current.primitive { color: #2dbfb8; }
+.content span.externcrate,
+.content span.mod, .content a.mod, .block a.current.mod { color: #D2991D; }
+.content span.trait, .content a.trait, .block a.current.trait { color: #b78cf2; }
+.content span.traitalias, .content a.traitalias, .block a.current.traitalias { color: #b78cf2; }
+.content span.fn, .content a.fn, .block a.current.fn,
+.content span.method, .content a.method, .block a.current.method,
+.content span.tymethod, .content a.tymethod, .block a.current.tymethod,
+.content .fnname{ color: #2BAB63; }
+.content span.keyword, .content a.keyword, .block a.current.keyword { color: #D2991D; }
+
+.sidebar a { color: #fdbf35; }
+.sidebar a.current.enum { color: #12ece2; }
+.sidebar a.current.struct { color: #12ece2; }
+.sidebar a.current.type { color: #12ece2; }
+.sidebar a.current.associatedtype { color: #fdbf35; }
+.sidebar a.current.foreigntype { color: #12ece2; }
+.sidebar a.current.attr,
+.sidebar a.current.derive,
+.sidebar a.current.macro { color: #0be900; }
+.sidebar a.current.union { color: #12ece2; }
+.sidebar a.current.constant
+.sidebar a.current.static { color: #fdbf35; }
+.sidebar a.current.primitive { color: #12ece2; }
+.sidebar a.current.externcrate
+.sidebar a.current.mod { color: #fdbf35; }
+.sidebar a.current.trait { color: #cca7ff; }
+.sidebar a.current.traitalias { color: #cca7ff; }
+.sidebar a.current.fn,
+.sidebar a.current.method,
+.sidebar a.current.tymethod { color: #32d479; }
+.sidebar a.current.keyword { color: #fdbf35; }
+
+pre.rust .comment { color: #8d8d8b; }
+pre.rust .doccomment { color: #8ca375; }
+
+nav.main .current {
+ border-top-color: #eee;
+ border-bottom-color: #eee;
+}
+nav.main .separator {
+ border-color: #eee;
+}
+
+a {
+ color: #D2991D;
+}
+
+body.source .example-wrap pre.rust a {
+ background: #333;
+}
+
+details.rustdoc-toggle > summary.hideme > span,
+details.rustdoc-toggle > summary::before {
+ color: #999;
+}
+
+details.rustdoc-toggle > summary::before {
+ filter: invert(100%);
+}
+
+#crate-search, .search-input {
+ color: #111;
+ background-color: #f0f0f0;
+ border-color: #f0f0f0;
+}
+
+#crate-search {
+ /* Without the `!important`, the border-color is ignored for `<select>`...
+ It cannot be in the group above because `.search-input` has a different border color on
+ hover. */
+ border-color: #f0f0f0 !important;
+}
+
+.search-input {
+ border-color: #e0e0e0;
+}
+
+.search-input:focus {
+ border-color: #008dfd;
+}
+
+.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
+.stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
+.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; }
+.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
+.stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
+.stab.portability > code { background: none; }
+
+.rightside,
+.out-of-band {
+ color: grey;
+}
+
+.line-numbers :target { background-color: transparent; }
+
+/* Code highlighting */
+pre.rust .kw { color: #ab8ac1; }
+pre.rust .kw-2, pre.rust .prelude-ty { color: #769acb; }
+pre.rust .number, pre.rust .string { color: #83a300; }
+pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val,
+pre.rust .attribute, pre.rust .attribute .ident { color: #ee6868; }
+pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
+pre.rust .lifetime { color: #d97f26; }
+pre.rust .question-mark {
+ color: #ff9011;
+}
+
+.example-wrap > pre.line-number {
+ border-color: #4a4949;
+}
+
+a.test-arrow {
+ color: #dedede;
+ background-color: rgba(78, 139, 202, 0.2);
+}
+
+a.test-arrow:hover{
+ background-color: #4e8bca;
+}
+
+.toggle-label,
+.code-attribute {
+ color: #999;
+}
+
+:target {
+ background-color: #494a3d;
+ border-right: 3px solid #bb7410;
+}
+
+pre.compile_fail {
+ border-left: 2px solid rgba(255,0,0,.8);
+}
+
+pre.compile_fail:hover, .information:hover + pre.compile_fail {
+ border-left: 2px solid #f00;
+}
+
+pre.should_panic {
+ border-left: 2px solid rgba(255,0,0,.8);
+}
+
+pre.should_panic:hover, .information:hover + pre.should_panic {
+ border-left: 2px solid #f00;
+}
+
+pre.ignore {
+ border-left: 2px solid rgba(255,142,0,.6);
+}
+
+pre.ignore:hover, .information:hover + pre.ignore {
+ border-left: 2px solid #ff9200;
+}
+
+.tooltip.compile_fail {
+ color: rgba(255,0,0,.8);
+}
+
+.information > .compile_fail:hover {
+ color: #f00;
+}
+
+.tooltip.should_panic {
+ color: rgba(255,0,0,.8);
+}
+
+.information > .should_panic:hover {
+ color: #f00;
+}
+
+.tooltip.ignore {
+ color: rgba(255,142,0,.6);
+}
+
+.information > .ignore:hover {
+ color: #ff9200;
+}
+
+.search-failed a {
+ color: #0089ff;
+}
+
+.tooltip::after {
+ background-color: #000;
+ color: #fff;
+ border-color: #000;
+}
+
+.tooltip::before {
+ border-color: transparent black transparent transparent;
+}
+
+.notable-traits-tooltiptext {
+ background-color: #111;
+ border-color: #777;
+}
+
+.notable-traits-tooltiptext .notable {
+ border-bottom-color: #d2d2d2;
+}
+
+#titles > button:not(.selected) {
+ background-color: #252525;
+ border-top-color: #252525;
+}
+
+#titles > button:hover, #titles > button.selected {
+ border-top-color: #0089ff;
+ background-color: #353535;
+}
+
+#titles > button > div.count {
+ color: #888;
+}
+
+@media (max-width: 700px) {
+ .sidebar-elems {
+ border-right-color: #000;
+ }
+}
+
+kbd {
+ color: #000;
+ background-color: #fafbfc;
+ border-color: #d1d5da;
+ border-bottom-color: #c6cbd1;
+ box-shadow: inset 0 -1px 0 #c6cbd1;
+}
+
+#settings-menu > a, #help-button > button {
+ border-color: #e0e0e0;
+ background: #f0f0f0;
+ color: #000;
+}
+
+#settings-menu > a:hover, #settings-menu > a:focus,
+#help-button > button:hover, #help-button > button:focus {
+ border-color: #ffb900;
+}
+
+.popover, .popover::before,
+#help-button span.top, #help-button span.bottom {
+ border-color: #d2d2d2;
+}
+
+#copy-path {
+ color: #999;
+}
+#copy-path > img {
+ filter: invert(50%);
+}
+#copy-path:hover > img {
+ filter: invert(65%);
+}
+
+#theme-choices {
+ border-color: #e0e0e0;
+ background-color: #353535;
+}
+
+#theme-choices > button:not(:first-child) {
+ border-top-color: #e0e0e0;
+}
+
+#theme-choices > button:hover, #theme-choices > button:focus {
+ background-color: #4e4e4e;
+}
+
+.search-results .result-name span.alias {
+ color: #fff;
+}
+.search-results .result-name span.grey {
+ color: #ccc;
+}
+
+#source-sidebar > .title {
+ border-bottom-color: #ccc;
+}
+#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
+ background-color: #444;
+}
+#source-sidebar div.files > a.selected {
+ background-color: #333;
+}
+
+.scraped-example-list .scrape-help {
+ border-color: #aaa;
+ color: #eee;
+}
+.scraped-example-list .scrape-help:hover {
+ border-color: white;
+ color: white;
+}
+.more-examples-toggle summary, .more-examples-toggle .hide-more {
+ color: #999;
+}
+.scraped-example .example-wrap .rust span.highlight {
+ background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+ background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+ background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+ background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.toggle-line-inner {
+ background: #999;
+}
+.toggle-line:hover .toggle-line-inner {
+ background: #c5c5c5;
+}
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
new file mode 100644
index 000000000..b751acff1
--- /dev/null
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -0,0 +1,395 @@
+:root {
+ --main-background-color: white;
+ --main-color: black;
+ --settings-input-color: #2196f3;
+ --sidebar-background-color: #F5F5F5;
+ --sidebar-background-color-hover: #E0E0E0;
+ --code-block-background-color: #F5F5F5;
+ --scrollbar-track-background-color: #dcdcdc;
+ --scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
+ --scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
+ --headings-border-bottom-color: #ddd;
+}
+
+.slider {
+ background-color: #ccc;
+}
+.slider:before {
+ background-color: white;
+}
+input:focus + .slider {
+ box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+}
+
+.in-band {
+ background-color: white;
+}
+
+.rust-logo {
+ /* This rule exists to force other themes to explicitly style the logo.
+ * Rustdoc has a custom linter for this purpose.
+ */
+}
+
+.sidebar .current,
+.sidebar a:hover {
+ background-color: #fff;
+}
+
+.line-numbers span { color: #c67e2d; }
+.line-numbers .line-highlighted {
+ background-color: #FDFFD3 !important;
+}
+
+.docblock table td, .docblock table th {
+ border-color: #ddd;
+}
+
+.search-results a:hover {
+ background-color: #ddd;
+}
+
+.search-results a:focus {
+ color: #000 !important;
+ background-color: #ccc;
+}
+.search-results a:focus span { color: #000 !important; }
+a.result-trait:focus { background-color: #c7b6ff; }
+a.result-traitalias:focus { background-color: #c7b6ff; }
+a.result-mod:focus,
+a.result-externcrate:focus { background-color: #afc6e4; }
+a.result-enum:focus { background-color: #e7b1a0; }
+a.result-struct:focus { background-color: #e7b1a0; }
+a.result-union:focus { background-color: #e7b1a0; }
+a.result-fn:focus,
+a.result-method:focus,
+a.result-tymethod:focus { background-color: #c6afb3; }
+a.result-type:focus { background-color: #e7b1a0; }
+a.result-associatedtype:focus { background-color: #afc6e4; }
+a.result-foreigntype:focus { background-color: #e7b1a0; }
+a.result-attr:focus,
+a.result-derive:focus,
+a.result-macro:focus { background-color: #8ce488; }
+a.result-constant:focus,
+a.result-static:focus { background-color: #afc6e4; }
+a.result-primitive:focus { background-color: #e7b1a0; }
+a.result-keyword:focus { background-color: #afc6e4; }
+
+.content .item-info::before { color: #ccc; }
+
+.content span.enum, .content a.enum, .block a.current.enum { color: #AD378A; }
+.content span.struct, .content a.struct, .block a.current.struct { color: #AD378A; }
+.content span.type, .content a.type, .block a.current.type { color: #AD378A; }
+.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #3873AD; }
+.content span.associatedtype,
+.content a.associatedtype,
+.block a.current.associatedtype { color: #3873AD; }
+.content span.attr, .content a.attr, .block a.current.attr,
+.content span.derive, .content a.derive, .block a.current.derive,
+.content span.macro, .content a.macro, .block a.current.macro { color: #068000; }
+.content span.union, .content a.union, .block a.current.union { color: #AD378A; }
+.content span.constant, .content a.constant, .block a.current.constant,
+.content span.static, .content a.static, .block a.current.static { color: #3873AD; }
+.content span.primitive, .content a.primitive, .block a.current.primitive { color: #AD378A; }
+.content span.externcrate,
+.content span.mod, .content a.mod, .block a.current.mod { color: #3873AD; }
+.content span.trait, .content a.trait, .block a.current.trait { color: #6E4FC9; }
+.content span.traitalias, .content a.traitalias, .block a.current.traitalias { color: #5137AD; }
+.content span.fn, .content a.fn, .block a.current.fn,
+.content span.method, .content a.method, .block a.current.method,
+.content span.tymethod, .content a.tymethod, .block a.current.tymethod,
+.content .fnname { color: #AD7C37; }
+.content span.keyword, .content a.keyword, .block a.current.keyword { color: #3873AD; }
+
+.sidebar a { color: #356da4; }
+.sidebar a.current.enum { color: #a63283; }
+.sidebar a.current.struct { color: #a63283; }
+.sidebar a.current.type { color: #a63283; }
+.sidebar a.current.associatedtype { color: #356da4; }
+.sidebar a.current.foreigntype { color: #356da4; }
+.sidebar a.current.attr,
+.sidebar a.current.derive,
+.sidebar a.current.macro { color: #067901; }
+.sidebar a.current.union { color: #a63283; }
+.sidebar a.current.constant
+.sidebar a.current.static { color: #356da4; }
+.sidebar a.current.primitive { color: #a63283; }
+.sidebar a.current.externcrate
+.sidebar a.current.mod { color: #356da4; }
+.sidebar a.current.trait { color: #6849c3; }
+.sidebar a.current.traitalias { color: #4b349e; }
+.sidebar a.current.fn,
+.sidebar a.current.method,
+.sidebar a.current.tymethod { color: #a67736; }
+.sidebar a.current.keyword { color: #356da4; }
+
+nav.main .current {
+ border-top-color: #000;
+ border-bottom-color: #000;
+}
+nav.main .separator {
+ border: 1px solid #000;
+}
+
+a {
+ color: #3873AD;
+}
+
+body.source .example-wrap pre.rust a {
+ background: #eee;
+}
+
+details.rustdoc-toggle > summary.hideme > span,
+details.rustdoc-toggle > summary::before {
+ color: #999;
+}
+
+#crate-search, .search-input {
+ background-color: white;
+ border-color: #e0e0e0;
+}
+
+#crate-search {
+ /* Without the `!important`, the border-color is ignored for `<select>`...
+ It cannot be in the group above because `.search-input` has a different border color on
+ hover. */
+ border-color: #e0e0e0 !important;
+}
+
+.search-input:focus {
+ border-color: #66afe9;
+}
+
+.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; }
+.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
+.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; }
+.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; }
+.stab.portability { background: #F3DFFF; border-color: #b07bdb; }
+.stab.portability > code { background: none; }
+
+.rightside,
+.out-of-band {
+ color: grey;
+}
+
+.line-numbers :target { background-color: transparent; }
+
+/* Code highlighting */
+pre.rust .kw { color: #8959A8; }
+pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
+pre.rust .number, pre.rust .string { color: #718C00; }
+pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val,
+pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
+pre.rust .comment { color: #8E908C; }
+pre.rust .doccomment { color: #4D4D4C; }
+pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
+pre.rust .lifetime { color: #B76514; }
+pre.rust .question-mark {
+ color: #ff9011;
+}
+
+.example-wrap > pre.line-number {
+ border-color: #c7c7c7;
+}
+
+a.test-arrow {
+ color: #f5f5f5;
+ background-color: rgba(78, 139, 202, 0.2);
+}
+
+a.test-arrow:hover{
+ background-color: #4e8bca;
+}
+
+.toggle-label,
+.code-attribute {
+ color: #999;
+}
+
+:target {
+ background: #FDFFD3;
+ border-right: 3px solid #AD7C37;
+}
+
+pre.compile_fail {
+ border-left: 2px solid rgba(255,0,0,.5);
+}
+
+pre.compile_fail:hover, .information:hover + pre.compile_fail {
+ border-left: 2px solid #f00;
+}
+
+pre.should_panic {
+ border-left: 2px solid rgba(255,0,0,.5);
+}
+
+pre.should_panic:hover, .information:hover + pre.should_panic {
+ border-left: 2px solid #f00;
+}
+
+pre.ignore {
+ border-left: 2px solid rgba(255,142,0,.6);
+}
+
+pre.ignore:hover, .information:hover + pre.ignore {
+ border-left: 2px solid #ff9200;
+}
+
+.tooltip.compile_fail {
+ color: rgba(255,0,0,.5);
+}
+
+.information > .compile_fail:hover {
+ color: #f00;
+}
+
+.tooltip.should_panic {
+ color: rgba(255,0,0,.5);
+}
+
+.information > .should_panic:hover {
+ color: #f00;
+}
+
+.tooltip.ignore {
+ color: rgba(255,142,0,.6);
+}
+
+.information > .ignore:hover {
+ color: #ff9200;
+}
+
+.search-failed a {
+ color: #3873AD;
+}
+
+.tooltip::after {
+ background-color: #000;
+ color: #fff;
+}
+
+.tooltip::before {
+ border-color: transparent black transparent transparent;
+}
+
+.notable-traits-tooltiptext {
+ background-color: #eee;
+ border-color: #999;
+}
+
+.notable-traits-tooltiptext .notable {
+ border-bottom-color: #DDDDDD;
+}
+
+#titles > button:not(.selected) {
+ background-color: #e6e6e6;
+ border-top-color: #e6e6e6;
+}
+
+#titles > button:hover, #titles > button.selected {
+ background-color: #ffffff;
+ border-top-color: #0089ff;
+}
+
+#titles > button > div.count {
+ color: #888;
+}
+
+@media (max-width: 700px) {
+ .sidebar-elems {
+ border-right-color: #000;
+ }
+}
+
+kbd {
+ color: #000;
+ background-color: #fafbfc;
+ border-color: #d1d5da;
+ border-bottom-color: #c6cbd1;
+ box-shadow: inset 0 -1px 0 #c6cbd1;
+}
+
+#settings-menu > a, #help-button > button {
+ border-color: #e0e0e0;
+ background-color: #fff;
+}
+
+#settings-menu > a:hover, #settings-menu > a:focus,
+#help-button > button:hover, #help-button > button:focus {
+ border-color: #717171;
+}
+
+.popover, .popover::before,
+#help-button span.top, #help-button span.bottom {
+ border-color: #DDDDDD;
+}
+
+#copy-path {
+ color: #999;
+}
+#copy-path > img {
+ filter: invert(50%);
+}
+#copy-path:hover > img {
+ filter: invert(35%);
+}
+
+#theme-choices {
+ border-color: #ccc;
+ background-color: #fff;
+}
+
+#theme-choices > button:not(:first-child) {
+ border-top-color: #e0e0e0;
+}
+
+#theme-choices > button:hover, #theme-choices > button:focus {
+ background-color: #eee;
+}
+
+.search-results .result-name span.alias {
+ color: #000;
+}
+.search-results .result-name span.grey {
+ color: #999;
+}
+
+#source-sidebar > .title {
+ border-bottom-color: #ccc;
+}
+#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
+ background-color: #E0E0E0;
+}
+#source-sidebar div.files > a.selected {
+ background-color: #fff;
+}
+.scraped-example-list .scrape-help {
+ border-color: #555;
+ color: #333;
+}
+.scraped-example-list .scrape-help:hover {
+ border-color: black;
+ color: black;
+}
+.more-examples-toggle summary, .more-examples-toggle .hide-more {
+ color: #999;
+}
+.scraped-example .example-wrap .rust span.highlight {
+ background: #fcffd6;
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+ background: #f6fdb0;
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+ background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+ background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+.toggle-line-inner {
+ background: #ccc;
+}
+.toggle-line:hover .toggle-line-inner {
+ background: #999;
+}
diff --git a/src/librustdoc/html/static/fonts/FiraSans-LICENSE.txt b/src/librustdoc/html/static/fonts/FiraSans-LICENSE.txt
new file mode 100644
index 000000000..ff9afab06
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/FiraSans-LICENSE.txt
@@ -0,0 +1,94 @@
+Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
+with Reserved Font Name < Fira >,
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/src/librustdoc/html/static/fonts/FiraSans-Medium.woff2 b/src/librustdoc/html/static/fonts/FiraSans-Medium.woff2
new file mode 100644
index 000000000..7a1e5fc54
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/FiraSans-Medium.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/fonts/FiraSans-Regular.woff2 b/src/librustdoc/html/static/fonts/FiraSans-Regular.woff2
new file mode 100644
index 000000000..e766e06cc
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/FiraSans-Regular.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/fonts/NanumBarunGothic-LICENSE.txt b/src/librustdoc/html/static/fonts/NanumBarunGothic-LICENSE.txt
new file mode 100644
index 000000000..0bf46682b
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/NanumBarunGothic-LICENSE.txt
@@ -0,0 +1,99 @@
+Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/),
+
+with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic,
+NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen,
+Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco,
+NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic,
+Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2 b/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2
new file mode 100644
index 000000000..1866ad4bc
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/fonts/SourceCodePro-It.ttf.woff2 b/src/librustdoc/html/static/fonts/SourceCodePro-It.ttf.woff2
new file mode 100644
index 000000000..462c34efc
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/SourceCodePro-It.ttf.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/fonts/SourceCodePro-LICENSE.txt b/src/librustdoc/html/static/fonts/SourceCodePro-LICENSE.txt
new file mode 100644
index 000000000..07542572e
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/SourceCodePro-LICENSE.txt
@@ -0,0 +1,93 @@
+Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+
+This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/src/librustdoc/html/static/fonts/SourceCodePro-Regular.ttf.woff2 b/src/librustdoc/html/static/fonts/SourceCodePro-Regular.ttf.woff2
new file mode 100644
index 000000000..10b558e0b
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/SourceCodePro-Regular.ttf.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/fonts/SourceCodePro-Semibold.ttf.woff2 b/src/librustdoc/html/static/fonts/SourceCodePro-Semibold.ttf.woff2
new file mode 100644
index 000000000..5ec64eef0
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/SourceCodePro-Semibold.ttf.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff2 b/src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff2
new file mode 100644
index 000000000..db57d2145
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff2 b/src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff2
new file mode 100644
index 000000000..1cbc021a3
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/fonts/SourceSerif4-LICENSE.md b/src/librustdoc/html/static/fonts/SourceSerif4-LICENSE.md
new file mode 100644
index 000000000..68ea18924
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/SourceSerif4-LICENSE.md
@@ -0,0 +1,93 @@
+Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+
+This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff2 b/src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff2
new file mode 100644
index 000000000..2db73fe2b
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/images/clipboard.svg b/src/librustdoc/html/static/images/clipboard.svg
new file mode 100644
index 000000000..8adbd9963
--- /dev/null
+++ b/src/librustdoc/html/static/images/clipboard.svg
@@ -0,0 +1 @@
+<svg width="24" height="25" viewBox="0 0 24 25" xmlns="http://www.w3.org/2000/svg" aria-label="Copy to clipboard"><path d="M18 20h2v3c0 1-1 2-2 2H2c-.998 0-2-1-2-2V5c0-.911.755-1.667 1.667-1.667h5A3.323 3.323 0 0110 0a3.323 3.323 0 013.333 3.333h5C19.245 3.333 20 4.09 20 5v8.333h-2V9H2v14h16v-3zM3 7h14c0-.911-.793-1.667-1.75-1.667H13.5c-.957 0-1.75-.755-1.75-1.666C11.75 2.755 10.957 2 10 2s-1.75.755-1.75 1.667c0 .911-.793 1.666-1.75 1.666H4.75C3.793 5.333 3 6.09 3 7z"/><path d="M4 19h6v2H4zM12 11H4v2h8zM4 17h4v-2H4zM15 15v-3l-4.5 4.5L15 21v-3l8.027-.032L23 15z"/></svg>
diff --git a/src/librustdoc/html/static/images/down-arrow.svg b/src/librustdoc/html/static/images/down-arrow.svg
new file mode 100644
index 000000000..35437e77a
--- /dev/null
+++ b/src/librustdoc/html/static/images/down-arrow.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg> \ No newline at end of file
diff --git a/src/librustdoc/html/static/images/favicon-16x16.png b/src/librustdoc/html/static/images/favicon-16x16.png
new file mode 100644
index 000000000..ea4b45cae
--- /dev/null
+++ b/src/librustdoc/html/static/images/favicon-16x16.png
Binary files differ
diff --git a/src/librustdoc/html/static/images/favicon-32x32.png b/src/librustdoc/html/static/images/favicon-32x32.png
new file mode 100644
index 000000000..69b8613ce
--- /dev/null
+++ b/src/librustdoc/html/static/images/favicon-32x32.png
Binary files differ
diff --git a/src/librustdoc/html/static/images/favicon.svg b/src/librustdoc/html/static/images/favicon.svg
new file mode 100644
index 000000000..8b34b5119
--- /dev/null
+++ b/src/librustdoc/html/static/images/favicon.svg
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;">
+<defs>
+ <style type="text/css"><![CDATA[
+ #logo {
+ fill-rule: nonzero;
+ }
+ #logo-teeth {
+ stroke: #000000;
+ stroke-width: 0.92px;
+ }
+ @media (prefers-color-scheme: dark) {
+ #logo {
+ fill: #FFFFFF;
+ fill-rule: nonzero;
+ }
+ #logo-teeth {
+ fill: #FFFFFF;
+ stroke: #FFFFFF;
+ stroke-width: 0.92px;
+ }
+ }
+ ]]></style>
+</defs>
+<path id="logo" d="M15.993,1.54c-7.972,0 -14.461,6.492 -14.461,14.462c0,7.969 6.492,14.461 14.461,14.461c7.97,0 14.462,-6.492 14.462,-14.461c0,-7.97 -6.492,-14.462 -14.462,-14.462Zm-0.021,1.285c0.511,0.013 0.924,0.439 0.924,0.951c0,0.522 -0.43,0.952 -0.952,0.952c-0.522,0 -0.951,-0.43 -0.951,-0.952c0,0 0,0 0,0c0,-0.522 0.429,-0.952 0.951,-0.952c0.01,0 0.019,0.001 0.028,0.001Zm2.178,1.566c3.379,0.633 6.313,2.723 8.016,5.709l-1.123,2.533c-0.193,0.438 0.006,0.952 0.44,1.147l2.16,0.958c0.067,0.675 0.076,1.355 0.025,2.031l-1.202,0c-0.12,0 -0.169,0.08 -0.169,0.196l0,0.551c0,1.297 -0.731,1.582 -1.373,1.652c-0.612,0.07 -1.288,-0.257 -1.374,-0.63c-0.361,-2.029 -0.961,-2.46 -1.909,-3.21c1.178,-0.746 2.401,-1.85 2.401,-3.325c0,-1.594 -1.092,-2.597 -1.835,-3.09c-1.046,-0.688 -2.203,-0.826 -2.515,-0.826l-12.421,0c1.717,-1.918 4.02,-3.218 6.55,-3.696l1.466,1.536c0.33,0.346 0.878,0.361 1.223,0.028l1.64,-1.564Zm-13.522,7.043c0.511,0.015 0.924,0.44 0.924,0.951c0,0.522 -0.43,0.952 -0.952,0.952c-0.522,0 -0.951,-0.43 -0.951,-0.952c0,0 0,0 0,0c0,-0.522 0.429,-0.951 0.951,-0.951c0.009,0 0.019,0 0.028,0Zm22.685,0.043c0.511,0.015 0.924,0.44 0.924,0.951c0,0.522 -0.43,0.952 -0.952,0.952c-0.522,0 -0.951,-0.43 -0.951,-0.952c0,0 0,0 0,0c0,-0.522 0.429,-0.952 0.951,-0.952c0.01,0 0.019,0 0.028,0.001Zm-20.892,0.153l1.658,0l0,7.477l-3.347,0c-0.414,-1.452 -0.542,-2.97 -0.38,-4.47l2.05,-0.912c0.438,-0.195 0.637,-0.706 0.441,-1.144l-0.422,-0.951Zm6.92,0.079l3.949,0c0.205,0 1.441,0.236 1.441,1.163c0,0.768 -0.948,1.043 -1.728,1.043l-3.665,0l0.003,-2.206Zm0,5.373l3.026,0c0.275,0 1.477,0.079 1.86,1.615c0.119,0.471 0.385,2.007 0.566,2.499c0.18,0.551 0.911,1.652 1.691,1.652l4.938,0c-0.331,0.444 -0.693,0.863 -1.083,1.255l-2.01,-0.432c-0.468,-0.101 -0.93,0.199 -1.031,0.667l-0.477,2.228c-3.104,1.406 -6.672,1.389 -9.762,-0.046l-0.478,-2.228c-0.101,-0.468 -0.56,-0.767 -1.028,-0.667l-1.967,0.423c-0.365,-0.377 -0.704,-0.778 -1.016,-1.2l9.567,0c0.107,0 0.181,-0.018 0.181,-0.119l0,-3.384c0,-0.097 -0.074,-0.119 -0.181,-0.119l-2.799,0l0.003,-2.144Zm-4.415,7.749c0.512,0.015 0.924,0.44 0.924,0.951c0,0.522 -0.429,0.952 -0.951,0.952c-0.522,0 -0.952,-0.43 -0.952,-0.952c0,0 0,0 0,0c0,-0.522 0.43,-0.952 0.952,-0.952c0.009,0 0.018,0.001 0.027,0.001Zm14.089,0.043c0.511,0.015 0.924,0.439 0.923,0.951c0,0.522 -0.429,0.952 -0.951,0.952c-0.522,0 -0.951,-0.43 -0.951,-0.952c0,0 0,0 0,0c0,-0.522 0.429,-0.952 0.951,-0.952c0.009,0 0.018,0 0.028,0.001Z"/><path id="logo-teeth" d="M29.647,16.002c0,7.49 -6.163,13.653 -13.654,13.653c-7.49,0 -13.654,-6.163 -13.654,-13.653c0,-7.491 6.164,-13.654 13.654,-13.654c7.491,0 13.654,6.163 13.654,13.654Zm-0.257,-1.319l2.13,1.319l-2.13,1.318l1.83,1.71l-2.344,0.878l1.463,2.035l-2.475,0.404l1.04,2.282l-2.506,-0.089l0.575,2.442l-2.441,-0.576l0.089,2.506l-2.283,-1.04l-0.403,2.475l-2.035,-1.462l-0.878,2.343l-1.71,-1.829l-1.319,2.129l-1.318,-2.129l-1.71,1.829l-0.878,-2.343l-2.035,1.462l-0.404,-2.475l-2.282,1.04l0.089,-2.506l-2.442,0.576l0.575,-2.442l-2.505,0.089l1.04,-2.282l-2.475,-0.404l1.462,-2.035l-2.343,-0.878l1.829,-1.71l-2.129,-1.318l2.129,-1.319l-1.829,-1.71l2.343,-0.878l-1.462,-2.035l2.475,-0.404l-1.04,-2.282l2.505,0.089l-0.575,-2.441l2.442,0.575l-0.089,-2.506l2.282,1.04l0.404,-2.475l2.035,1.463l0.878,-2.344l1.71,1.83l1.318,-2.13l1.319,2.13l1.71,-1.83l0.878,2.344l2.035,-1.463l0.403,2.475l2.283,-1.04l-0.089,2.506l2.441,-0.575l-0.575,2.441l2.506,-0.089l-1.04,2.282l2.475,0.404l-1.463,2.035l2.344,0.878l-1.83,1.71Z"/></svg>
diff --git a/src/librustdoc/html/static/images/rust-logo.svg b/src/librustdoc/html/static/images/rust-logo.svg
new file mode 100644
index 000000000..62424d8ff
--- /dev/null
+++ b/src/librustdoc/html/static/images/rust-logo.svg
@@ -0,0 +1,61 @@
+<svg version="1.1" height="106" width="106" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="logo" transform="translate(53, 53)">
+ <path id="r" transform="translate(0.5, 0.5)" stroke="black" stroke-width="1" stroke-linejoin="round" d="
+ M -9,-15 H 4 C 12,-15 12,-7 4,-7 H -9 Z
+ M -40,22 H 0 V 11 H -9 V 3 H 1 C 12,3 6,22 15,22 H 40
+ V 3 H 34 V 5 C 34,13 25,12 24,7 C 23,2 19,-2 18,-2 C 33,-10 24,-26 12,-26 H -35
+ V -15 H -25 V 11 H -40 Z" />
+ <g id="gear" mask="url(#holes)">
+ <circle r="43" fill="none" stroke="black" stroke-width="9" />
+ <g id="cogs">
+ <polygon id="cog" stroke="black" stroke-width="3" stroke-linejoin="round" points="46,3 51,0 46,-3" />
+ <use xlink:href="#cog" transform="rotate(11.25)" />
+ <use xlink:href="#cog" transform="rotate(22.50)" />
+ <use xlink:href="#cog" transform="rotate(33.75)" />
+ <use xlink:href="#cog" transform="rotate(45.00)" />
+ <use xlink:href="#cog" transform="rotate(56.25)" />
+ <use xlink:href="#cog" transform="rotate(67.50)" />
+ <use xlink:href="#cog" transform="rotate(78.75)" />
+ <use xlink:href="#cog" transform="rotate(90.00)" />
+ <use xlink:href="#cog" transform="rotate(101.25)" />
+ <use xlink:href="#cog" transform="rotate(112.50)" />
+ <use xlink:href="#cog" transform="rotate(123.75)" />
+ <use xlink:href="#cog" transform="rotate(135.00)" />
+ <use xlink:href="#cog" transform="rotate(146.25)" />
+ <use xlink:href="#cog" transform="rotate(157.50)" />
+ <use xlink:href="#cog" transform="rotate(168.75)" />
+ <use xlink:href="#cog" transform="rotate(180.00)" />
+ <use xlink:href="#cog" transform="rotate(191.25)" />
+ <use xlink:href="#cog" transform="rotate(202.50)" />
+ <use xlink:href="#cog" transform="rotate(213.75)" />
+ <use xlink:href="#cog" transform="rotate(225.00)" />
+ <use xlink:href="#cog" transform="rotate(236.25)" />
+ <use xlink:href="#cog" transform="rotate(247.50)" />
+ <use xlink:href="#cog" transform="rotate(258.75)" />
+ <use xlink:href="#cog" transform="rotate(270.00)" />
+ <use xlink:href="#cog" transform="rotate(281.25)" />
+ <use xlink:href="#cog" transform="rotate(292.50)" />
+ <use xlink:href="#cog" transform="rotate(303.75)" />
+ <use xlink:href="#cog" transform="rotate(315.00)" />
+ <use xlink:href="#cog" transform="rotate(326.25)" />
+ <use xlink:href="#cog" transform="rotate(337.50)" />
+ <use xlink:href="#cog" transform="rotate(348.75)" />
+ </g>
+ <g id="mounts">
+ <polygon id="mount" stroke="black" stroke-width="6" stroke-linejoin="round" points="-7,-42 0,-35 7,-42" />
+ <use xlink:href="#mount" transform="rotate(72)" />
+ <use xlink:href="#mount" transform="rotate(144)" />
+ <use xlink:href="#mount" transform="rotate(216)" />
+ <use xlink:href="#mount" transform="rotate(288)" />
+ </g>
+ </g>
+ <mask id="holes">
+ <rect x="-60" y="-60" width="120" height="120" fill="white"/>
+ <circle id="hole" cy="-40" r="3" />
+ <use xlink:href="#hole" transform="rotate(72)" />
+ <use xlink:href="#hole" transform="rotate(144)" />
+ <use xlink:href="#hole" transform="rotate(216)" />
+ <use xlink:href="#hole" transform="rotate(288)" />
+ </mask>
+</g>
+</svg>
diff --git a/src/librustdoc/html/static/images/toggle-minus.svg b/src/librustdoc/html/static/images/toggle-minus.svg
new file mode 100644
index 000000000..73154788a
--- /dev/null
+++ b/src/librustdoc/html/static/images/toggle-minus.svg
@@ -0,0 +1 @@
+<svg width="17" height="17" shape-rendering="crispEdges" stroke="#000" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7"/></svg> \ No newline at end of file
diff --git a/src/librustdoc/html/static/images/toggle-plus.svg b/src/librustdoc/html/static/images/toggle-plus.svg
new file mode 100644
index 000000000..08b17033e
--- /dev/null
+++ b/src/librustdoc/html/static/images/toggle-plus.svg
@@ -0,0 +1 @@
+<svg width="17" height="17" shape-rendering="crispEdges" stroke="#000" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7M8.5 12V8.625v0V5"/></svg> \ No newline at end of file
diff --git a/src/librustdoc/html/static/images/wheel.svg b/src/librustdoc/html/static/images/wheel.svg
new file mode 100644
index 000000000..01da3b24c
--- /dev/null
+++ b/src/librustdoc/html/static/images/wheel.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Capa_1" width="27.434" height="29.5" enable-background="new 0 0 27.434 29.5" version="1.1" viewBox="0 0 27.434 29.5" xml:space="preserve"><g><path d="M27.315,18.389c-0.165-0.604-0.509-1.113-0.981-1.459c-0.042-0.144-0.083-0.429-0.015-0.761l0.037-0.177v-0.182V14.8 c0-1.247-0.006-1.277-0.048-1.472c-0.076-0.354-0.035-0.653,0.007-0.803c0.477-0.346,0.828-0.861,0.996-1.476 c0.261-0.956,0.076-2.091-0.508-3.114l-0.591-1.032c-0.746-1.307-1.965-2.119-3.182-2.119c-0.378,0-0.75,0.081-1.085,0.235 c-0.198-0.025-0.554-0.15-0.855-0.389l-0.103-0.082l-0.114-0.065l-1.857-1.067L18.92,3.36l-0.105-0.044 c-0.376-0.154-0.658-0.41-0.768-0.556C17.918,1.172,16.349,0,14.296,0H13.14c-2.043,0-3.608,1.154-3.749,2.721 C9.277,2.862,8.999,3.104,8.633,3.25l-0.1,0.039L8.439,3.341L6.495,4.406L6.363,4.479L6.245,4.573 C5.936,4.82,5.596,4.944,5.416,4.977c-0.314-0.139-0.66-0.21-1.011-0.21c-1.198,0-2.411,0.819-3.165,2.139L0.65,7.938 c-0.412,0.72-0.642,1.521-0.644,2.258c-0.003,0.952,0.362,1.756,1.013,2.256c0.034,0.155,0.061,0.448-0.016,0.786 c-0.038,0.168-0.062,0.28-0.062,1.563c0,1.148,0,1.148,0.015,1.262l0.009,0.073l0.017,0.073c0.073,0.346,0.045,0.643,0.011,0.802 C0.348,17.512-0.01,18.314,0,19.268c0.008,0.729,0.238,1.523,0.648,2.242l0.589,1.031c0.761,1.331,1.967,2.159,3.15,2.159 c0.324,0,0.645-0.064,0.938-0.187c0.167,0.038,0.492,0.156,0.813,0.416l0.11,0.088l0.124,0.07l2.045,1.156l0.102,0.057l0.107,0.043 c0.364,0.147,0.646,0.381,0.766,0.521c0.164,1.52,1.719,2.634,3.745,2.634h1.155c2.037,0,3.598-1.134,3.747-2.675 c0.117-0.145,0.401-0.393,0.774-0.549l0.111-0.047l0.105-0.062l1.96-1.159l0.105-0.062l0.097-0.075 c0.309-0.246,0.651-0.371,0.832-0.402c0.313,0.138,0.662,0.212,1.016,0.212c1.199,0,2.412-0.82,3.166-2.139l0.59-1.032 C27.387,20.48,27.575,19.342,27.315,18.389z M25.274,20.635l-0.59,1.032c-0.438,0.765-1.104,1.251-1.639,1.251 c-0.133,0-0.258-0.029-0.369-0.094c-0.15-0.086-0.346-0.127-0.566-0.127c-0.596,0-1.383,0.295-2.01,0.796l-1.96,1.157 c-1.016,0.425-1.846,1.291-1.846,1.929s-0.898,1.159-1.998,1.159H13.14c-1.1,0-1.998-0.514-1.998-1.141s-0.834-1.477-1.854-1.888 l-2.046-1.157c-0.636-0.511-1.425-0.814-2.006-0.814c-0.202,0-0.379,0.037-0.516,0.115c-0.101,0.057-0.214,0.084-0.333,0.084 c-0.518,0-1.179-0.498-1.62-1.271l-0.591-1.032c-0.545-0.954-0.556-1.983-0.024-2.286c0.532-0.305,0.78-1.432,0.551-2.506 c0,0,0-0.003,0-1.042c0-1.088,0.021-1.18,0.021-1.18c0.238-1.072-0.01-2.203-0.552-2.513C1.631,10.8,1.634,9.765,2.18,8.812 L2.769,7.78c0.438-0.766,1.103-1.251,1.636-1.251c0.131,0,0.255,0.029,0.365,0.092C4.92,6.707,5.114,6.747,5.334,6.747 c0.596,0,1.38-0.296,2.007-0.795l1.944-1.065c1.021-0.407,1.856-1.277,1.856-1.933c0-0.656,0.898-1.192,1.998-1.192h1.156V1.761 c1.1,0,1.998,0.545,1.998,1.211c0,0.667,0.832,1.554,1.849,1.973L20,6.013c0.618,0.489,1.401,0.775,2.012,0.775 c0.24,0,0.454-0.045,0.62-0.139c0.122-0.069,0.259-0.102,0.403-0.102c0.551,0,1.221,0.476,1.653,1.231l0.59,1.032 c0.544,0.953,0.518,2.004-0.062,2.334c-0.577,0.331-0.859,1.48-0.627,2.554c0,0,0.01,0.042,0.01,1.103c0,1.012,0,1.012,0,1.012 c-0.218,1.049,0.068,2.174,0.636,2.498C25.802,18.635,25.819,19.68,25.274,20.635z"/><path d="M13.61,7.611c-3.913,0-7.084,3.173-7.084,7.085c0,3.914,3.171,7.085,7.084,7.085s7.085-3.172,7.085-7.085 C20.695,10.784,17.523,7.611,13.61,7.611z M13.61,20.02c-2.936,0-5.323-2.388-5.323-5.323c0-2.935,2.388-5.323,5.323-5.323 s5.324,2.388,5.324,5.323C18.934,17.632,16.546,20.02,13.61,20.02z"/><path d="M13.682,9.908c-2.602,0-4.718,2.116-4.718,4.718c0,2.601,2.116,4.716,4.718,4.716c2.601,0,4.717-2.115,4.717-4.716 C18.399,12.024,16.283,9.908,13.682,9.908z M13.682,17.581c-1.633,0-2.956-1.323-2.956-2.955s1.323-2.956,2.956-2.956 c1.632,0,2.956,1.324,2.956,2.956S15.314,17.581,13.682,17.581z"/></g></svg> \ No newline at end of file
diff --git a/src/librustdoc/html/static/js/README.md b/src/librustdoc/html/static/js/README.md
new file mode 100644
index 000000000..1fd859ad7
--- /dev/null
+++ b/src/librustdoc/html/static/js/README.md
@@ -0,0 +1,15 @@
+# Rustdoc JS
+
+These JavaScript files are incorporated into the rustdoc binary at build time,
+and are minified and written to the filesystem as part of the doc build process.
+
+We use the [Closure Compiler](https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler)
+dialect of JSDoc to comment our code and annotate params and return types.
+To run a check:
+
+ ./x.py doc library/std
+ npm i -g google-closure-compiler
+ google-closure-compiler -W VERBOSE \
+ build/<YOUR PLATFORM>/doc/{search-index*.js,crates*.js} \
+ src/librustdoc/html/static/js/{search.js,main.js,storage.js} \
+ --externs src/librustdoc/html/static/js/externs.js >/dev/null
diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js
new file mode 100644
index 000000000..ecbe15a59
--- /dev/null
+++ b/src/librustdoc/html/static/js/externs.js
@@ -0,0 +1,142 @@
+// This file contains type definitions that are processed by the Closure Compiler but are
+// not put into the JavaScript we include as part of the documentation. It is used for
+// type checking. See README.md in this directory for more info.
+
+/* eslint-disable */
+let searchState;
+function initSearch(searchIndex){}
+
+/**
+ * @typedef {{
+ * name: string,
+ * fullPath: Array<string>,
+ * pathWithoutLast: Array<string>,
+ * pathLast: string,
+ * generics: Array<QueryElement>,
+ * }}
+ */
+let QueryElement;
+
+/**
+ * @typedef {{
+ * pos: number,
+ * totalElems: number,
+ * typeFilter: (null|string),
+ * userQuery: string,
+ * }}
+ */
+let ParserState;
+
+/**
+ * @typedef {{
+ * original: string,
+ * userQuery: string,
+ * typeFilter: number,
+ * elems: Array<QueryElement>,
+ * args: Array<QueryElement>,
+ * returned: Array<QueryElement>,
+ * foundElems: number,
+ * }}
+ */
+let ParsedQuery;
+
+/**
+ * @typedef {{
+ * crate: string,
+ * desc: string,
+ * id: number,
+ * name: string,
+ * normalizedName: string,
+ * parent: (Object|null|undefined),
+ * path: string,
+ * ty: (Number|null|number),
+ * type: (Array<?>|null)
+ * }}
+ */
+let Row;
+
+/**
+ * @typedef {{
+ * in_args: Array<Object>,
+ * returned: Array<Object>,
+ * others: Array<Object>,
+ * query: ParsedQuery,
+ * }}
+ */
+let ResultsTable;
+
+/**
+ * @typedef {{
+ * desc: string,
+ * displayPath: string,
+ * fullPath: string,
+ * href: string,
+ * id: number,
+ * lev: number,
+ * name: string,
+ * normalizedName: string,
+ * parent: (Object|undefined),
+ * path: string,
+ * ty: number,
+ * }}
+ */
+let Results;
+
+/**
+ * A pair of [inputs, outputs], or 0 for null. This is stored in the search index.
+ * The JavaScript deserializes this into FunctionSearchType.
+ *
+ * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
+ * because `null` is four bytes while `0` is one byte.
+ *
+ * An input or output can be encoded as just a number if there is only one of them, AND
+ * it has no generics. The no generics rule exists to avoid ambiguity: imagine if you had
+ * a function with a single output, and that output had a single generic:
+ *
+ * fn something() -> Result<usize, usize>
+ *
+ * If output was allowed to be any RawFunctionType, it would look like this
+ *
+ * [[], [50, [3, 3]]]
+ *
+ * The problem is that the above output could be interpreted as either a type with ID 50 and two
+ * generics, or it could be interpreted as a pair of types, the first one with ID 50 and the second
+ * with ID 3 and a single generic parameter that is also ID 3. We avoid this ambiguity by choosing
+ * in favor of the pair of types interpretation. This is why the `(number|Array<RawFunctionType>)`
+ * is used instead of `(RawFunctionType|Array<RawFunctionType>)`.
+ *
+ * @typedef {(
+ * 0 |
+ * [(number|Array<RawFunctionType>)] |
+ * [(number|Array<RawFunctionType>), (number|Array<RawFunctionType>)]
+ * )}
+ */
+let RawFunctionSearchType;
+
+/**
+ * A single function input or output type. This is either a single path ID, or a pair of
+ * [path ID, generics].
+ *
+ * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
+ * because `null` is four bytes while `0` is one byte.
+ *
+ * @typedef {number | [number, Array<RawFunctionType>]}
+ */
+let RawFunctionType;
+
+/**
+ * @typedef {{
+ * inputs: Array<FunctionType>,
+ * outputs: Array<FunctionType>,
+ * }}
+ */
+let FunctionSearchType;
+
+/**
+ * @typedef {{
+ * name: (null|string),
+ * ty: (null|number),
+ * generics: Array<FunctionType>,
+ * }}
+ */
+let FunctionType;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
new file mode 100644
index 000000000..0702b2b0b
--- /dev/null
+++ b/src/librustdoc/html/static/js/main.js
@@ -0,0 +1,974 @@
+// Local js definitions:
+/* global addClass, getSettingValue, hasClass, searchState */
+/* global onEach, onEachLazy, removeClass */
+
+"use strict";
+
+// 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) {
+ const el = document.getElementById("rustdoc-vars");
+ if (el) {
+ return el.attributes["data-" + name].value;
+ } else {
+ return null;
+ }
+}
+
+// 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;
+}
+
+function hideMain() {
+ addClass(document.getElementById(MAIN_ID), "hidden");
+}
+
+function showMain() {
+ removeClass(document.getElementById(MAIN_ID), "hidden");
+}
+
+function elemIsInParent(elem, parent) {
+ while (elem && elem !== document.body) {
+ if (elem === parent) {
+ return true;
+ }
+ elem = elem.parentElement;
+ }
+ return false;
+}
+
+function blurHandler(event, parentElem, hideCallback) {
+ if (!elemIsInParent(document.activeElement, parentElem) &&
+ !elemIsInParent(event.relatedTarget, parentElem)
+ ) {
+ hideCallback();
+ }
+}
+
+(function() {
+ window.rootPath = getVar("root-path");
+ window.currentCrate = getVar("current-crate");
+}());
+
+function setMobileTopbar() {
+ // 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.
+ const mobileLocationTitle = document.querySelector(".mobile-topbar h2.location");
+ const locationTitle = document.querySelector(".sidebar h2.location");
+ if (mobileLocationTitle && locationTitle) {
+ mobileLocationTitle.innerHTML = locationTitle.innerHTML;
+ }
+}
+
+// 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) {
+ if ("key" in ev && typeof ev.key !== "undefined") {
+ return ev.key;
+ }
+
+ const c = ev.charCode || ev.keyCode;
+ if (c === 27) {
+ return "Escape";
+ }
+ return String.fromCharCode(c);
+}
+
+const MAIN_ID = "main-content";
+const SETTINGS_BUTTON_ID = "settings-menu";
+const ALTERNATIVE_DISPLAY_ID = "alternative-display";
+const NOT_DISPLAYED_ID = "not-displayed";
+const HELP_BUTTON_ID = "help-button";
+
+function getSettingsButton() {
+ return document.getElementById(SETTINGS_BUTTON_ID);
+}
+
+function getHelpButton() {
+ return document.getElementById(HELP_BUTTON_ID);
+}
+
+// Returns the current URL without any query parameter or hash.
+function getNakedUrl() {
+ return window.location.href.split("?")[0].split("#")[0];
+}
+
+/**
+ * This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode`
+ * doesn't have a parent node.
+ *
+ * @param {HTMLElement} newNode
+ * @param {HTMLElement} referenceNode
+ */
+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}
+ */
+function getAlternativeDisplayElem() {
+ return getOrCreateSection(ALTERNATIVE_DISPLAY_ID, "content hidden");
+}
+
+/**
+ * Returns the `<section>` element which contains the not-displayed elements.
+ *
+ * @return {HTMLElement}
+ */
+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
+ * 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
+ */
+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() {
+ function loadScript(url) {
+ const script = document.createElement("script");
+ script.src = url;
+ document.head.append(script);
+ }
+
+ getSettingsButton().onclick = event => {
+ addClass(getSettingsButton(), "rotate");
+ 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");
+ loadScript(resourcePath("settings", ".js"));
+ };
+
+ window.searchState = {
+ loadingText: "Loading search results...",
+ input: document.getElementsByClassName("search-input")[0],
+ outputElement: () => {
+ let el = document.getElementById("search");
+ if (!el) {
+ el = document.createElement("section");
+ el.id = "search";
+ getNotDisplayedElem().appendChild(el);
+ }
+ return el;
+ },
+ title: document.title,
+ 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,
+ // tab and back preserves the element that was focused.
+ focusedByTab: [null, null, null],
+ clearInputTimeout: () => {
+ if (searchState.timeout !== null) {
+ clearTimeout(searchState.timeout);
+ searchState.timeout = null;
+ }
+ },
+ isDisplayed: () => searchState.outputElement().parentElement.id === ALTERNATIVE_DISPLAY_ID,
+ // Sets the focus on the search bar at the top of the page
+ focus: () => {
+ searchState.input.focus();
+ },
+ // Removes the focus from the search bar.
+ defocus: () => {
+ searchState.input.blur();
+ },
+ showResults: search => {
+ if (search === null || typeof search === "undefined") {
+ search = searchState.outputElement();
+ }
+ switchDisplayedElement(search);
+ searchState.mouseMovedAfterSearch = false;
+ document.title = searchState.title;
+ },
+ hideResults: () => {
+ switchDisplayedElement(null);
+ document.title = searchState.titleBeforeSearch;
+ // We also remove the query parameter from the URL.
+ if (browserSupportsHistoryApi()) {
+ history.replaceState(null, window.currentCrate + " - Rust",
+ getNakedUrl() + window.location.hash);
+ }
+ },
+ getQueryStringParams: () => {
+ const params = {};
+ window.location.search.substring(1).split("&").
+ map(s => {
+ const pair = s.split("=");
+ params[decodeURIComponent(pair[0])] =
+ typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]);
+ });
+ return params;
+ },
+ setup: () => {
+ const search_input = searchState.input;
+ if (!searchState.input) {
+ return;
+ }
+ let searchLoaded = false;
+ function loadSearch() {
+ if (!searchLoaded) {
+ searchLoaded = true;
+ loadScript(resourcePath("search", ".js"));
+ loadScript(resourcePath("search-index", ".js"));
+ }
+ }
+
+ search_input.addEventListener("focus", () => {
+ search_input.origPlaceholder = search_input.placeholder;
+ search_input.placeholder = "Type your search here.";
+ loadSearch();
+ });
+
+ if (search_input.value !== "") {
+ loadSearch();
+ }
+
+ const params = searchState.getQueryStringParams();
+ if (params.search !== undefined) {
+ const search = searchState.outputElement();
+ search.innerHTML = "<h3 class=\"search-loading\">" +
+ searchState.loadingText + "</h3>";
+ searchState.showResults(search);
+ loadSearch();
+ }
+ },
+ };
+
+ function getPageId() {
+ if (window.location.hash) {
+ const tmp = window.location.hash.replace(/^#/, "");
+ if (tmp.length > 0) {
+ return tmp;
+ }
+ }
+ return null;
+ }
+
+ const toggleAllDocsId = "toggle-all-docs";
+ let savedHash = "";
+
+ function handleHashes(ev) {
+ if (ev !== null && searchState.isDisplayed() && ev.newURL) {
+ // This block occurs when clicking on an element in the navbar while
+ // in a search.
+ switchDisplayedElement(null);
+ const hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
+ if (browserSupportsHistoryApi()) {
+ // `window.location.search`` contains all the query parameters, not just `search`.
+ history.replaceState(null, "",
+ getNakedUrl() + window.location.search + "#" + hash);
+ }
+ const elem = document.getElementById(hash);
+ 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;
+ }
+ expandSection(savedHash.slice(1)); // we remove the '#'
+ }
+ }
+
+ function onHashChange(ev) {
+ // If we're in mobile mode, we should hide the sidebar in any case.
+ 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) {
+ openParentDetails(document.getElementById(id));
+ }
+
+ function handleEscape(ev) {
+ searchState.clearInputTimeout();
+ switchDisplayedElement(null);
+ if (browserSupportsHistoryApi()) {
+ history.replaceState(null, window.currentCrate + " - Rust",
+ getNakedUrl() + window.location.hash);
+ }
+ ev.preventDefault();
+ searchState.defocus();
+ window.hidePopoverMenus();
+ }
+
+ function handleShortcut(ev) {
+ // Don't interfere with browser shortcuts
+ const disableShortcuts = getSettingValue("disable-shortcuts") === "true";
+ if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) {
+ return;
+ }
+
+ if (document.activeElement.tagName === "INPUT" &&
+ document.activeElement.type !== "checkbox") {
+ switch (getVirtualKey(ev)) {
+ case "Escape":
+ handleEscape(ev);
+ break;
+ }
+ } else {
+ switch (getVirtualKey(ev)) {
+ case "Escape":
+ handleEscape(ev);
+ break;
+
+ case "s":
+ case "S":
+ ev.preventDefault();
+ searchState.focus();
+ break;
+
+ case "+":
+ case "-":
+ ev.preventDefault();
+ toggleAllDocs();
+ break;
+
+ case "?":
+ showHelp();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ document.addEventListener("keypress", handleShortcut);
+ document.addEventListener("keydown", handleShortcut);
+
+ function addSidebarItems() {
+ if (!window.SIDEBAR_ITEMS) {
+ return;
+ }
+ const sidebar = document.getElementsByClassName("sidebar-elems")[0];
+
+ /**
+ * 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) {
+ const filtered = window.SIDEBAR_ITEMS[shortty];
+ if (!filtered) {
+ return;
+ }
+
+ const div = document.createElement("div");
+ div.className = "block " + shortty;
+ const h3 = document.createElement("h3");
+ h3.innerHTML = `<a href="index.html#${id}">${longty}</a>`;
+ div.appendChild(h3);
+ const ul = document.createElement("ul");
+
+ for (const item of filtered) {
+ const name = item[0];
+ const desc = item[1]; // can be null
+
+ let klass = shortty;
+ let path;
+ if (shortty === "mod") {
+ path = name + "/index.html";
+ } else {
+ path = shortty + "." + name + ".html";
+ }
+ const current_page = document.location.href.split("/").pop();
+ if (path === current_page) {
+ klass += " current";
+ }
+ const link = document.createElement("a");
+ link.href = path;
+ link.title = desc;
+ link.className = klass;
+ link.textContent = name;
+ const li = document.createElement("li");
+ li.appendChild(link);
+ ul.appendChild(li);
+ }
+ div.appendChild(ul);
+ sidebar.appendChild(div);
+ }
+
+ if (sidebar) {
+ 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");
+ }
+ }
+
+ window.register_implementors = imp => {
+ const implementors = document.getElementById("implementors-list");
+ const synthetic_implementors = document.getElementById("synthetic-implementors-list");
+ const inlined_types = new Set();
+
+ 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 => {
+ const aliases = el.getAttribute("data-aliases");
+ if (!aliases) {
+ return;
+ }
+ aliases.split(",").forEach(alias => {
+ inlined_types.add(alias);
+ });
+ });
+ }
+
+ 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");
+ for (const lib of libs) {
+ if (lib === window.currentCrate || ignoreExternCrates.indexOf(lib) !== -1) {
+ continue;
+ }
+ const structs = imp[lib];
+
+ struct_loop:
+ for (const struct of structs) {
+ const list = struct.synthetic ? synthetic_implementors : implementors;
+
+ if (struct.synthetic) {
+ for (const struct_type of struct.types) {
+ if (inlined_types.has(struct_type)) {
+ continue struct_loop;
+ }
+ inlined_types.add(struct_type);
+ }
+ }
+
+ const code = document.createElement("h3");
+ code.innerHTML = struct.text;
+ addClass(code, "code-header");
+ addClass(code, "in-band");
+
+ onEachLazy(code.getElementsByTagName("a"), elem => {
+ const href = elem.getAttribute("href");
+
+ if (href && href.indexOf("http") !== 0) {
+ elem.setAttribute("href", window.rootPath + href);
+ }
+ });
+
+ const currentId = baseIdName + currentNbImpls;
+ const anchor = document.createElement("a");
+ anchor.href = "#" + currentId;
+ addClass(anchor, "anchor");
+
+ const display = document.createElement("div");
+ display.id = currentId;
+ addClass(display, "impl");
+ display.appendChild(anchor);
+ display.appendChild(code);
+ list.appendChild(display);
+ currentNbImpls += 1;
+ }
+ }
+ };
+ if (window.pending_implementors) {
+ window.register_implementors(window.pending_implementors);
+ }
+
+ function addSidebarCrates() {
+ if (!window.ALL_CRATES) {
+ return;
+ }
+ const sidebarElems = document.getElementsByClassName("sidebar-elems")[0];
+ if (!sidebarElems) {
+ return;
+ }
+ // Draw a convenient sidebar of known crates if we have a listing
+ const div = document.createElement("div");
+ div.className = "block crate";
+ div.innerHTML = "<h3>Crates</h3>";
+ const ul = document.createElement("ul");
+ div.appendChild(ul);
+
+ for (const crate of window.ALL_CRATES) {
+ let klass = "crate";
+ if (window.rootPath !== "./" && crate === window.currentCrate) {
+ klass += " current";
+ }
+ const link = document.createElement("a");
+ link.href = window.rootPath + crate + "/index.html";
+ link.className = klass;
+ link.textContent = crate;
+
+ const li = document.createElement("li");
+ li.appendChild(link);
+ ul.appendChild(li);
+ }
+ sidebarElems.appendChild(div);
+ }
+
+
+ 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
+ }
+
+ function toggleAllDocs() {
+ const innerToggle = document.getElementById(toggleAllDocsId);
+ if (!innerToggle) {
+ return;
+ }
+ let sectionIsCollapsed = false;
+ if (hasClass(innerToggle, "will-expand")) {
+ removeClass(innerToggle, "will-expand");
+ onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+ if (!hasClass(e, "type-contents-toggle")) {
+ e.open = true;
+ }
+ });
+ innerToggle.title = "collapse all docs";
+ } else {
+ addClass(innerToggle, "will-expand");
+ onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+ if (e.parentNode.id !== "implementations-list" ||
+ (!hasClass(e, "implementors-toggle") &&
+ !hasClass(e, "type-contents-toggle"))
+ ) {
+ e.open = false;
+ }
+ });
+ sectionIsCollapsed = true;
+ innerToggle.title = "expand all docs";
+ }
+ innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed);
+ }
+
+ (function() {
+ const toggles = document.getElementById(toggleAllDocsId);
+ if (toggles) {
+ toggles.onclick = toggleAllDocs;
+ }
+
+ 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) {
+ 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;
+ }
+
+ });
+
+ const pageId = getPageId();
+ if (pageId !== null) {
+ expandSection(pageId);
+ }
+ }());
+
+ (function() {
+ // To avoid checking on "rustdoc-line-numbers" value on every loop...
+ let lineNumbersFunc = () => {};
+ if (getSettingValue("line-numbers") === "true") {
+ lineNumbersFunc = x => {
+ const count = x.textContent.split("\n").length;
+ const elems = [];
+ for (let i = 0; i < count; ++i) {
+ elems.push(i + 1);
+ }
+ 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")) {
+ e.addEventListener("mouseover", function() {
+ this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
+ });
+ e.addEventListener("mouseout", function() {
+ this.parentElement.previousElementSibling.childNodes[0].style.color = "";
+ });
+ } else if (hasClass(e, "ignore")) {
+ e.addEventListener("mouseover", function() {
+ this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
+ });
+ e.addEventListener("mouseout", function() {
+ this.parentElement.previousElementSibling.childNodes[0].style.color = "";
+ });
+ }
+ lineNumbersFunc(e);
+ });
+ }());
+
+ function hideSidebar() {
+ const sidebar = document.getElementsByClassName("sidebar")[0];
+ removeClass(sidebar, "shown");
+ }
+
+ function handleClick(id, f) {
+ const elem = document.getElementById(id);
+ if (elem) {
+ elem.addEventListener("click", f);
+ }
+ }
+ 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() {
+ this.getElementsByClassName("notable-traits-tooltiptext")[0]
+ .classList.toggle("force-tooltip");
+ };
+ });
+
+ const sidebar_menu_toggle = document.getElementsByClassName("sidebar-menu-toggle")[0];
+ if (sidebar_menu_toggle) {
+ sidebar_menu_toggle.addEventListener("click", () => {
+ const sidebar = document.getElementsByClassName("sidebar")[0];
+ if (!hasClass(sidebar, "shown")) {
+ addClass(sidebar, "shown");
+ } else {
+ removeClass(sidebar, "shown");
+ }
+ });
+ }
+
+ function helpBlurHandler(event) {
+ blurHandler(event, getHelpButton(), window.hidePopoverMenus);
+ }
+
+ function buildHelpMenu() {
+ 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>.";
+
+ const shortcuts = [
+ ["?", "Show this help dialog"],
+ ["S", "Focus the search field"],
+ ["↑", "Move up in search results"],
+ ["↓", "Move down in search results"],
+ ["← / →", "Switch result tab (when results focused)"],
+ ["&#9166;", "Go to active search result"],
+ ["+", "Expand all sections"],
+ ["-", "Collapse all sections"],
+ ].map(x => "<dt>" +
+ x[0].split(" ")
+ .map((y, index) => ((index & 1) === 0 ? "<kbd>" + y + "</kbd>" : " " + y + " "))
+ .join("") + "</dt><dd>" + x[1] + "</dd>").join("");
+ const div_shortcuts = document.createElement("div");
+ addClass(div_shortcuts, "shortcuts");
+ div_shortcuts.innerHTML = "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts + "</dl></div>";
+
+ const infos = [
+ "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
+ 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("");
+ const div_infos = document.createElement("div");
+ addClass(div_infos, "infos");
+ div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;
+
+ const rustdoc_version = document.createElement("span");
+ rustdoc_version.className = "bottom";
+ const rustdoc_version_code = document.createElement("code");
+ rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version");
+ rustdoc_version.appendChild(rustdoc_version_code);
+
+ const container = document.createElement("div");
+ container.className = "popover";
+ container.style.display = "none";
+
+ const side_by_side = document.createElement("div");
+ side_by_side.className = "side-by-side";
+ side_by_side.appendChild(div_shortcuts);
+ side_by_side.appendChild(div_infos);
+
+ container.appendChild(book_info);
+ container.appendChild(side_by_side);
+ container.appendChild(rustdoc_version);
+
+ const help_button = getHelpButton();
+ help_button.appendChild(container);
+
+ container.onblur = helpBlurHandler;
+ container.onclick = event => {
+ event.preventDefault();
+ };
+ help_button.onblur = helpBlurHandler;
+ help_button.children[0].onblur = helpBlurHandler;
+
+ return container;
+ }
+
+ /**
+ * Hide all the popover menus.
+ */
+ window.hidePopoverMenus = function() {
+ onEachLazy(document.querySelectorAll(".search-container .popover"), elem => {
+ elem.style.display = "none";
+ });
+ };
+
+ /**
+ * Returns the help menu element (not the button).
+ *
+ * @param {boolean} buildNeeded - If this argument is `false`, the help menu element won't be
+ * built if it doesn't exist.
+ *
+ * @return {HTMLElement}
+ */
+ function getHelpMenu(buildNeeded) {
+ let menu = getHelpButton().querySelector(".popover");
+ if (!menu && buildNeeded) {
+ menu = buildHelpMenu();
+ }
+ return menu;
+ }
+
+ /**
+ * Show the help popup menu.
+ */
+ function showHelp() {
+ const menu = getHelpMenu(true);
+ if (menu.style.display === "none") {
+ window.hidePopoverMenus();
+ menu.style.display = "";
+ }
+ }
+
+ document.querySelector(`#${HELP_BUTTON_ID} > button`).addEventListener("click", event => {
+ const target = event.target;
+ if (target.tagName !== "BUTTON" || target.parentElement.id !== HELP_BUTTON_ID) {
+ return;
+ }
+ const menu = getHelpMenu(true);
+ const shouldShowHelp = menu.style.display === "none";
+ if (shouldShowHelp) {
+ showHelp();
+ } else {
+ window.hidePopoverMenus();
+ }
+ });
+
+ setMobileTopbar();
+ addSidebarItems();
+ addSidebarCrates();
+ onHashChange(null);
+ window.addEventListener("hashchange", onHashChange);
+ searchState.setup();
+}());
+
+(function() {
+ let reset_button_timeout = null;
+
+ window.copy_path = but => {
+ const parent = but.parentElement;
+ const path = [];
+
+ onEach(parent.childNodes, child => {
+ if (child.tagName === "A") {
+ path.push(child.textContent);
+ }
+ });
+
+ const el = document.createElement("textarea");
+ el.value = path.join("::");
+ el.setAttribute("readonly", "");
+ // To not make it appear on the screen.
+ el.style.position = "absolute";
+ el.style.left = "-9999px";
+
+ document.body.appendChild(el);
+ el.select();
+ document.execCommand("copy");
+ document.body.removeChild(el);
+
+ // There is always one children, but multiple childNodes.
+ but.children[0].style.display = "none";
+
+ let tmp;
+ if (but.childNodes.length < 2) {
+ tmp = document.createTextNode("✓");
+ but.appendChild(tmp);
+ } else {
+ onEachLazy(but.childNodes, e => {
+ if (e.nodeType === Node.TEXT_NODE) {
+ tmp = e;
+ return true;
+ }
+ });
+ tmp.textContent = "✓";
+ }
+
+ if (reset_button_timeout !== null) {
+ window.clearTimeout(reset_button_timeout);
+ }
+
+ function reset_button() {
+ tmp.textContent = "";
+ reset_button_timeout = null;
+ but.children[0].style.display = "";
+ }
+
+ reset_button_timeout = window.setTimeout(reset_button, 1000);
+ };
+}());
diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js
new file mode 100644
index 000000000..fd7a14497
--- /dev/null
+++ b/src/librustdoc/html/static/js/scrape-examples.js
@@ -0,0 +1,106 @@
+/* global addClass, hasClass, removeClass, onEachLazy */
+
+"use strict";
+
+(function() {
+ // Number of lines shown when code viewer is not expanded
+ const MAX_LINES = 10;
+
+ // Scroll code block to the given code location
+ function scrollToLoc(elt, loc) {
+ const lines = elt.querySelector(".line-numbers");
+ let scrollOffset;
+
+ // If the block is greater than the size of the viewer,
+ // then scroll to the top of the block. Otherwise scroll
+ // to the middle of the block.
+ if (loc[1] - loc[0] > MAX_LINES) {
+ const line = Math.max(0, loc[0] - 1);
+ scrollOffset = lines.children[line].offsetTop;
+ } else {
+ const wrapper = elt.querySelector(".code-wrapper");
+ const halfHeight = wrapper.offsetHeight / 2;
+ const offsetMid = (lines.children[loc[0]].offsetTop
+ + lines.children[loc[1]].offsetTop) / 2;
+ scrollOffset = offsetMid - halfHeight;
+ }
+
+ lines.scrollTo(0, scrollOffset);
+ elt.querySelector(".rust").scrollTo(0, scrollOffset);
+ }
+
+ function updateScrapedExample(example) {
+ const locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
+ let locIndex = 0;
+ const highlights = Array.prototype.slice.call(example.querySelectorAll(".highlight"));
+ const link = example.querySelector(".scraped-example-title a");
+
+ if (locs.length > 1) {
+ // Toggle through list of examples in a given file
+ const onChangeLoc = changeIndex => {
+ removeClass(highlights[locIndex], "focus");
+ changeIndex();
+ scrollToLoc(example, locs[locIndex][0]);
+ addClass(highlights[locIndex], "focus");
+
+ const url = locs[locIndex][1];
+ const title = locs[locIndex][2];
+
+ link.href = url;
+ link.innerHTML = title;
+ };
+
+ example.querySelector(".prev")
+ .addEventListener("click", () => {
+ onChangeLoc(() => {
+ locIndex = (locIndex - 1 + locs.length) % locs.length;
+ });
+ });
+
+ example.querySelector("next")
+ .addEventListener("click", () => {
+ onChangeLoc(() => {
+ locIndex = (locIndex + 1) % locs.length;
+ });
+ });
+ }
+
+ const expandButton = example.querySelector(".expand");
+ if (expandButton) {
+ expandButton.addEventListener("click", () => {
+ if (hasClass(example, "expanded")) {
+ removeClass(example, "expanded");
+ scrollToLoc(example, locs[0][0]);
+ } else {
+ addClass(example, "expanded");
+ }
+ });
+ }
+
+ // Start with the first example in view
+ scrollToLoc(example, locs[0][0]);
+ }
+
+ const firstExamples = document.querySelectorAll(".scraped-example-list > .scraped-example");
+ onEachLazy(firstExamples, updateScrapedExample);
+ onEachLazy(document.querySelectorAll(".more-examples-toggle"), toggle => {
+ // Allow users to click the left border of the <details> section to close it,
+ // since the section can be large and finding the [+] button is annoying.
+ onEachLazy(toggle.querySelectorAll(".toggle-line, .hide-more"), button => {
+ button.addEventListener("click", () => {
+ toggle.open = false;
+ });
+ });
+
+ const moreExamples = toggle.querySelectorAll(".scraped-example");
+ toggle.querySelector("summary").addEventListener("click", () => {
+ // Wrapping in setTimeout ensures the update happens after the elements are actually
+ // visible. This is necessary since updateScrapedExample calls scrollToLoc which
+ // depends on offsetHeight, a property that requires an element to be visible to
+ // compute correctly.
+ setTimeout(() => {
+ onEachLazy(moreExamples, updateScrapedExample);
+ });
+ }, {once: true});
+ });
+})();
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
new file mode 100644
index 000000000..75c7bd45a
--- /dev/null
+++ b/src/librustdoc/html/static/js/search.js
@@ -0,0 +1,2297 @@
+/* global addClass, getNakedUrl, getSettingValue */
+/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi, exports */
+
+"use strict";
+
+(function() {
+// This mapping table should match the discriminants of
+// `rustdoc::formats::item_type::ItemType` type in Rust.
+const itemTypes = [
+ "mod",
+ "externcrate",
+ "import",
+ "struct",
+ "enum",
+ "fn",
+ "type",
+ "static",
+ "trait",
+ "impl",
+ "tymethod",
+ "method",
+ "structfield",
+ "variant",
+ "macro",
+ "primitive",
+ "associatedtype",
+ "constant",
+ "associatedconstant",
+ "union",
+ "foreigntype",
+ "keyword",
+ "existential",
+ "attr",
+ "derive",
+ "traitalias",
+];
+
+// used for special search precedence
+const TY_PRIMITIVE = itemTypes.indexOf("primitive");
+const TY_KEYWORD = itemTypes.indexOf("keyword");
+const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../";
+
+function hasOwnPropertyRustdoc(obj, property) {
+ return Object.prototype.hasOwnProperty.call(obj, property);
+}
+
+// In the search display, allows to switch between tabs.
+function printTab(nb) {
+ let iter = 0;
+ let foundCurrentTab = false;
+ let foundCurrentResultSet = false;
+ onEachLazy(document.getElementById("titles").childNodes, elem => {
+ if (nb === iter) {
+ addClass(elem, "selected");
+ foundCurrentTab = true;
+ } else {
+ removeClass(elem, "selected");
+ }
+ iter += 1;
+ });
+ iter = 0;
+ onEachLazy(document.getElementById("results").childNodes, elem => {
+ if (nb === iter) {
+ addClass(elem, "active");
+ foundCurrentResultSet = true;
+ } else {
+ removeClass(elem, "active");
+ }
+ iter += 1;
+ });
+ if (foundCurrentTab && foundCurrentResultSet) {
+ searchState.currentTab = nb;
+ } else if (nb !== 0) {
+ printTab(0);
+ }
+}
+
+/**
+ * A function to compute the Levenshtein distance between two strings
+ * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
+ * Full License can be found at http://creativecommons.org/licenses/by-sa/3.0/legalcode
+ * This code is an unmodified version of the code written by Marco de Wit
+ * and was found at https://stackoverflow.com/a/18514751/745719
+ */
+const levenshtein_row2 = [];
+function levenshtein(s1, s2) {
+ if (s1 === s2) {
+ return 0;
+ }
+ const s1_len = s1.length, s2_len = s2.length;
+ if (s1_len && s2_len) {
+ let i1 = 0, i2 = 0, a, b, c, c2;
+ const row = levenshtein_row2;
+ while (i1 < s1_len) {
+ row[i1] = ++i1;
+ }
+ while (i2 < s2_len) {
+ c2 = s2.charCodeAt(i2);
+ a = i2;
+ ++i2;
+ b = i2;
+ for (i1 = 0; i1 < s1_len; ++i1) {
+ c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0);
+ a = row[i1];
+ b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
+ row[i1] = b;
+ }
+ }
+ return b;
+ }
+ return s1_len + s2_len;
+}
+
+function initSearch(rawSearchIndex) {
+ const MAX_LEV_DISTANCE = 3;
+ const MAX_RESULTS = 200;
+ const NO_TYPE_FILTER = -1;
+ /**
+ * @type {Array<Row>}
+ */
+ let searchIndex;
+ let currentResults;
+ const ALIASES = Object.create(null);
+
+ function isWhitespace(c) {
+ return " \t\n\r".indexOf(c) !== -1;
+ }
+
+ function isSpecialStartCharacter(c) {
+ return "<\"".indexOf(c) !== -1;
+ }
+
+ function isEndCharacter(c) {
+ return ",>-".indexOf(c) !== -1;
+ }
+
+ function isStopCharacter(c) {
+ return isWhitespace(c) || isEndCharacter(c);
+ }
+
+ function isErrorCharacter(c) {
+ return "()".indexOf(c) !== -1;
+ }
+
+ function itemTypeFromName(typename) {
+ for (let i = 0, len = itemTypes.length; i < len; ++i) {
+ if (itemTypes[i] === typename) {
+ return i;
+ }
+ }
+
+ throw new Error("Unknown type filter `" + typename + "`");
+ }
+
+ /**
+ * If we encounter a `"`, then we try to extract the string from it until we find another `"`.
+ *
+ * This function will throw an error in the following cases:
+ * * There is already another string element.
+ * * We are parsing a generic argument.
+ * * There is more than one element.
+ * * There is no closing `"`.
+ *
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {boolean} isInGenerics
+ */
+ function getStringElem(query, parserState, isInGenerics) {
+ if (isInGenerics) {
+ throw new Error("`\"` cannot be used in generics");
+ } else if (query.literalSearch) {
+ throw new Error("Cannot have more than one literal search element");
+ } else if (parserState.totalElems - parserState.genericsElems > 0) {
+ throw new Error("Cannot use literal search when there is more than one element");
+ }
+ parserState.pos += 1;
+ const start = parserState.pos;
+ const end = getIdentEndPosition(parserState);
+ if (parserState.pos >= parserState.length) {
+ throw new Error("Unclosed `\"`");
+ } else if (parserState.userQuery[end] !== "\"") {
+ throw new Error(`Unexpected \`${parserState.userQuery[end]}\` in a string element`);
+ } else if (start === end) {
+ throw new Error("Cannot have empty string element");
+ }
+ // To skip the quote at the end.
+ parserState.pos += 1;
+ query.literalSearch = true;
+ }
+
+ /**
+ * Returns `true` if the current parser position is starting with "::".
+ *
+ * @param {ParserState} parserState
+ *
+ * @return {boolean}
+ */
+ function isPathStart(parserState) {
+ return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) === "::";
+ }
+
+ /**
+ * Returns `true` if the current parser position is starting with "->".
+ *
+ * @param {ParserState} parserState
+ *
+ * @return {boolean}
+ */
+ function isReturnArrow(parserState) {
+ return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) === "->";
+ }
+
+ /**
+ * Returns `true` if the given `c` character is valid for an ident.
+ *
+ * @param {string} c
+ *
+ * @return {boolean}
+ */
+ function isIdentCharacter(c) {
+ return (
+ c === "_" ||
+ (c >= "0" && c <= "9") ||
+ (c >= "a" && c <= "z") ||
+ (c >= "A" && c <= "Z"));
+ }
+
+ /**
+ * Returns `true` if the given `c` character is a separator.
+ *
+ * @param {string} c
+ *
+ * @return {boolean}
+ */
+ function isSeparatorCharacter(c) {
+ return c === "," || isWhitespaceCharacter(c);
+ }
+
+ /**
+ * Returns `true` if the given `c` character is a whitespace.
+ *
+ * @param {string} c
+ *
+ * @return {boolean}
+ */
+ function isWhitespaceCharacter(c) {
+ return c === " " || c === "\t";
+ }
+
+ /**
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {string} name - Name of the query element.
+ * @param {Array<QueryElement>} generics - List of generics of this query element.
+ *
+ * @return {QueryElement} - The newly created `QueryElement`.
+ */
+ function createQueryElement(query, parserState, name, generics, isInGenerics) {
+ if (name === "*" || (name.length === 0 && generics.length === 0)) {
+ return;
+ }
+ if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
+ throw new Error("You cannot have more than one element if you use quotes");
+ }
+ const pathSegments = name.split("::");
+ if (pathSegments.length > 1) {
+ for (let i = 0, len = pathSegments.length; i < len; ++i) {
+ const pathSegment = pathSegments[i];
+
+ if (pathSegment.length === 0) {
+ if (i === 0) {
+ throw new Error("Paths cannot start with `::`");
+ } else if (i + 1 === len) {
+ throw new Error("Paths cannot end with `::`");
+ }
+ throw new Error("Unexpected `::::`");
+ }
+ }
+ }
+ // In case we only have something like `<p>`, there is no name.
+ if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === "")) {
+ throw new Error("Found generics without a path");
+ }
+ parserState.totalElems += 1;
+ if (isInGenerics) {
+ parserState.genericsElems += 1;
+ }
+ return {
+ name: name,
+ fullPath: pathSegments,
+ pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1),
+ pathLast: pathSegments[pathSegments.length - 1],
+ generics: generics,
+ };
+ }
+
+ /**
+ * This function goes through all characters until it reaches an invalid ident character or the
+ * end of the query. It returns the position of the last character of the ident.
+ *
+ * @param {ParserState} parserState
+ *
+ * @return {integer}
+ */
+ function getIdentEndPosition(parserState) {
+ let end = parserState.pos;
+ let foundExclamation = false;
+ while (parserState.pos < parserState.length) {
+ const c = parserState.userQuery[parserState.pos];
+ if (!isIdentCharacter(c)) {
+ if (c === "!") {
+ if (foundExclamation) {
+ throw new Error("Cannot have more than one `!` in an ident");
+ } else if (parserState.pos + 1 < parserState.length &&
+ isIdentCharacter(parserState.userQuery[parserState.pos + 1])
+ ) {
+ throw new Error("`!` can only be at the end of an ident");
+ }
+ foundExclamation = true;
+ } else if (isErrorCharacter(c)) {
+ throw new Error(`Unexpected \`${c}\``);
+ } else if (
+ isStopCharacter(c) ||
+ isSpecialStartCharacter(c) ||
+ isSeparatorCharacter(c)
+ ) {
+ break;
+ } else if (c === ":") { // If we allow paths ("str::string" for example).
+ if (!isPathStart(parserState)) {
+ break;
+ }
+ // Skip current ":".
+ parserState.pos += 1;
+ foundExclamation = false;
+ } else {
+ throw new Error(`Unexpected \`${c}\``);
+ }
+ }
+ parserState.pos += 1;
+ end = parserState.pos;
+ }
+ return end;
+ }
+
+ /**
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+ * @param {boolean} isInGenerics
+ */
+ function getNextElem(query, parserState, elems, isInGenerics) {
+ const generics = [];
+
+ let start = parserState.pos;
+ let end;
+ // We handle the strings on their own mostly to make code easier to follow.
+ if (parserState.userQuery[parserState.pos] === "\"") {
+ start += 1;
+ getStringElem(query, parserState, isInGenerics);
+ end = parserState.pos - 1;
+ } else {
+ end = getIdentEndPosition(parserState);
+ }
+ if (parserState.pos < parserState.length &&
+ parserState.userQuery[parserState.pos] === "<"
+ ) {
+ if (isInGenerics) {
+ throw new Error("Unexpected `<` after `<`");
+ } else if (start >= end) {
+ throw new Error("Found generics without a path");
+ }
+ parserState.pos += 1;
+ getItemsBefore(query, parserState, generics, ">");
+ }
+ if (start >= end && generics.length === 0) {
+ return;
+ }
+ elems.push(
+ createQueryElement(
+ query,
+ parserState,
+ parserState.userQuery.slice(start, end),
+ generics,
+ isInGenerics
+ )
+ );
+ }
+
+ /**
+ * This function parses the next query element until it finds `endChar`, calling `getNextElem`
+ * to collect each element.
+ *
+ * If there is no `endChar`, this function will implicitly stop at the end without raising an
+ * error.
+ *
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+ * @param {string} endChar - This function will stop when it'll encounter this
+ * character.
+ */
+ function getItemsBefore(query, parserState, elems, endChar) {
+ let foundStopChar = true;
+
+ while (parserState.pos < parserState.length) {
+ const c = parserState.userQuery[parserState.pos];
+ if (c === endChar) {
+ break;
+ } else if (isSeparatorCharacter(c)) {
+ parserState.pos += 1;
+ foundStopChar = true;
+ continue;
+ } else if (c === ":" && isPathStart(parserState)) {
+ throw new Error("Unexpected `::`: paths cannot start with `::`");
+ } else if (c === ":" || isEndCharacter(c)) {
+ let extra = "";
+ if (endChar === ">") {
+ extra = "`<`";
+ } else if (endChar === "") {
+ extra = "`->`";
+ }
+ throw new Error("Unexpected `" + c + "` after " + extra);
+ }
+ if (!foundStopChar) {
+ if (endChar !== "") {
+ throw new Error(`Expected \`,\`, \` \` or \`${endChar}\`, found \`${c}\``);
+ }
+ throw new Error(`Expected \`,\` or \` \`, found \`${c}\``);
+ }
+ const posBefore = parserState.pos;
+ getNextElem(query, parserState, elems, endChar === ">");
+ // This case can be encountered if `getNextElem` encounted a "stop character" right from
+ // the start. For example if you have `,,` or `<>`. In this case, we simply move up the
+ // current position to continue the parsing.
+ if (posBefore === parserState.pos) {
+ parserState.pos += 1;
+ }
+ foundStopChar = false;
+ }
+ // We are either at the end of the string or on the `endChar`` character, let's move forward
+ // in any case.
+ parserState.pos += 1;
+ }
+
+ /**
+ * Checks that the type filter doesn't have unwanted characters like `<>` (which are ignored
+ * if empty).
+ *
+ * @param {ParserState} parserState
+ */
+ function checkExtraTypeFilterCharacters(parserState) {
+ const query = parserState.userQuery;
+
+ for (let pos = 0; pos < parserState.pos; ++pos) {
+ if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) {
+ throw new Error(`Unexpected \`${query[pos]}\` in type filter`);
+ }
+ }
+ }
+
+ /**
+ * Parses the provided `query` input to fill `parserState`. If it encounters an error while
+ * parsing `query`, it'll throw an error.
+ *
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ */
+ function parseInput(query, parserState) {
+ let c, before;
+ let foundStopChar = true;
+
+ while (parserState.pos < parserState.length) {
+ c = parserState.userQuery[parserState.pos];
+ if (isStopCharacter(c)) {
+ foundStopChar = true;
+ if (isSeparatorCharacter(c)) {
+ parserState.pos += 1;
+ continue;
+ } else if (c === "-" || c === ">") {
+ if (isReturnArrow(parserState)) {
+ break;
+ }
+ throw new Error(`Unexpected \`${c}\` (did you mean \`->\`?)`);
+ }
+ throw new Error(`Unexpected \`${c}\``);
+ } else if (c === ":" && !isPathStart(parserState)) {
+ if (parserState.typeFilter !== null) {
+ throw new Error("Unexpected `:`");
+ }
+ if (query.elems.length === 0) {
+ throw new Error("Expected type filter before `:`");
+ } else if (query.elems.length !== 1 || parserState.totalElems !== 1) {
+ throw new Error("Unexpected `:`");
+ } else if (query.literalSearch) {
+ throw new Error("You cannot use quotes on type filter");
+ }
+ checkExtraTypeFilterCharacters(parserState);
+ // The type filter doesn't count as an element since it's a modifier.
+ parserState.typeFilter = query.elems.pop().name;
+ parserState.pos += 1;
+ parserState.totalElems = 0;
+ query.literalSearch = false;
+ foundStopChar = true;
+ continue;
+ }
+ if (!foundStopChar) {
+ if (parserState.typeFilter !== null) {
+ throw new Error(`Expected \`,\`, \` \` or \`->\`, found \`${c}\``);
+ }
+ throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``);
+ }
+ before = query.elems.length;
+ getNextElem(query, parserState, query.elems, false);
+ if (query.elems.length === before) {
+ // Nothing was added, weird... Let's increase the position to not remain stuck.
+ parserState.pos += 1;
+ }
+ foundStopChar = false;
+ }
+ while (parserState.pos < parserState.length) {
+ c = parserState.userQuery[parserState.pos];
+ if (isReturnArrow(parserState)) {
+ parserState.pos += 2;
+ // Get returned elements.
+ getItemsBefore(query, parserState, query.returned, "");
+ // Nothing can come afterward!
+ if (query.returned.length === 0) {
+ throw new Error("Expected at least one item after `->`");
+ }
+ break;
+ } else {
+ parserState.pos += 1;
+ }
+ }
+ }
+
+ /**
+ * Takes the user search input and returns an empty `ParsedQuery`.
+ *
+ * @param {string} userQuery
+ *
+ * @return {ParsedQuery}
+ */
+ function newParsedQuery(userQuery) {
+ return {
+ original: userQuery,
+ userQuery: userQuery.toLowerCase(),
+ typeFilter: NO_TYPE_FILTER,
+ elems: [],
+ returned: [],
+ // Total number of "top" elements (does not include generics).
+ foundElems: 0,
+ literalSearch: false,
+ error: null,
+ };
+ }
+
+ /**
+ * Build an URL with search parameters.
+ *
+ * @param {string} search - The current search being performed.
+ * @param {string|null} filterCrates - The current filtering crate (if any).
+ *
+ * @return {string}
+ */
+ function buildUrl(search, filterCrates) {
+ let extra = "?search=" + encodeURIComponent(search);
+
+ if (filterCrates !== null) {
+ extra += "&filter-crate=" + encodeURIComponent(filterCrates);
+ }
+ return getNakedUrl() + extra + window.location.hash;
+ }
+
+ /**
+ * Return the filtering crate or `null` if there is none.
+ *
+ * @return {string|null}
+ */
+ function getFilterCrates() {
+ const elem = document.getElementById("crate-search");
+
+ if (elem &&
+ elem.value !== "All crates" &&
+ hasOwnPropertyRustdoc(rawSearchIndex, elem.value)
+ ) {
+ return elem.value;
+ }
+ return null;
+ }
+
+ /**
+ * Parses the query.
+ *
+ * The supported syntax by this parser is as follow:
+ *
+ * ident = *(ALPHA / DIGIT / "_") [!]
+ * path = ident *(DOUBLE-COLON ident)
+ * arg = path [generics]
+ * arg-without-generic = path
+ * type-sep = COMMA/WS *(COMMA/WS)
+ * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
+ * nonempty-arg-list-without-generics = *(type-sep) arg-without-generic
+ * *(type-sep arg-without-generic) *(type-sep)
+ * generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list-without-generics ] *(type-sep)
+ * CLOSE-ANGLE-BRACKET/EOF
+ * return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
+ *
+ * exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
+ * type-search = [type-filter *WS COLON] [ nonempty-arg-list ] [ return-args ]
+ *
+ * query = *WS (exact-search / type-search) *WS
+ *
+ * type-filter = (
+ * "mod" /
+ * "externcrate" /
+ * "import" /
+ * "struct" /
+ * "enum" /
+ * "fn" /
+ * "type" /
+ * "static" /
+ * "trait" /
+ * "impl" /
+ * "tymethod" /
+ * "method" /
+ * "structfield" /
+ * "variant" /
+ * "macro" /
+ * "primitive" /
+ * "associatedtype" /
+ * "constant" /
+ * "associatedconstant" /
+ * "union" /
+ * "foreigntype" /
+ * "keyword" /
+ * "existential" /
+ * "attr" /
+ * "derive" /
+ * "traitalias")
+ *
+ * OPEN-ANGLE-BRACKET = "<"
+ * CLOSE-ANGLE-BRACKET = ">"
+ * COLON = ":"
+ * DOUBLE-COLON = "::"
+ * QUOTE = %x22
+ * COMMA = ","
+ * RETURN-ARROW = "->"
+ *
+ * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+ * DIGIT = %x30-39
+ * WS = %x09 / " "
+ *
+ * @param {string} val - The user query
+ *
+ * @return {ParsedQuery} - The parsed query
+ */
+ function parseQuery(userQuery) {
+ userQuery = userQuery.trim();
+ const parserState = {
+ length: userQuery.length,
+ pos: 0,
+ // Total number of elements (includes generics).
+ totalElems: 0,
+ genericsElems: 0,
+ typeFilter: null,
+ userQuery: userQuery.toLowerCase(),
+ };
+ let query = newParsedQuery(userQuery);
+
+ try {
+ parseInput(query, parserState);
+ if (parserState.typeFilter !== null) {
+ let typeFilter = parserState.typeFilter;
+ if (typeFilter === "const") {
+ typeFilter = "constant";
+ }
+ query.typeFilter = itemTypeFromName(typeFilter);
+ }
+ } catch (err) {
+ query = newParsedQuery(userQuery);
+ query.error = err.message;
+ query.typeFilter = -1;
+ return query;
+ }
+
+ if (!query.literalSearch) {
+ // If there is more than one element in the query, we switch to literalSearch in any
+ // case.
+ query.literalSearch = parserState.totalElems > 1;
+ }
+ query.foundElems = query.elems.length + query.returned.length;
+ return query;
+ }
+
+ /**
+ * Creates the query results.
+ *
+ * @param {Array<Result>} results_in_args
+ * @param {Array<Result>} results_returned
+ * @param {Array<Result>} results_in_args
+ * @param {ParsedQuery} parsedQuery
+ *
+ * @return {ResultsTable}
+ */
+ function createQueryResults(results_in_args, results_returned, results_others, parsedQuery) {
+ return {
+ "in_args": results_in_args,
+ "returned": results_returned,
+ "others": results_others,
+ "query": parsedQuery,
+ };
+ }
+
+ /**
+ * Executes the parsed query and builds a {ResultsTable}.
+ *
+ * @param {ParsedQuery} parsedQuery - The parsed user query
+ * @param {Object} searchWords - The list of search words to query against
+ * @param {Object} [filterCrates] - Crate to search in if defined
+ * @param {Object} [currentCrate] - Current crate, to rank results from this crate higher
+ *
+ * @return {ResultsTable}
+ */
+ function execQuery(parsedQuery, searchWords, filterCrates, currentCrate) {
+ const results_others = {}, results_in_args = {}, results_returned = {};
+
+ function transformResults(results) {
+ const duplicates = {};
+ const out = [];
+
+ for (const result of results) {
+ if (result.id > -1) {
+ const obj = searchIndex[result.id];
+ obj.lev = result.lev;
+ const res = buildHrefAndPath(obj);
+ obj.displayPath = pathSplitter(res[0]);
+ obj.fullPath = obj.displayPath + obj.name;
+ // To be sure than it some items aren't considered as duplicate.
+ obj.fullPath += "|" + obj.ty;
+
+ if (duplicates[obj.fullPath]) {
+ continue;
+ }
+ duplicates[obj.fullPath] = true;
+
+ obj.href = res[1];
+ out.push(obj);
+ if (out.length >= MAX_RESULTS) {
+ break;
+ }
+ }
+ }
+ return out;
+ }
+
+ function sortResults(results, isType, preferredCrate) {
+ const userQuery = parsedQuery.userQuery;
+ const ar = [];
+ for (const entry in results) {
+ if (hasOwnPropertyRustdoc(results, entry)) {
+ const result = results[entry];
+ result.word = searchWords[result.id];
+ result.item = searchIndex[result.id] || {};
+ ar.push(result);
+ }
+ }
+ results = ar;
+ // if there are no results then return to default and fail
+ if (results.length === 0) {
+ return [];
+ }
+
+ results.sort((aaa, bbb) => {
+ let a, b;
+
+ // sort by exact match with regard to the last word (mismatch goes later)
+ a = (aaa.word !== userQuery);
+ b = (bbb.word !== userQuery);
+ if (a !== b) {
+ return a - b;
+ }
+
+ // Sort by non levenshtein results and then levenshtein results by the distance
+ // (less changes required to match means higher rankings)
+ a = (aaa.lev);
+ b = (bbb.lev);
+ if (a !== b) {
+ return a - b;
+ }
+
+ // sort by crate (current crate comes first)
+ a = (aaa.item.crate !== preferredCrate);
+ b = (bbb.item.crate !== preferredCrate);
+ if (a !== b) {
+ return a - b;
+ }
+
+ // sort by item name length (longer goes later)
+ a = aaa.word.length;
+ b = bbb.word.length;
+ if (a !== b) {
+ return a - b;
+ }
+
+ // sort by item name (lexicographically larger goes later)
+ a = aaa.word;
+ b = bbb.word;
+ if (a !== b) {
+ return (a > b ? +1 : -1);
+ }
+
+ // sort by index of keyword in item name (no literal occurrence goes later)
+ a = (aaa.index < 0);
+ b = (bbb.index < 0);
+ if (a !== b) {
+ return a - b;
+ }
+ // (later literal occurrence, if any, goes later)
+ a = aaa.index;
+ b = bbb.index;
+ if (a !== b) {
+ return a - b;
+ }
+
+ // special precedence for primitive and keyword pages
+ if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) ||
+ (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) {
+ return -1;
+ }
+ if ((bbb.item.ty === TY_PRIMITIVE && aaa.item.ty !== TY_PRIMITIVE) ||
+ (bbb.item.ty === TY_KEYWORD && aaa.item.ty !== TY_KEYWORD)) {
+ return 1;
+ }
+
+ // sort by description (no description goes later)
+ a = (aaa.item.desc === "");
+ b = (bbb.item.desc === "");
+ if (a !== b) {
+ return a - b;
+ }
+
+ // sort by type (later occurrence in `itemTypes` goes later)
+ a = aaa.item.ty;
+ b = bbb.item.ty;
+ if (a !== b) {
+ return a - b;
+ }
+
+ // sort by path (lexicographically larger goes later)
+ a = aaa.item.path;
+ b = bbb.item.path;
+ if (a !== b) {
+ return (a > b ? +1 : -1);
+ }
+
+ // que sera, sera
+ return 0;
+ });
+
+ let nameSplit = null;
+ if (parsedQuery.elems.length === 1) {
+ const hasPath = typeof parsedQuery.elems[0].path === "undefined";
+ nameSplit = hasPath ? null : parsedQuery.elems[0].path;
+ }
+
+ for (const result of results) {
+ // this validation does not make sense when searching by types
+ if (result.dontValidate) {
+ continue;
+ }
+ const name = result.item.name.toLowerCase(),
+ path = result.item.path.toLowerCase(),
+ parent = result.item.parent;
+
+ if (!isType && !validateResult(name, path, nameSplit, parent)) {
+ result.id = -1;
+ }
+ }
+ return transformResults(results);
+ }
+
+ /**
+ * This function checks if the object (`row`) generics match the given type (`elem`)
+ * generics. If there are no generics on `row`, `defaultLev` is returned.
+ *
+ * @param {Row} row - The object to check.
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {integer} defaultLev - This is the value to return in case there are no generics.
+ *
+ * @return {integer} - Returns the best match (if any) or `MAX_LEV_DISTANCE + 1`.
+ */
+ function checkGenerics(row, elem, defaultLev) {
+ if (row.generics.length === 0) {
+ return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
+ } else if (row.generics.length > 0 && row.generics[0].name === null) {
+ return checkGenerics(row.generics[0], elem, defaultLev);
+ }
+ // The names match, but we need to be sure that all generics kinda
+ // match as well.
+ let elem_name;
+ if (elem.generics.length > 0 && row.generics.length >= elem.generics.length) {
+ const elems = Object.create(null);
+ for (const entry of row.generics) {
+ elem_name = entry.name;
+ if (elem_name === "") {
+ // Pure generic, needs to check into it.
+ if (checkGenerics(entry, elem, MAX_LEV_DISTANCE + 1) !== 0) {
+ return MAX_LEV_DISTANCE + 1;
+ }
+ continue;
+ }
+ if (elems[elem_name] === undefined) {
+ elems[elem_name] = 0;
+ }
+ elems[elem_name] += 1;
+ }
+ // We need to find the type that matches the most to remove it in order
+ // to move forward.
+ for (const generic of elem.generics) {
+ let match = null;
+ if (elems[generic.name]) {
+ match = generic.name;
+ } else {
+ for (elem_name in elems) {
+ if (!hasOwnPropertyRustdoc(elems, elem_name)) {
+ continue;
+ }
+ if (elem_name === generic) {
+ match = elem_name;
+ break;
+ }
+ }
+ }
+ if (match === null) {
+ return MAX_LEV_DISTANCE + 1;
+ }
+ elems[match] -= 1;
+ if (elems[match] === 0) {
+ delete elems[match];
+ }
+ }
+ return 0;
+ }
+ return MAX_LEV_DISTANCE + 1;
+ }
+
+ /**
+ * This function checks if the object (`row`) matches the given type (`elem`) and its
+ * generics (if any).
+ *
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
+ *
+ * @return {integer} - Returns a Levenshtein distance to the best match.
+ */
+ function checkIfInGenerics(row, elem) {
+ let lev = MAX_LEV_DISTANCE + 1;
+ for (const entry of row.generics) {
+ lev = Math.min(checkType(entry, elem, true), lev);
+ if (lev === 0) {
+ break;
+ }
+ }
+ return lev;
+ }
+
+ /**
+ * This function checks if the object (`row`) matches the given type (`elem`) and its
+ * generics (if any).
+ *
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {boolean} literalSearch
+ *
+ * @return {integer} - Returns a Levenshtein distance to the best match. If there is
+ * no match, returns `MAX_LEV_DISTANCE + 1`.
+ */
+ function checkType(row, elem, literalSearch) {
+ if (row.name === null) {
+ // This is a pure "generic" search, no need to run other checks.
+ if (row.generics.length > 0) {
+ return checkIfInGenerics(row, elem);
+ }
+ return MAX_LEV_DISTANCE + 1;
+ }
+
+ let lev = levenshtein(row.name, elem.name);
+ if (literalSearch) {
+ if (lev !== 0) {
+ // The name didn't match, let's try to check if the generics do.
+ if (elem.generics.length === 0) {
+ const checkGeneric = row.generics.length > 0;
+ if (checkGeneric && row.generics
+ .findIndex(tmp_elem => tmp_elem.name === elem.name) !== -1) {
+ return 0;
+ }
+ }
+ return MAX_LEV_DISTANCE + 1;
+ } else if (elem.generics.length > 0) {
+ return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1);
+ }
+ return 0;
+ } else if (row.generics.length > 0) {
+ if (elem.generics.length === 0) {
+ if (lev === 0) {
+ return 0;
+ }
+ // The name didn't match so we now check if the type we're looking for is inside
+ // the generics!
+ lev = checkIfInGenerics(row, elem);
+ // Now whatever happens, the returned distance is "less good" so we should mark
+ // it as such, and so we add 0.5 to the distance to make it "less good".
+ return lev + 0.5;
+ } else if (lev > MAX_LEV_DISTANCE) {
+ // So our item's name doesn't match at all and has generics.
+ //
+ // Maybe it's present in a sub generic? For example "f<A<B<C>>>()", if we're
+ // looking for "B<C>", we'll need to go down.
+ return checkIfInGenerics(row, elem);
+ } else {
+ // At this point, the name kinda match and we have generics to check, so
+ // let's go!
+ const tmp_lev = checkGenerics(row, elem, lev);
+ if (tmp_lev > MAX_LEV_DISTANCE) {
+ return MAX_LEV_DISTANCE + 1;
+ }
+ // We compute the median value of both checks and return it.
+ return (tmp_lev + lev) / 2;
+ }
+ } else if (elem.generics.length > 0) {
+ // In this case, we were expecting generics but there isn't so we simply reject this
+ // one.
+ return MAX_LEV_DISTANCE + 1;
+ }
+ // No generics on our query or on the target type so we can return without doing
+ // anything else.
+ return lev;
+ }
+
+ /**
+ * This function checks if the object (`row`) has an argument with the given type (`elem`).
+ *
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {integer} typeFilter
+ *
+ * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
+ * match, returns `MAX_LEV_DISTANCE + 1`.
+ */
+ function findArg(row, elem, typeFilter) {
+ let lev = MAX_LEV_DISTANCE + 1;
+
+ if (row && row.type && row.type.inputs && row.type.inputs.length > 0) {
+ for (const input of row.type.inputs) {
+ if (!typePassesFilter(typeFilter, input.ty)) {
+ continue;
+ }
+ lev = Math.min(lev, checkType(input, elem, parsedQuery.literalSearch));
+ if (lev === 0) {
+ return 0;
+ }
+ }
+ }
+ return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
+ }
+
+ /**
+ * This function checks if the object (`row`) returns the given type (`elem`).
+ *
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {integer} typeFilter
+ *
+ * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
+ * match, returns `MAX_LEV_DISTANCE + 1`.
+ */
+ function checkReturned(row, elem, typeFilter) {
+ let lev = MAX_LEV_DISTANCE + 1;
+
+ if (row && row.type && row.type.output.length > 0) {
+ const ret = row.type.output;
+ for (const ret_ty of ret) {
+ if (!typePassesFilter(typeFilter, ret_ty.ty)) {
+ continue;
+ }
+ lev = Math.min(lev, checkType(ret_ty, elem, parsedQuery.literalSearch));
+ if (lev === 0) {
+ return 0;
+ }
+ }
+ }
+ return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
+ }
+
+ function checkPath(contains, ty) {
+ if (contains.length === 0) {
+ return 0;
+ }
+ let ret_lev = MAX_LEV_DISTANCE + 1;
+ const path = ty.path.split("::");
+
+ if (ty.parent && ty.parent.name) {
+ path.push(ty.parent.name.toLowerCase());
+ }
+
+ const length = path.length;
+ const clength = contains.length;
+ if (clength > length) {
+ return MAX_LEV_DISTANCE + 1;
+ }
+ for (let i = 0; i < length; ++i) {
+ if (i + clength > length) {
+ break;
+ }
+ let lev_total = 0;
+ let aborted = false;
+ for (let x = 0; x < clength; ++x) {
+ const lev = levenshtein(path[i + x], contains[x]);
+ if (lev > MAX_LEV_DISTANCE) {
+ aborted = true;
+ break;
+ }
+ lev_total += lev;
+ }
+ if (!aborted) {
+ ret_lev = Math.min(ret_lev, Math.round(lev_total / clength));
+ }
+ }
+ return ret_lev;
+ }
+
+ function typePassesFilter(filter, type) {
+ // No filter or Exact mach
+ if (filter <= NO_TYPE_FILTER || filter === type) return true;
+
+ // Match related items
+ const name = itemTypes[type];
+ switch (itemTypes[filter]) {
+ case "constant":
+ return name === "associatedconstant";
+ case "fn":
+ return name === "method" || name === "tymethod";
+ case "type":
+ return name === "primitive" || name === "associatedtype";
+ case "trait":
+ return name === "traitalias";
+ }
+
+ // No match
+ return false;
+ }
+
+ function createAliasFromItem(item) {
+ return {
+ crate: item.crate,
+ name: item.name,
+ path: item.path,
+ desc: item.desc,
+ ty: item.ty,
+ parent: item.parent,
+ type: item.type,
+ is_alias: true,
+ };
+ }
+
+ function handleAliases(ret, query, filterCrates, currentCrate) {
+ const lowerQuery = query.toLowerCase();
+ // We separate aliases and crate aliases because we want to have current crate
+ // aliases to be before the others in the displayed results.
+ const aliases = [];
+ const crateAliases = [];
+ if (filterCrates !== null) {
+ if (ALIASES[filterCrates] && ALIASES[filterCrates][lowerQuery]) {
+ const query_aliases = ALIASES[filterCrates][lowerQuery];
+ for (const alias of query_aliases) {
+ aliases.push(createAliasFromItem(searchIndex[alias]));
+ }
+ }
+ } else {
+ Object.keys(ALIASES).forEach(crate => {
+ if (ALIASES[crate][lowerQuery]) {
+ const pushTo = crate === currentCrate ? crateAliases : aliases;
+ const query_aliases = ALIASES[crate][lowerQuery];
+ for (const alias of query_aliases) {
+ pushTo.push(createAliasFromItem(searchIndex[alias]));
+ }
+ }
+ });
+ }
+
+ const sortFunc = (aaa, bbb) => {
+ if (aaa.path < bbb.path) {
+ return 1;
+ } else if (aaa.path === bbb.path) {
+ return 0;
+ }
+ return -1;
+ };
+ crateAliases.sort(sortFunc);
+ aliases.sort(sortFunc);
+
+ const pushFunc = alias => {
+ alias.alias = query;
+ const res = buildHrefAndPath(alias);
+ alias.displayPath = pathSplitter(res[0]);
+ alias.fullPath = alias.displayPath + alias.name;
+ alias.href = res[1];
+
+ ret.others.unshift(alias);
+ if (ret.others.length > MAX_RESULTS) {
+ ret.others.pop();
+ }
+ };
+
+ aliases.forEach(pushFunc);
+ crateAliases.forEach(pushFunc);
+ }
+
+ /**
+ * This function adds the given result into the provided `results` map if it matches the
+ * following condition:
+ *
+ * * If it is a "literal search" (`parsedQuery.literalSearch`), then `lev` must be 0.
+ * * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`.
+ *
+ * The `results` map contains information which will be used to sort the search results:
+ *
+ * * `fullId` is a `string`` used as the key of the object we use for the `results` map.
+ * * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
+ * * `index` is an `integer`` used to sort by the position of the word in the item's name.
+ * * `lev` is the main metric used to sort the search results.
+ *
+ * @param {Results} results
+ * @param {string} fullId
+ * @param {integer} id
+ * @param {integer} index
+ * @param {integer} lev
+ */
+ function addIntoResults(results, fullId, id, index, lev) {
+ if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
+ if (results[fullId] !== undefined) {
+ const result = results[fullId];
+ if (result.dontValidate || result.lev <= lev) {
+ return;
+ }
+ }
+ results[fullId] = {
+ id: id,
+ index: index,
+ dontValidate: parsedQuery.literalSearch,
+ lev: lev,
+ };
+ }
+ }
+
+ /**
+ * This function is called in case the query is only one element (with or without generics).
+ * This element will be compared to arguments' and returned values' items and also to items.
+ *
+ * Other important thing to note: since there is only one element, we use levenshtein
+ * distance for name comparisons.
+ *
+ * @param {Row} row
+ * @param {integer} pos - Position in the `searchIndex`.
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {Results} results_others - Unqualified results (not in arguments nor in
+ * returned values).
+ * @param {Results} results_in_args - Matching arguments results.
+ * @param {Results} results_returned - Matching returned arguments results.
+ */
+ function handleSingleArg(
+ row,
+ pos,
+ elem,
+ results_others,
+ results_in_args,
+ results_returned
+ ) {
+ if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+ return;
+ }
+ let lev, lev_add = 0, index = -1;
+ const fullId = row.id;
+
+ const in_args = findArg(row, elem, parsedQuery.typeFilter);
+ const returned = checkReturned(row, elem, parsedQuery.typeFilter);
+
+ addIntoResults(results_in_args, fullId, pos, index, in_args);
+ addIntoResults(results_returned, fullId, pos, index, returned);
+
+ if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
+ return;
+ }
+ const searchWord = searchWords[pos];
+
+ if (parsedQuery.literalSearch) {
+ if (searchWord === elem.name) {
+ addIntoResults(results_others, fullId, pos, -1, 0);
+ }
+ return;
+ }
+
+ // No need to check anything else if it's a "pure" generics search.
+ if (elem.name.length === 0) {
+ if (row.type !== null) {
+ lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1);
+ addIntoResults(results_others, fullId, pos, index, lev);
+ }
+ return;
+ }
+
+ if (elem.fullPath.length > 1) {
+ lev = checkPath(elem.pathWithoutLast, row);
+ if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
+ return;
+ } else if (lev > 0) {
+ lev_add = lev / 10;
+ }
+ }
+
+ if (searchWord.indexOf(elem.pathLast) > -1 ||
+ row.normalizedName.indexOf(elem.pathLast) > -1
+ ) {
+ index = row.normalizedName.indexOf(elem.pathLast);
+ }
+ lev = levenshtein(searchWord, elem.pathLast);
+ if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) {
+ if (elem.pathLast.length < 6) {
+ lev = 1;
+ } else {
+ lev = 0;
+ }
+ }
+ lev += lev_add;
+ if (lev > MAX_LEV_DISTANCE) {
+ return;
+ } else if (index !== -1 && elem.fullPath.length < 2) {
+ lev -= 1;
+ }
+ if (lev < 0) {
+ lev = 0;
+ }
+ addIntoResults(results_others, fullId, pos, index, lev);
+ }
+
+ /**
+ * This function is called in case the query has more than one element. In this case, it'll
+ * try to match the items which validates all the elements. For `aa -> bb` will look for
+ * functions which have a parameter `aa` and has `bb` in its returned values.
+ *
+ * @param {Row} row
+ * @param {integer} pos - Position in the `searchIndex`.
+ * @param {Object} results
+ */
+ function handleArgs(row, pos, results) {
+ if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+ return;
+ }
+
+ let totalLev = 0;
+ let nbLev = 0;
+
+ // If the result is too "bad", we return false and it ends this search.
+ function checkArgs(elems, callback) {
+ for (const elem of elems) {
+ // There is more than one parameter to the query so all checks should be "exact"
+ const lev = callback(row, elem, NO_TYPE_FILTER);
+ if (lev <= 1) {
+ nbLev += 1;
+ totalLev += lev;
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+ if (!checkArgs(parsedQuery.elems, findArg)) {
+ return;
+ }
+ if (!checkArgs(parsedQuery.returned, checkReturned)) {
+ return;
+ }
+
+ if (nbLev === 0) {
+ return;
+ }
+ const lev = Math.round(totalLev / nbLev);
+ addIntoResults(results, row.id, pos, 0, lev);
+ }
+
+ function innerRunQuery() {
+ let elem, i, nSearchWords, in_returned, row;
+
+ if (parsedQuery.foundElems === 1) {
+ if (parsedQuery.elems.length === 1) {
+ elem = parsedQuery.elems[0];
+ for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+ // It means we want to check for this element everywhere (in names, args and
+ // returned).
+ handleSingleArg(
+ searchIndex[i],
+ i,
+ elem,
+ results_others,
+ results_in_args,
+ results_returned
+ );
+ }
+ } else if (parsedQuery.returned.length === 1) {
+ // We received one returned argument to check, so looking into returned values.
+ elem = parsedQuery.returned[0];
+ for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+ row = searchIndex[i];
+ in_returned = checkReturned(row, elem, parsedQuery.typeFilter);
+ addIntoResults(results_others, row.id, i, -1, in_returned);
+ }
+ }
+ } else if (parsedQuery.foundElems > 0) {
+ for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+ handleArgs(searchIndex[i], i, results_others);
+ }
+ }
+ }
+
+ if (parsedQuery.error === null) {
+ innerRunQuery();
+ }
+
+ const ret = createQueryResults(
+ sortResults(results_in_args, true, currentCrate),
+ sortResults(results_returned, true, currentCrate),
+ sortResults(results_others, false, currentCrate),
+ parsedQuery);
+ handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates, currentCrate);
+ if (parsedQuery.error !== null && ret.others.length !== 0) {
+ // It means some doc aliases were found so let's "remove" the error!
+ ret.query.error = null;
+ }
+ return ret;
+ }
+
+ /**
+ * Validate performs the following boolean logic. For example:
+ * "File::open" will give IF A PARENT EXISTS => ("file" && "open")
+ * exists in (name || path || parent) OR => ("file" && "open") exists in
+ * (name || path )
+ *
+ * This could be written functionally, but I wanted to minimise
+ * functions on stack.
+ *
+ * @param {string} name - The name of the result
+ * @param {string} path - The path of the result
+ * @param {string} keys - The keys to be used (["file", "open"])
+ * @param {Object} parent - The parent of the result
+ *
+ * @return {boolean} - Whether the result is valid or not
+ */
+ function validateResult(name, path, keys, parent) {
+ if (!keys || !keys.length) {
+ return true;
+ }
+ for (const key of keys) {
+ // each check is for validation so we negate the conditions and invalidate
+ if (!(
+ // check for an exact name match
+ name.indexOf(key) > -1 ||
+ // then an exact path match
+ path.indexOf(key) > -1 ||
+ // next if there is a parent, check for exact parent match
+ (parent !== undefined && parent.name !== undefined &&
+ parent.name.toLowerCase().indexOf(key) > -1) ||
+ // lastly check to see if the name was a levenshtein match
+ levenshtein(name, key) <= MAX_LEV_DISTANCE)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function nextTab(direction) {
+ const next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
+ searchState.focusedByTab[searchState.currentTab] = document.activeElement;
+ printTab(next);
+ focusSearchResult();
+ }
+
+ // Focus the first search result on the active tab, or the result that
+ // was focused last time this tab was active.
+ function focusSearchResult() {
+ const target = searchState.focusedByTab[searchState.currentTab] ||
+ document.querySelectorAll(".search-results.active a").item(0) ||
+ document.querySelectorAll("#titles > button").item(searchState.currentTab);
+ if (target) {
+ target.focus();
+ }
+ }
+
+ function buildHrefAndPath(item) {
+ let displayPath;
+ let href;
+ const type = itemTypes[item.ty];
+ const name = item.name;
+ let path = item.path;
+
+ if (type === "mod") {
+ displayPath = path + "::";
+ href = ROOT_PATH + path.replace(/::/g, "/") + "/" +
+ name + "/index.html";
+ } else if (type === "import") {
+ displayPath = item.path + "::";
+ href = ROOT_PATH + item.path.replace(/::/g, "/") + "/index.html#reexport." + name;
+ } else if (type === "primitive" || type === "keyword") {
+ displayPath = "";
+ href = ROOT_PATH + path.replace(/::/g, "/") +
+ "/" + type + "." + name + ".html";
+ } else if (type === "externcrate") {
+ displayPath = "";
+ href = ROOT_PATH + name + "/index.html";
+ } else if (item.parent !== undefined) {
+ const myparent = item.parent;
+ let anchor = "#" + type + "." + name;
+ const parentType = itemTypes[myparent.ty];
+ let pageType = parentType;
+ let pageName = myparent.name;
+
+ if (parentType === "primitive") {
+ displayPath = myparent.name + "::";
+ } else if (type === "structfield" && parentType === "variant") {
+ // Structfields belonging to variants are special: the
+ // final path element is the enum name.
+ const enumNameIdx = item.path.lastIndexOf("::");
+ const enumName = item.path.substr(enumNameIdx + 2);
+ path = item.path.substr(0, enumNameIdx);
+ displayPath = path + "::" + enumName + "::" + myparent.name + "::";
+ anchor = "#variant." + myparent.name + ".field." + name;
+ pageType = "enum";
+ pageName = enumName;
+ } else {
+ displayPath = path + "::" + myparent.name + "::";
+ }
+ href = ROOT_PATH + path.replace(/::/g, "/") +
+ "/" + pageType +
+ "." + pageName +
+ ".html" + anchor;
+ } else {
+ displayPath = item.path + "::";
+ href = ROOT_PATH + item.path.replace(/::/g, "/") +
+ "/" + type + "." + name + ".html";
+ }
+ return [displayPath, href];
+ }
+
+ function escape(content) {
+ const h1 = document.createElement("h1");
+ h1.textContent = content;
+ return h1.innerHTML;
+ }
+
+ function pathSplitter(path) {
+ const tmp = "<span>" + path.replace(/::/g, "::</span><span>");
+ if (tmp.endsWith("<span>")) {
+ return tmp.slice(0, tmp.length - 6);
+ }
+ return tmp;
+ }
+
+ /**
+ * Render a set of search results for a single tab.
+ * @param {Array<?>} array - The search results for this tab
+ * @param {ParsedQuery} query
+ * @param {boolean} display - True if this is the active tab
+ */
+ function addTab(array, query, display) {
+ let extraClass = "";
+ if (display === true) {
+ extraClass = " active";
+ }
+
+ const output = document.createElement("div");
+ let length = 0;
+ if (array.length > 0) {
+ output.className = "search-results " + extraClass;
+
+ array.forEach(item => {
+ const name = item.name;
+ const type = itemTypes[item.ty];
+
+ length += 1;
+
+ let extra = "";
+ if (type === "primitive") {
+ extra = " <i>(primitive type)</i>";
+ } else if (type === "keyword") {
+ extra = " <i>(keyword)</i>";
+ }
+
+ const link = document.createElement("a");
+ link.className = "result-" + type;
+ link.href = item.href;
+
+ const wrapper = document.createElement("div");
+ const resultName = document.createElement("div");
+ resultName.className = "result-name";
+
+ if (item.is_alias) {
+ const alias = document.createElement("span");
+ alias.className = "alias";
+
+ const bold = document.createElement("b");
+ bold.innerText = item.alias;
+ alias.appendChild(bold);
+
+ alias.insertAdjacentHTML(
+ "beforeend",
+ "<span class=\"grey\"><i>&nbsp;- see&nbsp;</i></span>");
+
+ resultName.appendChild(alias);
+ }
+ resultName.insertAdjacentHTML(
+ "beforeend",
+ item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>");
+ wrapper.appendChild(resultName);
+
+ const description = document.createElement("div");
+ description.className = "desc";
+ const spanDesc = document.createElement("span");
+ spanDesc.insertAdjacentHTML("beforeend", item.desc);
+
+ description.appendChild(spanDesc);
+ wrapper.appendChild(description);
+ link.appendChild(wrapper);
+ output.appendChild(link);
+ });
+ } else if (query.error === null) {
+ output.className = "search-failed" + extraClass;
+ output.innerHTML = "No results :(<br/>" +
+ "Try on <a href=\"https://duckduckgo.com/?q=" +
+ encodeURIComponent("rust " + query.userQuery) +
+ "\">DuckDuckGo</a>?<br/><br/>" +
+ "Or try looking in one of these:<ul><li>The <a " +
+ "href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
+ " for technical details about the language.</li><li><a " +
+ "href=\"https://doc.rust-lang.org/rust-by-example/index.html\">Rust By " +
+ "Example</a> for expository code examples.</a></li><li>The <a " +
+ "href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " +
+ "introductions to language features and the language itself.</li><li><a " +
+ "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
+ " <a href=\"https://crates.io/\">crates.io</a>.</li></ul>";
+ }
+ return [output, length];
+ }
+
+ function makeTabHeader(tabNb, text, nbElems) {
+ if (searchState.currentTab === tabNb) {
+ return "<button class=\"selected\">" + text +
+ " <div class=\"count\">(" + nbElems + ")</div></button>";
+ }
+ return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
+ }
+
+ /**
+ * @param {ResultsTable} results
+ * @param {boolean} go_to_first
+ * @param {string} filterCrates
+ */
+ function showResults(results, go_to_first, filterCrates) {
+ const search = searchState.outputElement();
+ if (go_to_first || (results.others.length === 1
+ && getSettingValue("go-to-only-result") === "true"
+ // By default, the search DOM element is "empty" (meaning it has no children not
+ // text content). Once a search has been run, it won't be empty, even if you press
+ // ESC or empty the search input (which also "cancels" the search).
+ && (!search.firstChild || search.firstChild.innerText !== searchState.loadingText))
+ ) {
+ const elem = document.createElement("a");
+ elem.href = results.others[0].href;
+ removeClass(elem, "active");
+ // For firefox, we need the element to be in the DOM so it can be clicked.
+ document.body.appendChild(elem);
+ elem.click();
+ return;
+ }
+ if (results.query === undefined) {
+ results.query = parseQuery(searchState.input.value);
+ }
+
+ currentResults = results.query.userQuery;
+
+ const ret_others = addTab(results.others, results.query, true);
+ const ret_in_args = addTab(results.in_args, results.query, false);
+ const ret_returned = addTab(results.returned, results.query, false);
+
+ // Navigate to the relevant tab if the current tab is empty, like in case users search
+ // for "-> String". If they had selected another tab previously, they have to click on
+ // it again.
+ let currentTab = searchState.currentTab;
+ if ((currentTab === 0 && ret_others[1] === 0) ||
+ (currentTab === 1 && ret_in_args[1] === 0) ||
+ (currentTab === 2 && ret_returned[1] === 0)) {
+ if (ret_others[1] !== 0) {
+ currentTab = 0;
+ } else if (ret_in_args[1] !== 0) {
+ currentTab = 1;
+ } else if (ret_returned[1] !== 0) {
+ currentTab = 2;
+ }
+ }
+
+ let crates = "";
+ const crates_list = Object.keys(rawSearchIndex);
+ if (crates_list.length > 1) {
+ crates = " in <select id=\"crate-search\"><option value=\"All crates\">" +
+ "All crates</option>";
+ for (const c of crates_list) {
+ crates += `<option value="${c}" ${c === filterCrates && "selected"}>${c}</option>`;
+ }
+ crates += "</select>";
+ }
+
+ let typeFilter = "";
+ if (results.query.typeFilter !== NO_TYPE_FILTER) {
+ typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
+ }
+
+ let output = "<div id=\"search-settings\">" +
+ `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
+ `${typeFilter}</h1>${crates}</div>`;
+ if (results.query.error !== null) {
+ output += `<h3>Query parser error: "${results.query.error}".</h3>`;
+ output += "<div id=\"titles\">" +
+ makeTabHeader(0, "In Names", ret_others[1]) +
+ "</div>";
+ currentTab = 0;
+ } else if (results.query.foundElems <= 1 && results.query.returned.length === 0) {
+ output += "<div id=\"titles\">" +
+ makeTabHeader(0, "In Names", ret_others[1]) +
+ makeTabHeader(1, "In Parameters", ret_in_args[1]) +
+ makeTabHeader(2, "In Return Types", ret_returned[1]) +
+ "</div>";
+ } else {
+ const signatureTabTitle =
+ results.query.elems.length === 0 ? "In Function Return Types" :
+ results.query.returned.length === 0 ? "In Function Parameters" :
+ "In Function Signatures";
+ output += "<div id=\"titles\">" +
+ makeTabHeader(0, signatureTabTitle, ret_others[1]) +
+ "</div>";
+ currentTab = 0;
+ }
+
+ const resultsElem = document.createElement("div");
+ resultsElem.id = "results";
+ resultsElem.appendChild(ret_others[0]);
+ resultsElem.appendChild(ret_in_args[0]);
+ resultsElem.appendChild(ret_returned[0]);
+
+ search.innerHTML = output;
+ const crateSearch = document.getElementById("crate-search");
+ if (crateSearch) {
+ crateSearch.addEventListener("input", updateCrate);
+ }
+ search.appendChild(resultsElem);
+ // Reset focused elements.
+ searchState.showResults(search);
+ const elems = document.getElementById("titles").childNodes;
+ searchState.focusedByTab = [];
+ let i = 0;
+ for (const elem of elems) {
+ const j = i;
+ elem.onclick = () => printTab(j);
+ searchState.focusedByTab.push(null);
+ i += 1;
+ }
+ printTab(currentTab);
+ }
+
+ /**
+ * Perform a search based on the current state of the search input element
+ * and display the results.
+ * @param {Event} [e] - The event that triggered this search, if any
+ * @param {boolean} [forced]
+ */
+ function search(e, forced) {
+ const params = searchState.getQueryStringParams();
+ const query = parseQuery(searchState.input.value.trim());
+
+ if (e) {
+ e.preventDefault();
+ }
+
+ if (!forced && query.userQuery === currentResults) {
+ if (query.userQuery.length > 0) {
+ putBackSearch();
+ }
+ return;
+ }
+
+ let filterCrates = getFilterCrates();
+
+ // In case we have no information about the saved crate and there is a URL query parameter,
+ // we override it with the URL query parameter.
+ if (filterCrates === null && params["filter-crate"] !== undefined) {
+ filterCrates = params["filter-crate"];
+ }
+
+ // Update document title to maintain a meaningful browser history
+ searchState.title = "Results for " + query.original + " - Rust";
+
+ // Because searching is incremental by character, only the most
+ // recent search query is added to the browser history.
+ if (browserSupportsHistoryApi()) {
+ const newURL = buildUrl(query.original, filterCrates);
+
+ if (!history.state && !params.search) {
+ history.pushState(null, "", newURL);
+ } else {
+ history.replaceState(null, "", newURL);
+ }
+ }
+
+ showResults(
+ execQuery(query, searchWords, filterCrates, window.currentCrate),
+ params.go_to_first,
+ filterCrates);
+ }
+
+ /**
+ * Convert a list of RawFunctionType / ID to object-based FunctionType.
+ *
+ * Crates often have lots of functions in them, and it's common to have a large number of
+ * functions that operate on a small set of data types, so the search index compresses them
+ * by encoding function parameter and return types as indexes into an array of names.
+ *
+ * Even when a general-purpose compression algorithm is used, this is still a win. I checked.
+ * https://github.com/rust-lang/rust/pull/98475#issue-1284395985
+ *
+ * The format for individual function types is encoded in
+ * librustdoc/html/render/mod.rs: impl Serialize for RenderType
+ *
+ * @param {null|Array<RawFunctionType>} types
+ * @param {Array<{name: string, ty: number}>} lowercasePaths
+ *
+ * @return {Array<FunctionSearchType>}
+ */
+ function buildItemSearchTypeAll(types, lowercasePaths) {
+ const PATH_INDEX_DATA = 0;
+ const GENERICS_DATA = 1;
+ return types.map(type => {
+ let pathIndex, generics;
+ if (typeof type === "number") {
+ pathIndex = type;
+ generics = [];
+ } else {
+ pathIndex = type[PATH_INDEX_DATA];
+ generics = buildItemSearchTypeAll(type[GENERICS_DATA], lowercasePaths);
+ }
+ return {
+ // `0` is used as a sentinel because it's fewer bytes than `null`
+ name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name,
+ ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty,
+ generics: generics,
+ };
+ });
+ }
+
+ /**
+ * Convert from RawFunctionSearchType to FunctionSearchType.
+ *
+ * Crates often have lots of functions in them, and function signatures are sometimes complex,
+ * so rustdoc uses a pretty tight encoding for them. This function converts it to a simpler,
+ * object-based encoding so that the actual search code is more readable and easier to debug.
+ *
+ * The raw function search type format is generated using serde in
+ * librustdoc/html/render/mod.rs: impl Serialize for IndexItemFunctionType
+ *
+ * @param {RawFunctionSearchType} functionSearchType
+ * @param {Array<{name: string, ty: number}>} lowercasePaths
+ *
+ * @return {null|FunctionSearchType}
+ */
+ function buildFunctionSearchType(functionSearchType, lowercasePaths) {
+ const INPUTS_DATA = 0;
+ const OUTPUT_DATA = 1;
+ // `0` is used as a sentinel because it's fewer bytes than `null`
+ if (functionSearchType === 0) {
+ return null;
+ }
+ let inputs, output;
+ if (typeof functionSearchType[INPUTS_DATA] === "number") {
+ const pathIndex = functionSearchType[INPUTS_DATA];
+ inputs = [{
+ name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name,
+ ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty,
+ generics: [],
+ }];
+ } else {
+ inputs = buildItemSearchTypeAll(functionSearchType[INPUTS_DATA], lowercasePaths);
+ }
+ if (functionSearchType.length > 1) {
+ if (typeof functionSearchType[OUTPUT_DATA] === "number") {
+ const pathIndex = functionSearchType[OUTPUT_DATA];
+ output = [{
+ name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name,
+ ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty,
+ generics: [],
+ }];
+ } else {
+ output = buildItemSearchTypeAll(functionSearchType[OUTPUT_DATA], lowercasePaths);
+ }
+ } else {
+ output = [];
+ }
+ return {
+ inputs, output,
+ };
+ }
+
+ function buildIndex(rawSearchIndex) {
+ searchIndex = [];
+ /**
+ * @type {Array<string>}
+ */
+ const searchWords = [];
+ let i, word;
+ let currentIndex = 0;
+ let id = 0;
+
+ for (const crate in rawSearchIndex) {
+ if (!hasOwnPropertyRustdoc(rawSearchIndex, crate)) {
+ continue;
+ }
+
+ let crateSize = 0;
+
+ /**
+ * The raw search data for a given crate. `n`, `t`, `d`, and `q`, `i`, and `f`
+ * are arrays with the same length. n[i] contains the name of an item.
+ * t[i] contains the type of that item (as a small integer that represents an
+ * offset in `itemTypes`). d[i] contains the description of that item.
+ *
+ * q[i] contains the full path of the item, or an empty string indicating
+ * "same as q[i-1]".
+ *
+ * i[i] contains an item's parent, usually a module. For compactness,
+ * it is a set of indexes into the `p` array.
+ *
+ * f[i] contains function signatures, or `0` if the item isn't a function.
+ * Functions are themselves encoded as arrays. The first item is a list of
+ * types representing the function's inputs, and the second list item is a list
+ * of types representing the function's output. Tuples are flattened.
+ * Types are also represented as arrays; the first item is an index into the `p`
+ * array, while the second is a list of types representing any generic parameters.
+ *
+ * `a` defines aliases with an Array of pairs: [name, offset], where `offset`
+ * points into the n/t/d/q/i/f arrays.
+ *
+ * `doc` contains the description of the crate.
+ *
+ * `p` is a list of path/type pairs. It is used for parents and function parameters.
+ *
+ * @type {{
+ * doc: string,
+ * a: Object,
+ * n: Array<string>,
+ * t: Array<Number>,
+ * d: Array<string>,
+ * q: Array<string>,
+ * i: Array<Number>,
+ * f: Array<RawFunctionSearchType>,
+ * p: Array<Object>,
+ * }}
+ */
+ const crateCorpus = rawSearchIndex[crate];
+
+ searchWords.push(crate);
+ // This object should have exactly the same set of fields as the "row"
+ // object defined below. Your JavaScript runtime will thank you.
+ // https://mathiasbynens.be/notes/shapes-ics
+ const crateRow = {
+ crate: crate,
+ ty: 1, // == ExternCrate
+ name: crate,
+ path: "",
+ desc: crateCorpus.doc,
+ parent: undefined,
+ type: null,
+ id: id,
+ normalizedName: crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, ""),
+ };
+ id += 1;
+ searchIndex.push(crateRow);
+ currentIndex += 1;
+
+ // an array of (Number) item types
+ const itemTypes = crateCorpus.t;
+ // an array of (String) item names
+ const itemNames = crateCorpus.n;
+ // an array of (String) full paths (or empty string for previous path)
+ const itemPaths = crateCorpus.q;
+ // an array of (String) descriptions
+ const itemDescs = crateCorpus.d;
+ // an array of (Number) the parent path index + 1 to `paths`, or 0 if none
+ const itemParentIdxs = crateCorpus.i;
+ // an array of (Object | null) the type of the function, if any
+ const itemFunctionSearchTypes = crateCorpus.f;
+ // an array of [(Number) item type,
+ // (String) name]
+ const paths = crateCorpus.p;
+ // an array of [(String) alias name
+ // [Number] index to items]
+ const aliases = crateCorpus.a;
+
+ // an array of [{name: String, ty: Number}]
+ const lowercasePaths = [];
+
+ // convert `rawPaths` entries into object form
+ // generate normalizedPaths for function search mode
+ let len = paths.length;
+ for (i = 0; i < len; ++i) {
+ lowercasePaths.push({ty: paths[i][0], name: paths[i][1].toLowerCase()});
+ paths[i] = {ty: paths[i][0], name: paths[i][1]};
+ }
+
+ // convert `item*` into an object form, and construct word indices.
+ //
+ // before any analysis is performed lets gather the search terms to
+ // search against apart from the rest of the data. This is a quick
+ // operation that is cached for the life of the page state so that
+ // all other search operations have access to this cached data for
+ // faster analysis operations
+ len = itemTypes.length;
+ let lastPath = "";
+ for (i = 0; i < len; ++i) {
+ // This object should have exactly the same set of fields as the "crateRow"
+ // object defined above.
+ if (typeof itemNames[i] === "string") {
+ word = itemNames[i].toLowerCase();
+ searchWords.push(word);
+ } else {
+ word = "";
+ searchWords.push("");
+ }
+ const row = {
+ crate: crate,
+ ty: itemTypes[i],
+ name: itemNames[i],
+ path: itemPaths[i] ? itemPaths[i] : lastPath,
+ desc: itemDescs[i],
+ parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined,
+ type: buildFunctionSearchType(itemFunctionSearchTypes[i], lowercasePaths),
+ id: id,
+ normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""),
+ };
+ id += 1;
+ searchIndex.push(row);
+ lastPath = row.path;
+ crateSize += 1;
+ }
+
+ if (aliases) {
+ ALIASES[crate] = Object.create(null);
+ for (const alias_name in aliases) {
+ if (!hasOwnPropertyRustdoc(aliases, alias_name)) {
+ continue;
+ }
+
+ if (!hasOwnPropertyRustdoc(ALIASES[crate], alias_name)) {
+ ALIASES[crate][alias_name] = [];
+ }
+ for (const local_alias of aliases[alias_name]) {
+ ALIASES[crate][alias_name].push(local_alias + currentIndex);
+ }
+ }
+ }
+ currentIndex += crateSize;
+ }
+ return searchWords;
+ }
+
+ /**
+ * Callback for when the search form is submitted.
+ * @param {Event} [e] - The event that triggered this call, if any
+ */
+ function onSearchSubmit(e) {
+ e.preventDefault();
+ searchState.clearInputTimeout();
+ search();
+ }
+
+ function putBackSearch() {
+ const search_input = searchState.input;
+ if (!searchState.input) {
+ return;
+ }
+ if (search_input.value !== "" && !searchState.isDisplayed()) {
+ searchState.showResults();
+ if (browserSupportsHistoryApi()) {
+ history.replaceState(null, "",
+ buildUrl(search_input.value, getFilterCrates()));
+ }
+ document.title = searchState.title;
+ }
+ }
+
+ function registerSearchEvents() {
+ const params = searchState.getQueryStringParams();
+
+ // Populate search bar with query string search term when provided,
+ // but only if the input bar is empty. This avoid the obnoxious issue
+ // where you start trying to do a search, and the index loads, and
+ // suddenly your search is gone!
+ if (searchState.input.value === "") {
+ searchState.input.value = params.search || "";
+ }
+
+ const searchAfter500ms = () => {
+ searchState.clearInputTimeout();
+ if (searchState.input.value.length === 0) {
+ if (browserSupportsHistoryApi()) {
+ history.replaceState(null, window.currentCrate + " - Rust",
+ getNakedUrl() + window.location.hash);
+ }
+ searchState.hideResults();
+ } else {
+ searchState.timeout = setTimeout(search, 500);
+ }
+ };
+ searchState.input.onkeyup = searchAfter500ms;
+ searchState.input.oninput = searchAfter500ms;
+ document.getElementsByClassName("search-form")[0].onsubmit = onSearchSubmit;
+ searchState.input.onchange = e => {
+ if (e.target !== document.activeElement) {
+ // To prevent doing anything when it's from a blur event.
+ return;
+ }
+ // Do NOT e.preventDefault() here. It will prevent pasting.
+ searchState.clearInputTimeout();
+ // zero-timeout necessary here because at the time of event handler execution the
+ // pasted content is not in the input field yet. Shouldn’t make any difference for
+ // change, though.
+ setTimeout(search, 0);
+ };
+ searchState.input.onpaste = searchState.input.onchange;
+
+ searchState.outputElement().addEventListener("keydown", e => {
+ // We only handle unmodified keystrokes here. We don't want to interfere with,
+ // for instance, alt-left and alt-right for history navigation.
+ if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
+ return;
+ }
+ // up and down arrow select next/previous search result, or the
+ // search box if we're already at the top.
+ if (e.which === 38) { // up
+ const previous = document.activeElement.previousElementSibling;
+ if (previous) {
+ previous.focus();
+ } else {
+ searchState.focus();
+ }
+ e.preventDefault();
+ } else if (e.which === 40) { // down
+ const next = document.activeElement.nextElementSibling;
+ if (next) {
+ next.focus();
+ }
+ const rect = document.activeElement.getBoundingClientRect();
+ if (window.innerHeight - rect.bottom < rect.height) {
+ window.scrollBy(0, rect.height);
+ }
+ e.preventDefault();
+ } else if (e.which === 37) { // left
+ nextTab(-1);
+ e.preventDefault();
+ } else if (e.which === 39) { // right
+ nextTab(1);
+ e.preventDefault();
+ }
+ });
+
+ searchState.input.addEventListener("keydown", e => {
+ if (e.which === 40) { // down
+ focusSearchResult();
+ e.preventDefault();
+ }
+ });
+
+ searchState.input.addEventListener("focus", () => {
+ putBackSearch();
+ });
+
+ searchState.input.addEventListener("blur", () => {
+ searchState.input.placeholder = searchState.input.origPlaceholder;
+ });
+
+ // Push and pop states are used to add search results to the browser
+ // history.
+ if (browserSupportsHistoryApi()) {
+ // Store the previous <title> so we can revert back to it later.
+ const previousTitle = document.title;
+
+ window.addEventListener("popstate", e => {
+ const params = searchState.getQueryStringParams();
+ // Revert to the previous title manually since the History
+ // API ignores the title parameter.
+ document.title = previousTitle;
+ // When browsing forward to search results the previous
+ // search will be repeated, so the currentResults are
+ // cleared to ensure the search is successful.
+ currentResults = null;
+ // Synchronize search bar with query string state and
+ // perform the search. This will empty the bar if there's
+ // nothing there, which lets you really go back to a
+ // previous state with nothing in the bar.
+ if (params.search && params.search.length > 0) {
+ searchState.input.value = params.search;
+ // Some browsers fire "onpopstate" for every page load
+ // (Chrome), while others fire the event only when actually
+ // popping a state (Firefox), which is why search() is
+ // called both here and at the end of the startSearch()
+ // function.
+ search(e);
+ } else {
+ searchState.input.value = "";
+ // When browsing back from search results the main page
+ // visibility must be reset.
+ searchState.hideResults();
+ }
+ });
+ }
+
+ // This is required in firefox to avoid this problem: Navigating to a search result
+ // with the keyboard, hitting enter, and then hitting back would take you back to
+ // the doc page, rather than the search that should overlay it.
+ // This was an interaction between the back-forward cache and our handlers
+ // that try to sync state between the URL and the search input. To work around it,
+ // do a small amount of re-init on page show.
+ window.onpageshow = () => {
+ const qSearch = searchState.getQueryStringParams().search;
+ if (searchState.input.value === "" && qSearch) {
+ searchState.input.value = qSearch;
+ }
+ search();
+ };
+ }
+
+ function updateCrate(ev) {
+ if (ev.target.value === "All crates") {
+ // If we don't remove it from the URL, it'll be picked up again by the search.
+ const params = searchState.getQueryStringParams();
+ const query = searchState.input.value.trim();
+ if (!history.state && !params.search) {
+ history.pushState(null, "", buildUrl(query, null));
+ } else {
+ history.replaceState(null, "", buildUrl(query, null));
+ }
+ }
+ // In case you "cut" the entry from the search input, then change the crate filter
+ // before paste back the previous search, you get the old search results without
+ // the filter. To prevent this, we need to remove the previous results.
+ currentResults = null;
+ search(undefined, true);
+ }
+
+ /**
+ * @type {Array<string>}
+ */
+ const searchWords = buildIndex(rawSearchIndex);
+ if (typeof window !== "undefined") {
+ registerSearchEvents();
+ // If there's a search term in the URL, execute the search now.
+ if (window.searchState.getQueryStringParams().search) {
+ search();
+ }
+ }
+
+ if (typeof exports !== "undefined") {
+ exports.initSearch = initSearch;
+ exports.execQuery = execQuery;
+ exports.parseQuery = parseQuery;
+ }
+ return searchWords;
+}
+
+if (typeof window !== "undefined") {
+ window.initSearch = initSearch;
+ if (window.searchIndex !== undefined) {
+ initSearch(window.searchIndex);
+ }
+} else {
+ // Running in Node, not a browser. Run initSearch just to produce the
+ // exports.
+ initSearch({});
+}
+
+
+})();
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
new file mode 100644
index 000000000..797b931af
--- /dev/null
+++ b/src/librustdoc/html/static/js/settings.js
@@ -0,0 +1,272 @@
+// Local js definitions:
+/* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */
+/* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */
+/* global MAIN_ID, getVar, getSettingsButton */
+
+"use strict";
+
+(function() {
+ const isSettingsPage = window.location.pathname.endsWith("/settings.html");
+
+ function changeSetting(settingName, value) {
+ updateLocalStorage(settingName, value);
+
+ switch (settingName) {
+ case "theme":
+ case "preferred-dark-theme":
+ case "preferred-light-theme":
+ case "use-system-theme":
+ updateSystemTheme();
+ updateLightAndDark();
+ break;
+ }
+ }
+
+ function handleKey(ev) {
+ // Don't interfere with browser shortcuts
+ if (ev.ctrlKey || ev.altKey || ev.metaKey) {
+ return;
+ }
+ switch (getVirtualKey(ev)) {
+ case "Enter":
+ case "Return":
+ case "Space":
+ ev.target.checked = !ev.target.checked;
+ ev.preventDefault();
+ break;
+ }
+ }
+
+ function showLightAndDark() {
+ addClass(document.getElementById("theme").parentElement, "hidden");
+ removeClass(document.getElementById("preferred-light-theme").parentElement, "hidden");
+ removeClass(document.getElementById("preferred-dark-theme").parentElement, "hidden");
+ }
+
+ function hideLightAndDark() {
+ addClass(document.getElementById("preferred-light-theme").parentElement, "hidden");
+ addClass(document.getElementById("preferred-dark-theme").parentElement, "hidden");
+ removeClass(document.getElementById("theme").parentElement, "hidden");
+ }
+
+ function updateLightAndDark() {
+ if (getSettingValue("use-system-theme") !== "false") {
+ showLightAndDark();
+ } else {
+ hideLightAndDark();
+ }
+ }
+
+ function setEvents(settingsElement) {
+ updateLightAndDark();
+ onEachLazy(settingsElement.getElementsByClassName("slider"), elem => {
+ const toggle = elem.previousElementSibling;
+ const settingId = toggle.id;
+ const settingValue = getSettingValue(settingId);
+ if (settingValue !== null) {
+ toggle.checked = settingValue === "true";
+ }
+ toggle.onchange = function() {
+ changeSetting(this.id, this.checked);
+ };
+ toggle.onkeyup = handleKey;
+ toggle.onkeyrelease = handleKey;
+ });
+ onEachLazy(settingsElement.getElementsByClassName("select-wrapper"), elem => {
+ const select = elem.getElementsByTagName("select")[0];
+ const settingId = select.id;
+ const settingValue = getSettingValue(settingId);
+ if (settingValue !== null) {
+ select.value = settingValue;
+ }
+ select.onchange = function() {
+ changeSetting(this.id, this.value);
+ };
+ });
+ onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => {
+ const settingId = elem.name;
+ const settingValue = getSettingValue(settingId);
+ if (settingValue !== null && settingValue !== "null") {
+ elem.checked = settingValue === elem.value;
+ }
+ elem.addEventListener("change", ev => {
+ changeSetting(ev.target.name, ev.target.value);
+ });
+ });
+ }
+
+ /**
+ * This function builds the sections inside the "settings page". It takes a `settings` list
+ * as argument which describes each setting and how to render it. It returns a string
+ * representing the raw HTML.
+ *
+ * @param {Array<Object>} settings
+ *
+ * @return {string}
+ */
+ function buildSettingsPageSections(settings) {
+ let output = "";
+
+ for (const setting of settings) {
+ output += "<div class=\"setting-line\">";
+ const js_data_name = setting["js_name"];
+ const setting_name = setting["name"];
+
+ if (setting["options"] !== undefined) {
+ // This is a select setting.
+ output += `<div class="radio-line" id="${js_data_name}">\
+ <span class="setting-name">${setting_name}</span>\
+ <div class="choices">`;
+ onEach(setting["options"], option => {
+ const checked = option === setting["default"] ? " checked" : "";
+
+ output += `<label for="${js_data_name}-${option}" class="choice">\
+ <input type="radio" name="${js_data_name}" \
+ id="${js_data_name}-${option}" value="${option}"${checked}>\
+ <span>${option}</span>\
+ </label>`;
+ });
+ output += "</div></div>";
+ } else {
+ // This is a toggle.
+ const checked = setting["default"] === true ? " checked" : "";
+ output += `<label class="toggle">\
+ <input type="checkbox" id="${js_data_name}"${checked}>\
+ <span class="slider"></span>\
+ <span class="label">${setting_name}</span>\
+ </label>`;
+ }
+ output += "</div>";
+ }
+ return output;
+ }
+
+ /**
+ * This function builds the "settings page" and returns the generated HTML element.
+ *
+ * @return {HTMLElement}
+ */
+ function buildSettingsPage() {
+ const themes = getVar("themes").split(",");
+ const settings = [
+ {
+ "name": "Use system theme",
+ "js_name": "use-system-theme",
+ "default": true,
+ },
+ {
+ "name": "Theme",
+ "js_name": "theme",
+ "default": "light",
+ "options": themes,
+ },
+ {
+ "name": "Preferred light theme",
+ "js_name": "preferred-light-theme",
+ "default": "light",
+ "options": themes,
+ },
+ {
+ "name": "Preferred dark theme",
+ "js_name": "preferred-dark-theme",
+ "default": "dark",
+ "options": themes,
+ },
+ {
+ "name": "Auto-hide item contents for large items",
+ "js_name": "auto-hide-large-items",
+ "default": true,
+ },
+ {
+ "name": "Auto-hide item methods' documentation",
+ "js_name": "auto-hide-method-docs",
+ "default": false,
+ },
+ {
+ "name": "Auto-hide trait implementation documentation",
+ "js_name": "auto-hide-trait-implementations",
+ "default": false,
+ },
+ {
+ "name": "Directly go to item in search if there is only one result",
+ "js_name": "go-to-only-result",
+ "default": false,
+ },
+ {
+ "name": "Show line numbers on code examples",
+ "js_name": "line-numbers",
+ "default": false,
+ },
+ {
+ "name": "Disable keyboard shortcuts",
+ "js_name": "disable-shortcuts",
+ "default": false,
+ },
+ ];
+
+ // Then we build the DOM.
+ const elementKind = isSettingsPage ? "section" : "div";
+ const innerHTML = `<div class="settings">${buildSettingsPageSections(settings)}</div>`;
+ const el = document.createElement(elementKind);
+ el.id = "settings";
+ el.className = "popover";
+ el.innerHTML = innerHTML;
+
+ if (isSettingsPage) {
+ document.getElementById(MAIN_ID).appendChild(el);
+ } else {
+ el.setAttribute("tabindex", "-1");
+ getSettingsButton().appendChild(el);
+ }
+ return el;
+ }
+
+ const settingsMenu = buildSettingsPage();
+
+ function displaySettings() {
+ settingsMenu.style.display = "";
+ }
+
+ function settingsBlurHandler(event) {
+ blurHandler(event, getSettingsButton(), window.hidePopoverMenus);
+ }
+
+ if (isSettingsPage) {
+ // We replace the existing "onclick" callback to do nothing if clicked.
+ getSettingsButton().onclick = function(event) {
+ event.preventDefault();
+ };
+ } else {
+ // We replace the existing "onclick" callback.
+ const settingsButton = getSettingsButton();
+ const settingsMenu = document.getElementById("settings");
+ settingsButton.onclick = function(event) {
+ if (elemIsInParent(event.target, settingsMenu)) {
+ return;
+ }
+ event.preventDefault();
+ const shouldDisplaySettings = settingsMenu.style.display === "none";
+
+ window.hidePopoverMenus();
+ if (shouldDisplaySettings) {
+ displaySettings();
+ }
+ };
+ settingsButton.onblur = settingsBlurHandler;
+ settingsButton.querySelector("a").onblur = settingsBlurHandler;
+ onEachLazy(settingsMenu.querySelectorAll("input"), el => {
+ el.onblur = settingsBlurHandler;
+ });
+ settingsMenu.onblur = settingsBlurHandler;
+ }
+
+ // We now wait a bit for the web browser to end re-computing the DOM...
+ setTimeout(() => {
+ setEvents(settingsMenu);
+ // The setting menu is already displayed if we're on the settings page.
+ if (!isSettingsPage) {
+ displaySettings();
+ }
+ removeClass(getSettingsButton(), "rotate");
+ }, 0);
+})();
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
new file mode 100644
index 000000000..c45d61429
--- /dev/null
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -0,0 +1,241 @@
+// From rust:
+/* global sourcesIndex */
+
+// Local js definitions:
+/* global addClass, getCurrentValue, onEachLazy, removeClass, browserSupportsHistoryApi */
+/* global updateLocalStorage */
+
+"use strict";
+
+(function() {
+
+const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
+let oldScrollPosition = 0;
+
+const NAME_OFFSET = 0;
+const DIRS_OFFSET = 1;
+const FILES_OFFSET = 2;
+
+function closeSidebarIfMobile() {
+ if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+ updateLocalStorage("source-sidebar-show", "false");
+ }
+}
+
+function createDirEntry(elem, parent, fullPath, hasFoundFile) {
+ const dirEntry = document.createElement("details");
+ const summary = document.createElement("summary");
+
+ dirEntry.className = "dir-entry";
+
+ fullPath += elem[NAME_OFFSET] + "/";
+
+ summary.innerText = elem[NAME_OFFSET];
+ dirEntry.appendChild(summary);
+
+ const folders = document.createElement("div");
+ folders.className = "folders";
+ if (elem[DIRS_OFFSET]) {
+ for (const dir of elem[DIRS_OFFSET]) {
+ if (createDirEntry(dir, folders, fullPath, false)) {
+ dirEntry.open = true;
+ hasFoundFile = true;
+ }
+ }
+ }
+ dirEntry.appendChild(folders);
+
+ const files = document.createElement("div");
+ files.className = "files";
+ if (elem[FILES_OFFSET]) {
+ for (const file_text of elem[FILES_OFFSET]) {
+ const file = document.createElement("a");
+ file.innerText = file_text;
+ file.href = rootPath + "src/" + fullPath + file_text + ".html";
+ file.addEventListener("click", closeSidebarIfMobile);
+ const w = window.location.href.split("#")[0];
+ if (!hasFoundFile && w === file.href) {
+ file.className = "selected";
+ dirEntry.open = true;
+ hasFoundFile = true;
+ }
+ files.appendChild(file);
+ }
+ }
+ dirEntry.appendChild(files);
+ parent.appendChild(dirEntry);
+ return hasFoundFile;
+}
+
+function toggleSidebar() {
+ const child = this.parentNode.children[0];
+ if (child.innerText === ">") {
+ if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+ // This is to keep the scroll position on mobile.
+ oldScrollPosition = window.scrollY;
+ document.body.style.position = "fixed";
+ document.body.style.top = `-${oldScrollPosition}px`;
+ }
+ addClass(document.documentElement, "source-sidebar-expanded");
+ child.innerText = "<";
+ updateLocalStorage("source-sidebar-show", "true");
+ } else {
+ if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+ // This is to keep the scroll position on mobile.
+ document.body.style.position = "";
+ document.body.style.top = "";
+ // The scroll position is lost when resetting the style, hence why we store it in
+ // `oldScroll`.
+ window.scrollTo(0, oldScrollPosition);
+ }
+ removeClass(document.documentElement, "source-sidebar-expanded");
+ child.innerText = ">";
+ updateLocalStorage("source-sidebar-show", "false");
+ }
+}
+
+function createSidebarToggle() {
+ const sidebarToggle = document.createElement("div");
+ sidebarToggle.id = "sidebar-toggle";
+
+ const inner = document.createElement("button");
+
+ if (getCurrentValue("source-sidebar-show") === "true") {
+ inner.innerText = "<";
+ } else {
+ inner.innerText = ">";
+ }
+ inner.onclick = toggleSidebar;
+
+ sidebarToggle.appendChild(inner);
+ return sidebarToggle;
+}
+
+// This function is called from "source-files.js", generated in `html/render/mod.rs`.
+// eslint-disable-next-line no-unused-vars
+function createSourceSidebar() {
+ const container = document.querySelector("nav.sidebar");
+
+ const sidebarToggle = createSidebarToggle();
+ container.insertBefore(sidebarToggle, container.firstChild);
+
+ const sidebar = document.createElement("div");
+ sidebar.id = "source-sidebar";
+
+ let hasFoundFile = false;
+
+ const title = document.createElement("div");
+ title.className = "title";
+ title.innerText = "Files";
+ sidebar.appendChild(title);
+ Object.keys(sourcesIndex).forEach(key => {
+ sourcesIndex[key][NAME_OFFSET] = key;
+ hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "",
+ hasFoundFile);
+ });
+
+ container.appendChild(sidebar);
+ // Focus on the current file in the source files sidebar.
+ const selected_elem = sidebar.getElementsByClassName("selected")[0];
+ if (typeof selected_elem !== "undefined") {
+ selected_elem.focus();
+ }
+}
+
+const lineNumbersRegex = /^#?(\d+)(?:-(\d+))?$/;
+
+function highlightSourceLines(match) {
+ if (typeof match === "undefined") {
+ match = window.location.hash.match(lineNumbersRegex);
+ }
+ if (!match) {
+ return;
+ }
+ let from = parseInt(match[1], 10);
+ let to = from;
+ if (typeof match[2] !== "undefined") {
+ to = parseInt(match[2], 10);
+ }
+ if (to < from) {
+ const tmp = to;
+ to = from;
+ from = tmp;
+ }
+ let elem = document.getElementById(from);
+ if (!elem) {
+ return;
+ }
+ const x = document.getElementById(from);
+ if (x) {
+ x.scrollIntoView();
+ }
+ onEachLazy(document.getElementsByClassName("line-numbers"), e => {
+ onEachLazy(e.getElementsByTagName("span"), i_e => {
+ removeClass(i_e, "line-highlighted");
+ });
+ });
+ for (let i = from; i <= to; ++i) {
+ elem = document.getElementById(i);
+ if (!elem) {
+ break;
+ }
+ addClass(elem, "line-highlighted");
+ }
+}
+
+const handleSourceHighlight = (function() {
+ let prev_line_id = 0;
+
+ const set_fragment = name => {
+ const x = window.scrollX,
+ y = window.scrollY;
+ if (browserSupportsHistoryApi()) {
+ history.replaceState(null, null, "#" + name);
+ highlightSourceLines();
+ } else {
+ location.replace("#" + name);
+ }
+ // Prevent jumps when selecting one or many lines
+ window.scrollTo(x, y);
+ };
+
+ return ev => {
+ let cur_line_id = parseInt(ev.target.id, 10);
+ // It can happen when clicking not on a line number span.
+ if (isNaN(cur_line_id)) {
+ return;
+ }
+ ev.preventDefault();
+
+ if (ev.shiftKey && prev_line_id) {
+ // Swap selection if needed
+ if (prev_line_id > cur_line_id) {
+ const tmp = prev_line_id;
+ prev_line_id = cur_line_id;
+ cur_line_id = tmp;
+ }
+
+ set_fragment(prev_line_id + "-" + cur_line_id);
+ } else {
+ prev_line_id = cur_line_id;
+
+ set_fragment(cur_line_id);
+ }
+ };
+}());
+
+window.addEventListener("hashchange", () => {
+ const match = window.location.hash.match(lineNumbersRegex);
+ if (match) {
+ return highlightSourceLines(match);
+ }
+});
+
+onEachLazy(document.getElementsByClassName("line-numbers"), el => {
+ el.addEventListener("click", handleSourceHighlight);
+});
+
+highlightSourceLines();
+
+window.createSourceSidebar = createSourceSidebar;
+})();
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
new file mode 100644
index 000000000..0c5389d45
--- /dev/null
+++ b/src/librustdoc/html/static/js/storage.js
@@ -0,0 +1,268 @@
+// storage.js is loaded in the `<head>` of all rustdoc pages and doesn't
+// use `async` or `defer`. That means it blocks further parsing and rendering
+// of the page: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script.
+// This makes it the correct place to act on settings that affect the display of
+// the page, so we don't see major layout changes during the load of the page.
+"use strict";
+
+const darkThemes = ["dark", "ayu"];
+window.currentTheme = document.getElementById("themeStyle");
+window.mainTheme = document.getElementById("mainThemeStyle");
+
+// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
+// If you update this line, then you also need to update the two media queries with the same
+// warning in rustdoc.css
+window.RUSTDOC_MOBILE_BREAKPOINT = 701;
+
+const settingsDataset = (function() {
+ const settingsElement = document.getElementById("default-settings");
+ if (settingsElement === null) {
+ return null;
+ }
+ const dataset = settingsElement.dataset;
+ if (dataset === undefined) {
+ return null;
+ }
+ return dataset;
+})();
+
+function getSettingValue(settingName) {
+ const current = getCurrentValue(settingName);
+ if (current !== null) {
+ return current;
+ }
+ if (settingsDataset !== null) {
+ // See the comment for `default_settings.into_iter()` etc. in
+ // `Options::from_matches` in `librustdoc/config.rs`.
+ const def = settingsDataset[settingName.replace(/-/g,"_")];
+ if (def !== undefined) {
+ return def;
+ }
+ }
+ return null;
+}
+
+const localStoredTheme = getSettingValue("theme");
+
+const savedHref = [];
+
+// eslint-disable-next-line no-unused-vars
+function hasClass(elem, className) {
+ return elem && elem.classList && elem.classList.contains(className);
+}
+
+// eslint-disable-next-line no-unused-vars
+function addClass(elem, className) {
+ if (!elem || !elem.classList) {
+ return;
+ }
+ elem.classList.add(className);
+}
+
+// eslint-disable-next-line no-unused-vars
+function removeClass(elem, className) {
+ if (!elem || !elem.classList) {
+ return;
+ }
+ elem.classList.remove(className);
+}
+
+/**
+ * Run a callback for every element of an Array.
+ * @param {Array<?>} arr - The array to iterate over
+ * @param {function(?)} func - The callback
+ * @param {boolean} [reversed] - Whether to iterate in reverse
+ */
+function onEach(arr, func, reversed) {
+ if (arr && arr.length > 0 && func) {
+ if (reversed) {
+ const length = arr.length;
+ for (let i = length - 1; i >= 0; --i) {
+ if (func(arr[i])) {
+ return true;
+ }
+ }
+ } else {
+ for (const elem of arr) {
+ if (func(elem)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Turn an HTMLCollection or a NodeList into an Array, then run a callback
+ * for every element. This is useful because iterating over an HTMLCollection
+ * or a "live" NodeList while modifying it can be very slow.
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection
+ * https://developer.mozilla.org/en-US/docs/Web/API/NodeList
+ * @param {NodeList<?>|HTMLCollection<?>} lazyArray - An array to iterate over
+ * @param {function(?)} func - The callback
+ * @param {boolean} [reversed] - Whether to iterate in reverse
+ */
+function onEachLazy(lazyArray, func, reversed) {
+ return onEach(
+ Array.prototype.slice.call(lazyArray),
+ func,
+ reversed);
+}
+
+function updateLocalStorage(name, value) {
+ try {
+ window.localStorage.setItem("rustdoc-" + name, value);
+ } catch (e) {
+ // localStorage is not accessible, do nothing
+ }
+}
+
+function getCurrentValue(name) {
+ try {
+ return window.localStorage.getItem("rustdoc-" + name);
+ } catch (e) {
+ return null;
+ }
+}
+
+function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
+ const newHref = mainStyleElem.href.replace(
+ /\/rustdoc([^/]*)\.css/, "/" + newTheme + "$1" + ".css");
+
+ // If this new value comes from a system setting or from the previously
+ // saved theme, no need to save it.
+ if (saveTheme) {
+ updateLocalStorage("theme", newTheme);
+ }
+
+ if (styleElem.href === newHref) {
+ return;
+ }
+
+ let found = false;
+ if (savedHref.length === 0) {
+ onEachLazy(document.getElementsByTagName("link"), el => {
+ savedHref.push(el.href);
+ });
+ }
+ onEach(savedHref, el => {
+ if (el === newHref) {
+ found = true;
+ return true;
+ }
+ });
+ if (found) {
+ styleElem.href = newHref;
+ }
+}
+
+// This function is called from "main.js".
+// eslint-disable-next-line no-unused-vars
+function useSystemTheme(value) {
+ if (value === undefined) {
+ value = true;
+ }
+
+ updateLocalStorage("use-system-theme", value);
+
+ // update the toggle if we're on the settings page
+ const toggle = document.getElementById("use-system-theme");
+ if (toggle && toggle instanceof HTMLInputElement) {
+ toggle.checked = value;
+ }
+}
+
+const updateSystemTheme = (function() {
+ if (!window.matchMedia) {
+ // fallback to the CSS computed value
+ return () => {
+ const cssTheme = getComputedStyle(document.documentElement)
+ .getPropertyValue("content");
+
+ switchTheme(
+ window.currentTheme,
+ window.mainTheme,
+ JSON.parse(cssTheme) || "light",
+ true
+ );
+ };
+ }
+
+ // only listen to (prefers-color-scheme: dark) because light is the default
+ const mql = window.matchMedia("(prefers-color-scheme: dark)");
+
+ function handlePreferenceChange(mql) {
+ const use = theme => {
+ switchTheme(window.currentTheme, window.mainTheme, theme, true);
+ };
+ // maybe the user has disabled the setting in the meantime!
+ if (getSettingValue("use-system-theme") !== "false") {
+ const lightTheme = getSettingValue("preferred-light-theme") || "light";
+ const darkTheme = getSettingValue("preferred-dark-theme") || "dark";
+
+ if (mql.matches) {
+ use(darkTheme);
+ } else {
+ // prefers a light theme, or has no preference
+ use(lightTheme);
+ }
+ // note: we save the theme so that it doesn't suddenly change when
+ // the user disables "use-system-theme" and reloads the page or
+ // navigates to another page
+ } else {
+ use(getSettingValue("theme"));
+ }
+ }
+
+ mql.addListener(handlePreferenceChange);
+
+ return () => {
+ handlePreferenceChange(mql);
+ };
+})();
+
+function switchToSavedTheme() {
+ switchTheme(
+ window.currentTheme,
+ window.mainTheme,
+ getSettingValue("theme") || "light",
+ false
+ );
+}
+
+if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
+ // update the preferred dark theme if the user is already using a dark theme
+ // See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732
+ if (getSettingValue("use-system-theme") === null
+ && getSettingValue("preferred-dark-theme") === null
+ && darkThemes.indexOf(localStoredTheme) >= 0) {
+ updateLocalStorage("preferred-dark-theme", localStoredTheme);
+ }
+
+ // call the function to initialize the theme at least once!
+ updateSystemTheme();
+} else {
+ switchToSavedTheme();
+}
+
+if (getSettingValue("source-sidebar-show") === "true") {
+ // At this point in page load, `document.body` is not available yet.
+ // Set a class on the `<html>` element instead.
+ addClass(document.documentElement, "source-sidebar-expanded");
+}
+
+// If we navigate away (for example to a settings page), and then use the back or
+// forward button to get back to a page, the theme may have changed in the meantime.
+// But scripts may not be re-loaded in such a case due to the bfcache
+// (https://web.dev/bfcache/). The "pageshow" event triggers on such navigations.
+// Use that opportunity to update the theme.
+// We use a setTimeout with a 0 timeout here to put the change on the event queue.
+// For some reason, if we try to change the theme while the `pageshow` event is
+// running, it sometimes fails to take effect. The problem manifests on Chrome,
+// specifically when talking to a remote website with no caching.
+window.addEventListener("pageshow", ev => {
+ if (ev.persisted) {
+ setTimeout(switchToSavedTheme, 0);
+ }
+});
diff --git a/src/librustdoc/html/static/scrape-examples-help.md b/src/librustdoc/html/static/scrape-examples-help.md
new file mode 100644
index 000000000..035b2e18b
--- /dev/null
+++ b/src/librustdoc/html/static/scrape-examples-help.md
@@ -0,0 +1,34 @@
+Rustdoc will automatically scrape examples of documented items from the `examples/` directory of a project. These examples will be included within the generated documentation for that item. For example, if your library contains a public function:
+
+```rust
+// src/lib.rs
+pub fn a_func() {}
+```
+
+And you have an example calling this function:
+
+```rust
+// examples/ex.rs
+fn main() {
+ a_crate::a_func();
+}
+```
+
+Then this code snippet will be included in the documentation for `a_func`.
+
+## How to read scraped examples
+
+Scraped examples are shown as blocks of code from a given file. The relevant item will be highlighted. If the file is larger than a couple lines, only a small window will be shown which you can expand by clicking &varr; in the top-right. If a file contains multiple instances of an item, you can use the &pr; and &sc; buttons to toggle through each instance.
+
+If there is more than one file that contains examples, then you should click "More examples" to see these examples.
+
+
+## How Rustdoc scrapes examples
+
+When you run `cargo doc`, Rustdoc will analyze all the crates that match Cargo's `--examples` filter for instances of items that occur in the crates being documented. Then Rustdoc will include the source code of these instances in the generated documentation.
+
+Rustdoc has a few techniques to ensure this doesn't overwhelm documentation readers, and that it doesn't blow up the page size:
+
+1. For a given item, a maximum of 5 examples are included in the page. The remaining examples are just links to source code.
+2. Only one example is shown by default, and the remaining examples are hidden behind a toggle.
+3. For a given file that contains examples, only the item containing the examples will be included in the generated documentation.