]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/static/main.js
Merge commit '9a0c32934ebe376128230aa8da3275697b2053e7' into sync_cg_clif-2021-03-05
[rust.git] / src / librustdoc / html / static / main.js
1 // Local js definitions:
2 /* global addClass, getSettingValue, hasClass */
3 /* global onEach, onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */
4 /* global hideThemeButtonState, showThemeButtonState */
5
6 if (!String.prototype.startsWith) {
7     String.prototype.startsWith = function(searchString, position) {
8         position = position || 0;
9         return this.indexOf(searchString, position) === position;
10     };
11 }
12 if (!String.prototype.endsWith) {
13     String.prototype.endsWith = function(suffix, length) {
14         var l = length || this.length;
15         return this.indexOf(suffix, l - suffix.length) !== -1;
16     };
17 }
18
19 if (!DOMTokenList.prototype.add) {
20     DOMTokenList.prototype.add = function(className) {
21         if (className && !hasClass(this, className)) {
22             if (this.className && this.className.length > 0) {
23                 this.className += " " + className;
24             } else {
25                 this.className = className;
26             }
27         }
28     };
29 }
30
31 if (!DOMTokenList.prototype.remove) {
32     DOMTokenList.prototype.remove = function(className) {
33         if (className && this.className) {
34             this.className = (" " + this.className + " ").replace(" " + className + " ", " ")
35                                                          .trim();
36         }
37     };
38 }
39
40 (function () {
41     var rustdocVars = document.getElementById("rustdoc-vars");
42     if (rustdocVars) {
43         window.rootPath = rustdocVars.attributes["data-root-path"].value;
44         window.currentCrate = rustdocVars.attributes["data-current-crate"].value;
45         window.searchJS = rustdocVars.attributes["data-search-js"].value;
46     }
47     var sidebarVars = document.getElementById("sidebar-vars");
48     if (sidebarVars) {
49         window.sidebarCurrent = {
50             name: sidebarVars.attributes["data-name"].value,
51             ty: sidebarVars.attributes["data-ty"].value,
52             relpath: sidebarVars.attributes["data-relpath"].value,
53         };
54     }
55 }());
56
57 // Gets the human-readable string for the virtual-key code of the
58 // given KeyboardEvent, ev.
59 //
60 // This function is meant as a polyfill for KeyboardEvent#key,
61 // since it is not supported in IE 11 or Chrome for Android. We also test for
62 // KeyboardEvent#keyCode because the handleShortcut handler is
63 // also registered for the keydown event, because Blink doesn't fire
64 // keypress on hitting the Escape key.
65 //
66 // So I guess you could say things are getting pretty interoperable.
67 function getVirtualKey(ev) {
68     if ("key" in ev && typeof ev.key != "undefined") {
69         return ev.key;
70     }
71
72     var c = ev.charCode || ev.keyCode;
73     if (c == 27) {
74         return "Escape";
75     }
76     return String.fromCharCode(c);
77 }
78
79 function getSearchInput() {
80     return document.getElementsByClassName("search-input")[0];
81 }
82
83 function getSearchElement() {
84     return document.getElementById("search");
85 }
86
87 function getThemesElement() {
88     return document.getElementById("theme-choices");
89 }
90
91 function getThemePickerElement() {
92     return document.getElementById("theme-picker");
93 }
94
95 // Returns the current URL without any query parameter or hash.
96 function getNakedUrl() {
97     return window.location.href.split("?")[0].split("#")[0];
98 }
99
100 // Sets the focus on the search bar at the top of the page
101 function focusSearchBar() {
102     getSearchInput().focus();
103 }
104
105 // Removes the focus from the search bar.
106 function defocusSearchBar() {
107     getSearchInput().blur();
108 }
109
110 (function() {
111     "use strict";
112
113     // This mapping table should match the discriminants of
114     // `rustdoc::html::item_type::ItemType` type in Rust.
115     var itemTypes = ["mod",
116                      "externcrate",
117                      "import",
118                      "struct",
119                      "enum",
120                      "fn",
121                      "type",
122                      "static",
123                      "trait",
124                      "impl",
125                      "tymethod",
126                      "method",
127                      "structfield",
128                      "variant",
129                      "macro",
130                      "primitive",
131                      "associatedtype",
132                      "constant",
133                      "associatedconstant",
134                      "union",
135                      "foreigntype",
136                      "keyword",
137                      "existential",
138                      "attr",
139                      "derive",
140                      "traitalias"];
141
142     var disableShortcuts = getSettingValue("disable-shortcuts") === "true";
143     var search_input = getSearchInput();
144     var searchTimeout = null;
145     var toggleAllDocsId = "toggle-all-docs";
146
147     // On the search screen, so you remain on the last tab you opened.
148     //
149     // 0 for "In Names"
150     // 1 for "In Parameters"
151     // 2 for "In Return Types"
152     var currentTab = 0;
153
154     var mouseMovedAfterSearch = true;
155
156     var titleBeforeSearch = document.title;
157     var searchTitle = null;
158
159     function clearInputTimeout() {
160         if (searchTimeout !== null) {
161             clearTimeout(searchTimeout);
162             searchTimeout = null;
163         }
164     }
165
166     function getPageId() {
167         if (window.location.hash) {
168             var tmp = window.location.hash.replace(/^#/, "");
169             if (tmp.length > 0) {
170                 return tmp;
171             }
172         }
173         return null;
174     }
175
176     function showSidebar() {
177         var elems = document.getElementsByClassName("sidebar-elems")[0];
178         if (elems) {
179             addClass(elems, "show-it");
180         }
181         var sidebar = document.getElementsByClassName("sidebar")[0];
182         if (sidebar) {
183             addClass(sidebar, "mobile");
184             var filler = document.getElementById("sidebar-filler");
185             if (!filler) {
186                 var div = document.createElement("div");
187                 div.id = "sidebar-filler";
188                 sidebar.appendChild(div);
189             }
190         }
191     }
192
193     function hideSidebar() {
194         var elems = document.getElementsByClassName("sidebar-elems")[0];
195         if (elems) {
196             removeClass(elems, "show-it");
197         }
198         var sidebar = document.getElementsByClassName("sidebar")[0];
199         removeClass(sidebar, "mobile");
200         var filler = document.getElementById("sidebar-filler");
201         if (filler) {
202             filler.remove();
203         }
204         document.getElementsByTagName("body")[0].style.marginTop = "";
205     }
206
207     function showSearchResults(search) {
208         if (search === null || typeof search === 'undefined') {
209             search = getSearchElement();
210         }
211         addClass(main, "hidden");
212         removeClass(search, "hidden");
213         mouseMovedAfterSearch = false;
214         document.title = searchTitle;
215     }
216
217     function hideSearchResults(search) {
218         if (search === null || typeof search === 'undefined') {
219             search = getSearchElement();
220         }
221         addClass(search, "hidden");
222         removeClass(main, "hidden");
223         document.title = titleBeforeSearch;
224         // We also remove the query parameter from the URL.
225         if (browserSupportsHistoryApi()) {
226             history.replaceState("", window.currentCrate + " - Rust",
227                 getNakedUrl() + window.location.hash);
228         }
229     }
230
231     // used for special search precedence
232     var TY_PRIMITIVE = itemTypes.indexOf("primitive");
233     var TY_KEYWORD = itemTypes.indexOf("keyword");
234
235     function getQueryStringParams() {
236         var params = {};
237         window.location.search.substring(1).split("&").
238             map(function(s) {
239                 var pair = s.split("=");
240                 params[decodeURIComponent(pair[0])] =
241                     typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]);
242             });
243         return params;
244     }
245
246     function browserSupportsHistoryApi() {
247         return window.history && typeof window.history.pushState === "function";
248     }
249
250     function isHidden(elem) {
251         return elem.offsetHeight === 0;
252     }
253
254     var main = document.getElementById("main");
255     var savedHash = "";
256
257     function handleHashes(ev) {
258         var elem;
259         var search = getSearchElement();
260         if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
261             // This block occurs when clicking on an element in the navbar while
262             // in a search.
263             hideSearchResults(search);
264             var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
265             if (browserSupportsHistoryApi()) {
266                 // `window.location.search`` contains all the query parameters, not just `search`.
267                 history.replaceState(hash, "",
268                     getNakedUrl() + window.location.search + "#" + hash);
269             }
270             elem = document.getElementById(hash);
271             if (elem) {
272                 elem.scrollIntoView();
273             }
274         }
275         // This part is used in case an element is not visible.
276         if (savedHash !== window.location.hash) {
277             savedHash = window.location.hash;
278             if (savedHash.length === 0) {
279                 return;
280             }
281             elem = document.getElementById(savedHash.slice(1)); // we remove the '#'
282             if (!elem || !isHidden(elem)) {
283                 return;
284             }
285             var parent = elem.parentNode;
286             if (parent && hasClass(parent, "impl-items")) {
287                 // In case this is a trait implementation item, we first need to toggle
288                 // the "Show hidden undocumented items".
289                 onEachLazy(parent.getElementsByClassName("collapsed"), function(e) {
290                     if (e.parentNode === parent) {
291                         // Only click on the toggle we're looking for.
292                         e.click();
293                         return true;
294                     }
295                 });
296                 if (isHidden(elem)) {
297                     // The whole parent is collapsed. We need to click on its toggle as well!
298                     if (hasClass(parent.lastElementChild, "collapse-toggle")) {
299                         parent.lastElementChild.click();
300                     }
301                 }
302             }
303         }
304     }
305
306     function highlightSourceLines(match, ev) {
307         if (typeof match === "undefined") {
308             // If we're in mobile mode, we should hide the sidebar in any case.
309             hideSidebar();
310             match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
311         }
312         if (!match) {
313             return;
314         }
315         var from = parseInt(match[1], 10);
316         var to = from;
317         if (typeof match[2] !== "undefined") {
318             to = parseInt(match[2], 10);
319         }
320         if (to < from) {
321             var tmp = to;
322             to = from;
323             from = tmp;
324         }
325         var elem = document.getElementById(from);
326         if (!elem) {
327             return;
328         }
329         if (!ev) {
330             var x = document.getElementById(from);
331             if (x) {
332                 x.scrollIntoView();
333             }
334         }
335         onEachLazy(document.getElementsByClassName("line-numbers"), function(e) {
336             onEachLazy(e.getElementsByTagName("span"), function(i_e) {
337                 removeClass(i_e, "line-highlighted");
338             });
339         });
340         for (var i = from; i <= to; ++i) {
341             elem = document.getElementById(i);
342             if (!elem) {
343                 break;
344             }
345             addClass(elem, "line-highlighted");
346         }
347     }
348
349     function onHashChange(ev) {
350         // If we're in mobile mode, we should hide the sidebar in any case.
351         hideSidebar();
352         var match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
353         if (match) {
354             return highlightSourceLines(match, ev);
355         }
356         handleHashes(ev);
357     }
358
359     function expandSection(id) {
360         var elem = document.getElementById(id);
361         if (elem && isHidden(elem)) {
362             var h3 = elem.parentNode.previousElementSibling;
363             if (h3 && h3.tagName !== "H3") {
364                 h3 = h3.previousElementSibling; // skip div.docblock
365             }
366
367             if (h3) {
368                 var collapses = h3.getElementsByClassName("collapse-toggle");
369                 if (collapses.length > 0) {
370                     // The element is not visible, we need to make it appear!
371                     collapseDocs(collapses[0], "show");
372                 }
373             }
374         }
375     }
376
377     function getHelpElement() {
378         buildHelperPopup();
379         return document.getElementById("help");
380     }
381
382     function displayHelp(display, ev, help) {
383         help = help ? help : getHelpElement();
384         if (display === true) {
385             if (hasClass(help, "hidden")) {
386                 ev.preventDefault();
387                 removeClass(help, "hidden");
388                 addClass(document.body, "blur");
389             }
390         } else if (hasClass(help, "hidden") === false) {
391             ev.preventDefault();
392             addClass(help, "hidden");
393             removeClass(document.body, "blur");
394         }
395     }
396
397     function handleEscape(ev) {
398         var help = getHelpElement();
399         var search = getSearchElement();
400         if (hasClass(help, "hidden") === false) {
401             displayHelp(false, ev, help);
402         } else if (hasClass(search, "hidden") === false) {
403             clearInputTimeout();
404             ev.preventDefault();
405             hideSearchResults(search);
406         }
407         defocusSearchBar();
408         hideThemeButtonState();
409     }
410
411     function handleShortcut(ev) {
412         // Don't interfere with browser shortcuts
413         if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts === true) {
414             return;
415         }
416
417         if (document.activeElement.tagName === "INPUT") {
418             switch (getVirtualKey(ev)) {
419             case "Escape":
420                 handleEscape(ev);
421                 break;
422             }
423         } else {
424             switch (getVirtualKey(ev)) {
425             case "Escape":
426                 handleEscape(ev);
427                 break;
428
429             case "s":
430             case "S":
431                 displayHelp(false, ev);
432                 ev.preventDefault();
433                 focusSearchBar();
434                 break;
435
436             case "+":
437             case "-":
438                 ev.preventDefault();
439                 toggleAllDocs();
440                 break;
441
442             case "?":
443                 displayHelp(true, ev);
444                 break;
445
446             case "t":
447             case "T":
448                 displayHelp(false, ev);
449                 ev.preventDefault();
450                 var themePicker = getThemePickerElement();
451                 themePicker.click();
452                 themePicker.focus();
453                 break;
454
455             default:
456                 var themePicker = getThemePickerElement();
457                 if (themePicker.parentNode.contains(ev.target)) {
458                     handleThemeKeyDown(ev);
459                 }
460             }
461         }
462     }
463
464     function handleThemeKeyDown(ev) {
465         var active = document.activeElement;
466         var themes = getThemesElement();
467         switch (getVirtualKey(ev)) {
468         case "ArrowUp":
469             ev.preventDefault();
470             if (active.previousElementSibling && ev.target.id !== "theme-picker") {
471                 active.previousElementSibling.focus();
472             } else {
473                 showThemeButtonState();
474                 themes.lastElementChild.focus();
475             }
476             break;
477         case "ArrowDown":
478             ev.preventDefault();
479             if (active.nextElementSibling && ev.target.id !== "theme-picker") {
480                 active.nextElementSibling.focus();
481             } else {
482                 showThemeButtonState();
483                 themes.firstElementChild.focus();
484             }
485             break;
486         case "Enter":
487         case "Return":
488         case "Space":
489             if (ev.target.id === "theme-picker" && themes.style.display === "none") {
490                 ev.preventDefault();
491                 showThemeButtonState();
492                 themes.firstElementChild.focus();
493             }
494             break;
495         case "Home":
496             ev.preventDefault();
497             themes.firstElementChild.focus();
498             break;
499         case "End":
500             ev.preventDefault();
501             themes.lastElementChild.focus();
502             break;
503         // The escape key is handled in handleEscape, not here,
504         // so that pressing escape will close the menu even if it isn't focused
505         }
506     }
507
508     function findParentElement(elem, tagName) {
509         do {
510             if (elem && elem.tagName === tagName) {
511                 return elem;
512             }
513             elem = elem.parentNode;
514         } while (elem);
515         return null;
516     }
517
518     document.addEventListener("keypress", handleShortcut);
519     document.addEventListener("keydown", handleShortcut);
520
521     document.addEventListener("mousemove", function() { mouseMovedAfterSearch = true; });
522
523     var handleSourceHighlight = (function() {
524         var prev_line_id = 0;
525
526         var set_fragment = function(name) {
527             var x = window.scrollX,
528                 y = window.scrollY;
529             if (browserSupportsHistoryApi()) {
530                 history.replaceState(null, null, "#" + name);
531                 highlightSourceLines();
532             } else {
533                 location.replace("#" + name);
534             }
535             // Prevent jumps when selecting one or many lines
536             window.scrollTo(x, y);
537         };
538
539         return function(ev) {
540             var cur_line_id = parseInt(ev.target.id, 10);
541             ev.preventDefault();
542
543             if (ev.shiftKey && prev_line_id) {
544                 // Swap selection if needed
545                 if (prev_line_id > cur_line_id) {
546                     var tmp = prev_line_id;
547                     prev_line_id = cur_line_id;
548                     cur_line_id = tmp;
549                 }
550
551                 set_fragment(prev_line_id + "-" + cur_line_id);
552             } else {
553                 prev_line_id = cur_line_id;
554
555                 set_fragment(cur_line_id);
556             }
557         };
558     }());
559
560     document.addEventListener("click", function(ev) {
561         if (hasClass(ev.target, "help-button")) {
562             displayHelp(true, ev);
563         } else if (hasClass(ev.target, "collapse-toggle")) {
564             collapseDocs(ev.target, "toggle");
565         } else if (hasClass(ev.target.parentNode, "collapse-toggle")) {
566             collapseDocs(ev.target.parentNode, "toggle");
567         } else if (ev.target.tagName === "SPAN" && hasClass(ev.target.parentNode, "line-numbers")) {
568             handleSourceHighlight(ev);
569         } else if (hasClass(getHelpElement(), "hidden") === false) {
570             var help = getHelpElement();
571             var is_inside_help_popup = ev.target !== help && help.contains(ev.target);
572             if (is_inside_help_popup === false) {
573                 addClass(help, "hidden");
574                 removeClass(document.body, "blur");
575             }
576         } else {
577             // Making a collapsed element visible on onhashchange seems
578             // too late
579             var a = findParentElement(ev.target, "A");
580             if (a && a.hash) {
581                 expandSection(a.hash.replace(/^#/, ""));
582             }
583         }
584     });
585
586     (function() {
587         var x = document.getElementsByClassName("version-selector");
588         if (x.length > 0) {
589             x[0].onchange = function() {
590                 var i, match,
591                     url = document.location.href,
592                     stripped = "",
593                     len = window.rootPath.match(/\.\.\//g).length + 1;
594
595                 for (i = 0; i < len; ++i) {
596                     match = url.match(/\/[^\/]*$/);
597                     if (i < len - 1) {
598                         stripped = match[0] + stripped;
599                     }
600                     url = url.substring(0, url.length - match[0].length);
601                 }
602
603                 var selectedVersion = document.getElementsByClassName("version-selector")[0].value;
604                 url += "/" + selectedVersion + stripped;
605
606                 document.location.href = url;
607             };
608         }
609     }());
610
611     /**
612      * A function to compute the Levenshtein distance between two strings
613      * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
614      * Full License can be found at http://creativecommons.org/licenses/by-sa/3.0/legalcode
615      * This code is an unmodified version of the code written by Marco de Wit
616      * and was found at http://stackoverflow.com/a/18514751/745719
617      */
618     var levenshtein_row2 = [];
619     function levenshtein(s1, s2) {
620         if (s1 === s2) {
621             return 0;
622         }
623         var s1_len = s1.length, s2_len = s2.length;
624         if (s1_len && s2_len) {
625             var i1 = 0, i2 = 0, a, b, c, c2, row = levenshtein_row2;
626             while (i1 < s1_len) {
627                 row[i1] = ++i1;
628             }
629             while (i2 < s2_len) {
630                 c2 = s2.charCodeAt(i2);
631                 a = i2;
632                 ++i2;
633                 b = i2;
634                 for (i1 = 0; i1 < s1_len; ++i1) {
635                     c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0);
636                     a = row[i1];
637                     b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
638                     row[i1] = b;
639                 }
640             }
641             return b;
642         }
643         return s1_len + s2_len;
644     }
645
646     window.initSearch = function(rawSearchIndex) {
647         var MAX_LEV_DISTANCE = 3;
648         var MAX_RESULTS = 200;
649         var GENERICS_DATA = 1;
650         var NAME = 0;
651         var INPUTS_DATA = 0;
652         var OUTPUT_DATA = 1;
653         var NO_TYPE_FILTER = -1;
654         var currentResults, index, searchIndex;
655         var ALIASES = {};
656         var params = getQueryStringParams();
657
658         // Populate search bar with query string search term when provided,
659         // but only if the input bar is empty. This avoid the obnoxious issue
660         // where you start trying to do a search, and the index loads, and
661         // suddenly your search is gone!
662         if (search_input.value === "") {
663             search_input.value = params.search || "";
664         }
665
666         /**
667          * Executes the query and builds an index of results
668          * @param  {[Object]} query      [The user query]
669          * @param  {[type]} searchWords  [The list of search words to query
670          *                                against]
671          * @param  {[type]} filterCrates [Crate to search in if defined]
672          * @return {[type]}              [A search index of results]
673          */
674         function execQuery(query, searchWords, filterCrates) {
675             function itemTypeFromName(typename) {
676                 for (var i = 0, len = itemTypes.length; i < len; ++i) {
677                     if (itemTypes[i] === typename) {
678                         return i;
679                     }
680                 }
681                 return NO_TYPE_FILTER;
682             }
683
684             var valLower = query.query.toLowerCase(),
685                 val = valLower,
686                 typeFilter = itemTypeFromName(query.type),
687                 results = {}, results_in_args = {}, results_returned = {},
688                 split = valLower.split("::");
689
690             split = split.filter(function(segment) { return segment !== ""; });
691
692             function transformResults(results, isType) {
693                 var out = [];
694                 for (var i = 0, len = results.length; i < len; ++i) {
695                     if (results[i].id > -1) {
696                         var obj = searchIndex[results[i].id];
697                         obj.lev = results[i].lev;
698                         if (isType !== true || obj.type) {
699                             var res = buildHrefAndPath(obj);
700                             obj.displayPath = pathSplitter(res[0]);
701                             obj.fullPath = obj.displayPath + obj.name;
702                             // To be sure than it some items aren't considered as duplicate.
703                             obj.fullPath += "|" + obj.ty;
704                             obj.href = res[1];
705                             out.push(obj);
706                             if (out.length >= MAX_RESULTS) {
707                                 break;
708                             }
709                         }
710                     }
711                 }
712                 return out;
713             }
714
715             function sortResults(results, isType) {
716                 var ar = [];
717                 for (var entry in results) {
718                     if (hasOwnProperty(results, entry)) {
719                         ar.push(results[entry]);
720                     }
721                 }
722                 results = ar;
723                 var i, len, result;
724                 for (i = 0, len = results.length; i < len; ++i) {
725                     result = results[i];
726                     result.word = searchWords[result.id];
727                     result.item = searchIndex[result.id] || {};
728                 }
729                 // if there are no results then return to default and fail
730                 if (results.length === 0) {
731                     return [];
732                 }
733
734                 results.sort(function(aaa, bbb) {
735                     var a, b;
736
737                     // sort by exact match with regard to the last word (mismatch goes later)
738                     a = (aaa.word !== val);
739                     b = (bbb.word !== val);
740                     if (a !== b) { return a - b; }
741
742                     // Sort by non levenshtein results and then levenshtein results by the distance
743                     // (less changes required to match means higher rankings)
744                     a = (aaa.lev);
745                     b = (bbb.lev);
746                     if (a !== b) { return a - b; }
747
748                     // sort by crate (non-current crate goes later)
749                     a = (aaa.item.crate !== window.currentCrate);
750                     b = (bbb.item.crate !== window.currentCrate);
751                     if (a !== b) { return a - b; }
752
753                     // sort by item name length (longer goes later)
754                     a = aaa.word.length;
755                     b = bbb.word.length;
756                     if (a !== b) { return a - b; }
757
758                     // sort by item name (lexicographically larger goes later)
759                     a = aaa.word;
760                     b = bbb.word;
761                     if (a !== b) { return (a > b ? +1 : -1); }
762
763                     // sort by index of keyword in item name (no literal occurrence goes later)
764                     a = (aaa.index < 0);
765                     b = (bbb.index < 0);
766                     if (a !== b) { return a - b; }
767                     // (later literal occurrence, if any, goes later)
768                     a = aaa.index;
769                     b = bbb.index;
770                     if (a !== b) { return a - b; }
771
772                     // special precedence for primitive and keyword pages
773                     if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) ||
774                         (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) {
775                         return -1;
776                     }
777                     if ((bbb.item.ty === TY_PRIMITIVE && aaa.item.ty !== TY_PRIMITIVE) ||
778                         (bbb.item.ty === TY_KEYWORD && aaa.item.ty !== TY_KEYWORD)) {
779                         return 1;
780                     }
781
782                     // sort by description (no description goes later)
783                     a = (aaa.item.desc === "");
784                     b = (bbb.item.desc === "");
785                     if (a !== b) { return a - b; }
786
787                     // sort by type (later occurrence in `itemTypes` goes later)
788                     a = aaa.item.ty;
789                     b = bbb.item.ty;
790                     if (a !== b) { return a - b; }
791
792                     // sort by path (lexicographically larger goes later)
793                     a = aaa.item.path;
794                     b = bbb.item.path;
795                     if (a !== b) { return (a > b ? +1 : -1); }
796
797                     // que sera, sera
798                     return 0;
799                 });
800
801                 for (i = 0, len = results.length; i < len; ++i) {
802                     var result = results[i];
803
804                     // this validation does not make sense when searching by types
805                     if (result.dontValidate) {
806                         continue;
807                     }
808                     var name = result.item.name.toLowerCase(),
809                         path = result.item.path.toLowerCase(),
810                         parent = result.item.parent;
811
812                     if (isType !== true &&
813                         validateResult(name, path, split, parent) === false)
814                     {
815                         result.id = -1;
816                     }
817                 }
818                 return transformResults(results);
819             }
820
821             function extractGenerics(val) {
822                 val = val.toLowerCase();
823                 if (val.indexOf("<") !== -1) {
824                     var values = val.substring(val.indexOf("<") + 1, val.lastIndexOf(">"));
825                     return {
826                         name: val.substring(0, val.indexOf("<")),
827                         generics: values.split(/\s*,\s*/),
828                     };
829                 }
830                 return {
831                     name: val,
832                     generics: [],
833                 };
834             }
835
836             function getObjectFromId(id) {
837                 if (typeof id === "number") {
838                     return searchIndex[id];
839                 }
840                 return {'name': id};
841             }
842
843             function checkGenerics(obj, val) {
844                 // The names match, but we need to be sure that all generics kinda
845                 // match as well.
846                 if (val.generics.length > 0) {
847                     if (obj.length > GENERICS_DATA &&
848                           obj[GENERICS_DATA].length >= val.generics.length) {
849                         var elems = obj[GENERICS_DATA].slice(0);
850                         var total = 0;
851                         var done = 0;
852                         // We need to find the type that matches the most to remove it in order
853                         // to move forward.
854                         var vlength = val.generics.length;
855                         for (var y = 0; y < vlength; ++y) {
856                             var lev = { pos: -1, lev: MAX_LEV_DISTANCE + 1};
857                             var firstGeneric = getObjectFromId(val.generics[y]).name;
858                             for (var x = 0, elength = elems.length; x < elength; ++x) {
859                                 var tmp_lev = levenshtein(getObjectFromId(elems[x]).name,
860                                                                           firstGeneric);
861                                 if (tmp_lev < lev.lev) {
862                                     lev.lev = tmp_lev;
863                                     lev.pos = x;
864                                 }
865                             }
866                             if (lev.pos !== -1) {
867                                 elems.splice(lev.pos, 1);
868                                 total += lev.lev;
869                                 done += 1;
870                             } else {
871                                 return MAX_LEV_DISTANCE + 1;
872                             }
873                         }
874                         return Math.ceil(total / done);
875                     }
876                 }
877                 return MAX_LEV_DISTANCE + 1;
878             }
879
880             // Check for type name and type generics (if any).
881             function checkType(obj, val, literalSearch) {
882                 var lev_distance = MAX_LEV_DISTANCE + 1;
883                 var len, x, y, e_len, firstGeneric;
884                 if (obj[NAME] === val.name) {
885                     if (literalSearch === true) {
886                         if (val.generics && val.generics.length !== 0) {
887                             if (obj.length > GENERICS_DATA &&
888                                   obj[GENERICS_DATA].length >= val.generics.length) {
889                                 var elems = obj[GENERICS_DATA].slice(0);
890                                 var allFound = true;
891
892                                 len = val.generics.length;
893                                 for (y = 0; allFound === true && y < len; ++y) {
894                                     allFound = false;
895                                     firstGeneric = getObjectFromId(val.generics[y]).name;
896                                     e_len = elems.length;
897                                     for (x = 0; allFound === false && x < e_len; ++x) {
898                                         allFound = getObjectFromId(elems[x]).name === firstGeneric;
899                                     }
900                                     if (allFound === true) {
901                                         elems.splice(x - 1, 1);
902                                     }
903                                 }
904                                 if (allFound === true) {
905                                     return true;
906                                 }
907                             } else {
908                                 return false;
909                             }
910                         }
911                         return true;
912                     }
913                     // If the type has generics but don't match, then it won't return at this point.
914                     // Otherwise, `checkGenerics` will return 0 and it'll return.
915                     if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
916                         var tmp_lev = checkGenerics(obj, val);
917                         if (tmp_lev <= MAX_LEV_DISTANCE) {
918                             return tmp_lev;
919                         }
920                     } else {
921                         return 0;
922                     }
923                 }
924                 // Names didn't match so let's check if one of the generic types could.
925                 if (literalSearch === true) {
926                      if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
927                         return obj[GENERICS_DATA].some(
928                             function(name) {
929                                 return name === val.name;
930                             });
931                     }
932                     return false;
933                 }
934                 lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
935                 if (lev_distance <= MAX_LEV_DISTANCE) {
936                     // The generics didn't match but the name kinda did so we give it
937                     // a levenshtein distance value that isn't *this* good so it goes
938                     // into the search results but not too high.
939                     lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
940                 } else if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
941                     // We can check if the type we're looking for is inside the generics!
942                     var olength = obj[GENERICS_DATA].length;
943                     for (x = 0; x < olength; ++x) {
944                         lev_distance = Math.min(levenshtein(obj[GENERICS_DATA][x], val.name),
945                                                 lev_distance);
946                     }
947                 }
948                 // Now whatever happens, the returned distance is "less good" so we should mark it
949                 // as such, and so we add 1 to the distance to make it "less good".
950                 return lev_distance + 1;
951             }
952
953             function findArg(obj, val, literalSearch, typeFilter) {
954                 var lev_distance = MAX_LEV_DISTANCE + 1;
955
956                 if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
957                     var length = obj.type[INPUTS_DATA].length;
958                     for (var i = 0; i < length; i++) {
959                         var tmp = obj.type[INPUTS_DATA][i];
960                         if (typePassesFilter(typeFilter, tmp[1]) === false) {
961                             continue;
962                         }
963                         tmp = checkType(tmp, val, literalSearch);
964                         if (literalSearch === true) {
965                             if (tmp === true) {
966                                 return true;
967                             }
968                             continue;
969                         }
970                         lev_distance = Math.min(tmp, lev_distance);
971                         if (lev_distance === 0) {
972                             return 0;
973                         }
974                     }
975                 }
976                 return literalSearch === true ? false : lev_distance;
977             }
978
979             function checkReturned(obj, val, literalSearch, typeFilter) {
980                 var lev_distance = MAX_LEV_DISTANCE + 1;
981
982                 if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
983                     var ret = obj.type[OUTPUT_DATA];
984                     if (typeof ret[0] === "string") {
985                         ret = [ret];
986                     }
987                     for (var x = 0, len = ret.length; x < len; ++x) {
988                         var tmp = ret[x];
989                         if (typePassesFilter(typeFilter, tmp[1]) === false) {
990                             continue;
991                         }
992                         tmp = checkType(tmp, val, literalSearch);
993                         if (literalSearch === true) {
994                             if (tmp === true) {
995                                 return true;
996                             }
997                             continue;
998                         }
999                         lev_distance = Math.min(tmp, lev_distance);
1000                         if (lev_distance === 0) {
1001                             return 0;
1002                         }
1003                     }
1004                 }
1005                 return literalSearch === true ? false : lev_distance;
1006             }
1007
1008             function checkPath(contains, lastElem, ty) {
1009                 if (contains.length === 0) {
1010                     return 0;
1011                 }
1012                 var ret_lev = MAX_LEV_DISTANCE + 1;
1013                 var path = ty.path.split("::");
1014
1015                 if (ty.parent && ty.parent.name) {
1016                     path.push(ty.parent.name.toLowerCase());
1017                 }
1018
1019                 var length = path.length;
1020                 var clength = contains.length;
1021                 if (clength > length) {
1022                     return MAX_LEV_DISTANCE + 1;
1023                 }
1024                 for (var i = 0; i < length; ++i) {
1025                     if (i + clength > length) {
1026                         break;
1027                     }
1028                     var lev_total = 0;
1029                     var aborted = false;
1030                     for (var x = 0; x < clength; ++x) {
1031                         var lev = levenshtein(path[i + x], contains[x]);
1032                         if (lev > MAX_LEV_DISTANCE) {
1033                             aborted = true;
1034                             break;
1035                         }
1036                         lev_total += lev;
1037                     }
1038                     if (aborted === false) {
1039                         ret_lev = Math.min(ret_lev, Math.round(lev_total / clength));
1040                     }
1041                 }
1042                 return ret_lev;
1043             }
1044
1045             function typePassesFilter(filter, type) {
1046                 // No filter
1047                 if (filter <= NO_TYPE_FILTER) return true;
1048
1049                 // Exact match
1050                 if (filter === type) return true;
1051
1052                 // Match related items
1053                 var name = itemTypes[type];
1054                 switch (itemTypes[filter]) {
1055                     case "constant":
1056                         return name === "associatedconstant";
1057                     case "fn":
1058                         return name === "method" || name === "tymethod";
1059                     case "type":
1060                         return name === "primitive" || name === "associatedtype";
1061                     case "trait":
1062                         return name === "traitalias";
1063                 }
1064
1065                 // No match
1066                 return false;
1067             }
1068
1069             function generateId(ty) {
1070                 if (ty.parent && ty.parent.name) {
1071                     return itemTypes[ty.ty] + ty.path + ty.parent.name + ty.name;
1072                 }
1073                 return itemTypes[ty.ty] + ty.path + ty.name;
1074             }
1075
1076             function createAliasFromItem(item) {
1077                 return {
1078                     crate: item.crate,
1079                     name: item.name,
1080                     path: item.path,
1081                     desc: item.desc,
1082                     ty: item.ty,
1083                     parent: item.parent,
1084                     type: item.type,
1085                     is_alias: true,
1086                 };
1087             }
1088
1089             function handleAliases(ret, query, filterCrates) {
1090                 // We separate aliases and crate aliases because we want to have current crate
1091                 // aliases to be before the others in the displayed results.
1092                 var aliases = [];
1093                 var crateAliases = [];
1094                 if (filterCrates !== undefined) {
1095                     if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
1096                         var query_aliases = ALIASES[filterCrates][query.search];
1097                         var len = query_aliases.length;
1098                         for (var i = 0; i < len; ++i) {
1099                             aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
1100                         }
1101                     }
1102                 } else {
1103                     Object.keys(ALIASES).forEach(function(crate) {
1104                         if (ALIASES[crate][query.search]) {
1105                             var pushTo = crate === window.currentCrate ? crateAliases : aliases;
1106                             var query_aliases = ALIASES[crate][query.search];
1107                             var len = query_aliases.length;
1108                             for (var i = 0; i < len; ++i) {
1109                                 pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
1110                             }
1111                         }
1112                     });
1113                 }
1114
1115                 var sortFunc = function(aaa, bbb) {
1116                     if (aaa.path < bbb.path) {
1117                         return 1;
1118                     } else if (aaa.path === bbb.path) {
1119                         return 0;
1120                     }
1121                     return -1;
1122                 };
1123                 crateAliases.sort(sortFunc);
1124                 aliases.sort(sortFunc);
1125
1126                 var pushFunc = function(alias) {
1127                     alias.alias = query.raw;
1128                     var res = buildHrefAndPath(alias);
1129                     alias.displayPath = pathSplitter(res[0]);
1130                     alias.fullPath = alias.displayPath + alias.name;
1131                     alias.href = res[1];
1132
1133                     ret.others.unshift(alias);
1134                     if (ret.others.length > MAX_RESULTS) {
1135                         ret.others.pop();
1136                     }
1137                 };
1138                 onEach(aliases, pushFunc);
1139                 onEach(crateAliases, pushFunc);
1140             }
1141
1142             // quoted values mean literal search
1143             var nSearchWords = searchWords.length;
1144             var i, it;
1145             var ty;
1146             var fullId;
1147             var returned;
1148             var in_args;
1149             var len;
1150             if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
1151                 val.charAt(val.length - 1) === val.charAt(0))
1152             {
1153                 val = extractGenerics(val.substr(1, val.length - 2));
1154                 for (i = 0; i < nSearchWords; ++i) {
1155                     if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
1156                         continue;
1157                     }
1158                     in_args = findArg(searchIndex[i], val, true, typeFilter);
1159                     returned = checkReturned(searchIndex[i], val, true, typeFilter);
1160                     ty = searchIndex[i];
1161                     fullId = generateId(ty);
1162
1163                     if (searchWords[i] === val.name
1164                         && typePassesFilter(typeFilter, searchIndex[i].ty)
1165                         && results[fullId] === undefined) {
1166                         results[fullId] = {
1167                             id: i,
1168                             index: -1,
1169                             dontValidate: true,
1170                         };
1171                     }
1172                     if (in_args === true && results_in_args[fullId] === undefined) {
1173                         results_in_args[fullId] = {
1174                             id: i,
1175                             index: -1,
1176                             dontValidate: true,
1177                         };
1178                     }
1179                     if (returned === true && results_returned[fullId] === undefined) {
1180                         results_returned[fullId] = {
1181                             id: i,
1182                             index: -1,
1183                             dontValidate: true,
1184                         };
1185                     }
1186                 }
1187                 query.inputs = [val];
1188                 query.output = val;
1189                 query.search = val;
1190             // searching by type
1191             } else if (val.search("->") > -1) {
1192                 var trimmer = function(s) { return s.trim(); };
1193                 var parts = val.split("->").map(trimmer);
1194                 var input = parts[0];
1195                 // sort inputs so that order does not matter
1196                 var inputs = input.split(",").map(trimmer).sort();
1197                 for (i = 0, len = inputs.length; i < len; ++i) {
1198                     inputs[i] = extractGenerics(inputs[i]);
1199                 }
1200                 var output = extractGenerics(parts[1]);
1201
1202                 for (i = 0; i < nSearchWords; ++i) {
1203                     if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
1204                         continue;
1205                     }
1206                     var type = searchIndex[i].type;
1207                     ty = searchIndex[i];
1208                     if (!type) {
1209                         continue;
1210                     }
1211                     fullId = generateId(ty);
1212
1213                     returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
1214                     if (output.name === "*" || returned === true) {
1215                         in_args = false;
1216                         var is_module = false;
1217
1218                         if (input === "*") {
1219                             is_module = true;
1220                         } else {
1221                             var allFound = true;
1222                             for (it = 0, len = inputs.length; allFound === true && it < len; it++) {
1223                                 allFound = checkType(type, inputs[it], true);
1224                             }
1225                             in_args = allFound;
1226                         }
1227                         if (in_args === true) {
1228                             results_in_args[fullId] = {
1229                                 id: i,
1230                                 index: -1,
1231                                 dontValidate: true,
1232                             };
1233                         }
1234                         if (returned === true) {
1235                             results_returned[fullId] = {
1236                                 id: i,
1237                                 index: -1,
1238                                 dontValidate: true,
1239                             };
1240                         }
1241                         if (is_module === true) {
1242                             results[fullId] = {
1243                                 id: i,
1244                                 index: -1,
1245                                 dontValidate: true,
1246                             };
1247                         }
1248                     }
1249                 }
1250                 query.inputs = inputs.map(function(input) {
1251                     return input.name;
1252                 });
1253                 query.output = output.name;
1254             } else {
1255                 query.inputs = [val];
1256                 query.output = val;
1257                 query.search = val;
1258                 // gather matching search results up to a certain maximum
1259                 val = val.replace(/\_/g, "");
1260
1261                 var valGenerics = extractGenerics(val);
1262
1263                 var paths = valLower.split("::");
1264                 var j;
1265                 for (j = 0, len = paths.length; j < len; ++j) {
1266                     if (paths[j] === "") {
1267                         paths.splice(j, 1);
1268                         j -= 1;
1269                     }
1270                 }
1271                 val = paths[paths.length - 1];
1272                 var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
1273
1274                 var lev;
1275                 for (j = 0; j < nSearchWords; ++j) {
1276                     ty = searchIndex[j];
1277                     if (!ty || (filterCrates !== undefined && ty.crate !== filterCrates)) {
1278                         continue;
1279                     }
1280                     var lev_add = 0;
1281                     if (paths.length > 1) {
1282                         lev = checkPath(contains, paths[paths.length - 1], ty);
1283                         if (lev > MAX_LEV_DISTANCE) {
1284                             continue;
1285                         } else if (lev > 0) {
1286                             lev_add = lev / 10;
1287                         }
1288                     }
1289
1290                     returned = MAX_LEV_DISTANCE + 1;
1291                     in_args = MAX_LEV_DISTANCE + 1;
1292                     var index = -1;
1293                     // we want lev results to go lower than others
1294                     lev = MAX_LEV_DISTANCE + 1;
1295                     fullId = generateId(ty);
1296
1297                     if (searchWords[j].indexOf(split[i]) > -1 ||
1298                         searchWords[j].indexOf(val) > -1 ||
1299                         searchWords[j].replace(/_/g, "").indexOf(val) > -1)
1300                     {
1301                         // filter type: ... queries
1302                         if (typePassesFilter(typeFilter, ty.ty) && results[fullId] === undefined) {
1303                             index = searchWords[j].replace(/_/g, "").indexOf(val);
1304                         }
1305                     }
1306                     if ((lev = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
1307                         if (typePassesFilter(typeFilter, ty.ty) === false) {
1308                             lev = MAX_LEV_DISTANCE + 1;
1309                         } else {
1310                             lev += 1;
1311                         }
1312                     }
1313                     in_args = findArg(ty, valGenerics, false, typeFilter);
1314                     returned = checkReturned(ty, valGenerics, false, typeFilter);
1315
1316                     lev += lev_add;
1317                     if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
1318                         if (val.length < 6) {
1319                             lev -= 1;
1320                         } else {
1321                             lev = 0;
1322                         }
1323                     }
1324                     if (in_args <= MAX_LEV_DISTANCE) {
1325                         if (results_in_args[fullId] === undefined) {
1326                             results_in_args[fullId] = {
1327                                 id: j,
1328                                 index: index,
1329                                 lev: in_args,
1330                             };
1331                         }
1332                         results_in_args[fullId].lev =
1333                             Math.min(results_in_args[fullId].lev, in_args);
1334                     }
1335                     if (returned <= MAX_LEV_DISTANCE) {
1336                         if (results_returned[fullId] === undefined) {
1337                             results_returned[fullId] = {
1338                                 id: j,
1339                                 index: index,
1340                                 lev: returned,
1341                             };
1342                         }
1343                         results_returned[fullId].lev =
1344                             Math.min(results_returned[fullId].lev, returned);
1345                     }
1346                     if (index !== -1 || lev <= MAX_LEV_DISTANCE) {
1347                         if (index !== -1 && paths.length < 2) {
1348                             lev = 0;
1349                         }
1350                         if (results[fullId] === undefined) {
1351                             results[fullId] = {
1352                                 id: j,
1353                                 index: index,
1354                                 lev: lev,
1355                             };
1356                         }
1357                         results[fullId].lev = Math.min(results[fullId].lev, lev);
1358                     }
1359                 }
1360             }
1361
1362             var ret = {
1363                 "in_args": sortResults(results_in_args, true),
1364                 "returned": sortResults(results_returned, true),
1365                 "others": sortResults(results),
1366             };
1367             handleAliases(ret, query, filterCrates);
1368             return ret;
1369         }
1370
1371         /**
1372          * Validate performs the following boolean logic. For example:
1373          * "File::open" will give IF A PARENT EXISTS => ("file" && "open")
1374          * exists in (name || path || parent) OR => ("file" && "open") exists in
1375          * (name || path )
1376          *
1377          * This could be written functionally, but I wanted to minimise
1378          * functions on stack.
1379          *
1380          * @param  {[string]} name   [The name of the result]
1381          * @param  {[string]} path   [The path of the result]
1382          * @param  {[string]} keys   [The keys to be used (["file", "open"])]
1383          * @param  {[object]} parent [The parent of the result]
1384          * @return {[boolean]}       [Whether the result is valid or not]
1385          */
1386         function validateResult(name, path, keys, parent) {
1387             for (var i = 0, len = keys.length; i < len; ++i) {
1388                 // each check is for validation so we negate the conditions and invalidate
1389                 if (!(
1390                     // check for an exact name match
1391                     name.indexOf(keys[i]) > -1 ||
1392                     // then an exact path match
1393                     path.indexOf(keys[i]) > -1 ||
1394                     // next if there is a parent, check for exact parent match
1395                     (parent !== undefined && parent.name !== undefined &&
1396                         parent.name.toLowerCase().indexOf(keys[i]) > -1) ||
1397                     // lastly check to see if the name was a levenshtein match
1398                     levenshtein(name, keys[i]) <= MAX_LEV_DISTANCE)) {
1399                     return false;
1400                 }
1401             }
1402             return true;
1403         }
1404
1405         function getQuery(raw) {
1406             var matches, type, query;
1407             query = raw;
1408
1409             matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
1410             if (matches) {
1411                 type = matches[1].replace(/^const$/, "constant");
1412                 query = query.substring(matches[0].length);
1413             }
1414
1415             return {
1416                 raw: raw,
1417                 query: query,
1418                 type: type,
1419                 id: query + type
1420             };
1421         }
1422
1423         function initSearchNav() {
1424             var hoverTimeout;
1425
1426             var click_func = function(e) {
1427                 var el = e.target;
1428                 // to retrieve the real "owner" of the event.
1429                 while (el.tagName !== "TR") {
1430                     el = el.parentNode;
1431                 }
1432                 var dst = e.target.getElementsByTagName("a");
1433                 if (dst.length < 1) {
1434                     return;
1435                 }
1436                 dst = dst[0];
1437                 if (window.location.pathname === dst.pathname) {
1438                     hideSearchResults();
1439                     document.location.href = dst.href;
1440                 }
1441             };
1442             var mouseover_func = function(e) {
1443                 if (mouseMovedAfterSearch) {
1444                     var el = e.target;
1445                     // to retrieve the real "owner" of the event.
1446                     while (el.tagName !== "TR") {
1447                         el = el.parentNode;
1448                     }
1449                     clearTimeout(hoverTimeout);
1450                     hoverTimeout = setTimeout(function() {
1451                         onEachLazy(document.getElementsByClassName("search-results"), function(e) {
1452                             onEachLazy(e.getElementsByClassName("result"), function(i_e) {
1453                                 removeClass(i_e, "highlighted");
1454                             });
1455                         });
1456                         addClass(el, "highlighted");
1457                     }, 20);
1458                 }
1459             };
1460             onEachLazy(document.getElementsByClassName("search-results"), function(e) {
1461                 onEachLazy(e.getElementsByClassName("result"), function(i_e) {
1462                     i_e.onclick = click_func;
1463                     i_e.onmouseover = mouseover_func;
1464                 });
1465             });
1466
1467             search_input.onkeydown = function(e) {
1468                 // "actives" references the currently highlighted item in each search tab.
1469                 // Each array in "actives" represents a tab.
1470                 var actives = [[], [], []];
1471                 // "current" is used to know which tab we're looking into.
1472                 var current = 0;
1473                 onEachLazy(document.getElementById("results").childNodes, function(e) {
1474                     onEachLazy(e.getElementsByClassName("highlighted"), function(h_e) {
1475                         actives[current].push(h_e);
1476                     });
1477                     current += 1;
1478                 });
1479
1480                 if (e.which === 38) { // up
1481                     if (e.ctrlKey) { // Going through result tabs.
1482                         printTab(currentTab > 0 ? currentTab - 1 : 2);
1483                     } else {
1484                         if (!actives[currentTab].length ||
1485                             !actives[currentTab][0].previousElementSibling) {
1486                             return;
1487                         }
1488                         addClass(actives[currentTab][0].previousElementSibling, "highlighted");
1489                         removeClass(actives[currentTab][0], "highlighted");
1490                     }
1491                     e.preventDefault();
1492                 } else if (e.which === 40) { // down
1493                     if (e.ctrlKey) { // Going through result tabs.
1494                         printTab(currentTab > 1 ? 0 : currentTab + 1);
1495                     } else if (!actives[currentTab].length) {
1496                         var results = document.getElementById("results").childNodes;
1497                         if (results.length > 0) {
1498                             var res = results[currentTab].getElementsByClassName("result");
1499                             if (res.length > 0) {
1500                                 addClass(res[0], "highlighted");
1501                             }
1502                         }
1503                     } else if (actives[currentTab][0].nextElementSibling) {
1504                         addClass(actives[currentTab][0].nextElementSibling, "highlighted");
1505                         removeClass(actives[currentTab][0], "highlighted");
1506                     }
1507                     e.preventDefault();
1508                 } else if (e.which === 13) { // return
1509                     if (actives[currentTab].length) {
1510                         document.location.href =
1511                             actives[currentTab][0].getElementsByTagName("a")[0].href;
1512                     }
1513                 } else if (e.which === 16) { // shift
1514                     // Does nothing, it's just to avoid losing "focus" on the highlighted element.
1515                 } else if (actives[currentTab].length > 0) {
1516                     removeClass(actives[currentTab][0], "highlighted");
1517                 }
1518             };
1519         }
1520
1521         function buildHrefAndPath(item) {
1522             var displayPath;
1523             var href;
1524             var type = itemTypes[item.ty];
1525             var name = item.name;
1526             var path = item.path;
1527
1528             if (type === "mod") {
1529                 displayPath = path + "::";
1530                 href = window.rootPath + path.replace(/::/g, "/") + "/" +
1531                        name + "/index.html";
1532             } else if (type === "primitive" || type === "keyword") {
1533                 displayPath = "";
1534                 href = window.rootPath + path.replace(/::/g, "/") +
1535                        "/" + type + "." + name + ".html";
1536             } else if (type === "externcrate") {
1537                 displayPath = "";
1538                 href = window.rootPath + name + "/index.html";
1539             } else if (item.parent !== undefined) {
1540                 var myparent = item.parent;
1541                 var anchor = "#" + type + "." + name;
1542                 var parentType = itemTypes[myparent.ty];
1543                 var pageType = parentType;
1544                 var pageName = myparent.name;
1545
1546                 if (parentType === "primitive") {
1547                     displayPath = myparent.name + "::";
1548                 } else if (type === "structfield" && parentType === "variant") {
1549                     // Structfields belonging to variants are special: the
1550                     // final path element is the enum name.
1551                     var splitPath = item.path.split("::");
1552                     var enumName = splitPath.pop();
1553                     path = splitPath.join("::");
1554                     displayPath = path + "::" + enumName + "::" + myparent.name + "::";
1555                     anchor = "#variant." + myparent.name + ".field." + name;
1556                     pageType = "enum";
1557                     pageName = enumName;
1558                 } else {
1559                     displayPath = path + "::" + myparent.name + "::";
1560                 }
1561                 href = window.rootPath + path.replace(/::/g, "/") +
1562                        "/" + pageType +
1563                        "." + pageName +
1564                        ".html" + anchor;
1565             } else {
1566                 displayPath = item.path + "::";
1567                 href = window.rootPath + item.path.replace(/::/g, "/") +
1568                        "/" + type + "." + name + ".html";
1569             }
1570             return [displayPath, href];
1571         }
1572
1573         function escape(content) {
1574             var h1 = document.createElement("h1");
1575             h1.textContent = content;
1576             return h1.innerHTML;
1577         }
1578
1579         function pathSplitter(path) {
1580             var tmp = "<span>" + path.replace(/::/g, "::</span><span>");
1581             if (tmp.endsWith("<span>")) {
1582                 return tmp.slice(0, tmp.length - 6);
1583             }
1584             return tmp;
1585         }
1586
1587         function addTab(array, query, display) {
1588             var extraStyle = "";
1589             if (display === false) {
1590                 extraStyle = " style=\"display: none;\"";
1591             }
1592
1593             var output = "";
1594             var duplicates = {};
1595             var length = 0;
1596             if (array.length > 0) {
1597                 output = "<table class=\"search-results\"" + extraStyle + ">";
1598
1599                 array.forEach(function(item) {
1600                     var name, type;
1601
1602                     name = item.name;
1603                     type = itemTypes[item.ty];
1604
1605                     if (item.is_alias !== true) {
1606                         if (duplicates[item.fullPath]) {
1607                             return;
1608                         }
1609                         duplicates[item.fullPath] = true;
1610                     }
1611                     length += 1;
1612
1613                     output += "<tr class=\"" + type + " result\"><td>" +
1614                               "<a href=\"" + item.href + "\">" +
1615                               (item.is_alias === true ?
1616                                ("<span class=\"alias\"><b>" + item.alias + " </b></span><span " +
1617                                   "class=\"grey\"><i>&nbsp;- see&nbsp;</i></span>") : "") +
1618                               item.displayPath + "<span class=\"" + type + "\">" +
1619                               name + "</span></a></td><td>" +
1620                               "<a href=\"" + item.href + "\">" +
1621                               "<span class=\"desc\">" + item.desc +
1622                               "&nbsp;</span></a></td></tr>";
1623                 });
1624                 output += "</table>";
1625             } else {
1626                 output = "<div class=\"search-failed\"" + extraStyle + ">No results :(<br/>" +
1627                     "Try on <a href=\"https://duckduckgo.com/?q=" +
1628                     encodeURIComponent("rust " + query.query) +
1629                     "\">DuckDuckGo</a>?<br/><br/>" +
1630                     "Or try looking in one of these:<ul><li>The <a " +
1631                     "href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
1632                     " for technical details about the language.</li><li><a " +
1633                     "href=\"https://doc.rust-lang.org/rust-by-example/index.html\">Rust By " +
1634                     "Example</a> for expository code examples.</a></li><li>The <a " +
1635                     "href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " +
1636                     "introductions to language features and the language itself.</li><li><a " +
1637                     "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
1638                     " <a href=\"https://crates.io/\">crates.io</a>.</li></ul></div>";
1639             }
1640             return [output, length];
1641         }
1642
1643         function makeTabHeader(tabNb, text, nbElems) {
1644             if (currentTab === tabNb) {
1645                 return "<button class=\"selected\">" + text +
1646                        " <div class=\"count\">(" + nbElems + ")</div></button>";
1647             }
1648             return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
1649         }
1650
1651         function showResults(results) {
1652             var search = getSearchElement();
1653             if (results.others.length === 1
1654                 && getSettingValue("go-to-only-result") === "true"
1655                 // By default, the search DOM element is "empty" (meaning it has no children not
1656                 // text content). Once a search has been run, it won't be empty, even if you press
1657                 // ESC or empty the search input (which also "cancels" the search).
1658                 && (!search.firstChild || search.firstChild.innerText !== getSearchLoadingText()))
1659             {
1660                 var elem = document.createElement("a");
1661                 elem.href = results.others[0].href;
1662                 elem.style.display = "none";
1663                 // For firefox, we need the element to be in the DOM so it can be clicked.
1664                 document.body.appendChild(elem);
1665                 elem.click();
1666                 return;
1667             }
1668             var query = getQuery(search_input.value);
1669
1670             currentResults = query.id;
1671
1672             var ret_others = addTab(results.others, query);
1673             var ret_in_args = addTab(results.in_args, query, false);
1674             var ret_returned = addTab(results.returned, query, false);
1675
1676             // Navigate to the relevant tab if the current tab is empty, like in case users search
1677             // for "-> String". If they had selected another tab previously, they have to click on
1678             // it again.
1679             if ((currentTab === 0 && ret_others[1] === 0) ||
1680                     (currentTab === 1 && ret_in_args[1] === 0) ||
1681                     (currentTab === 2 && ret_returned[1] === 0)) {
1682                 if (ret_others[1] !== 0) {
1683                     currentTab = 0;
1684                 } else if (ret_in_args[1] !== 0) {
1685                     currentTab = 1;
1686                 } else if (ret_returned[1] !== 0) {
1687                     currentTab = 2;
1688                 }
1689             }
1690
1691             var output = "<h1>Results for " + escape(query.query) +
1692                 (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
1693                 "<div id=\"titles\">" +
1694                 makeTabHeader(0, "In Names", ret_others[1]) +
1695                 makeTabHeader(1, "In Parameters", ret_in_args[1]) +
1696                 makeTabHeader(2, "In Return Types", ret_returned[1]) +
1697                 "</div><div id=\"results\">" +
1698                 ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
1699
1700             search.innerHTML = output;
1701             showSearchResults(search);
1702             initSearchNav();
1703             var elems = document.getElementById("titles").childNodes;
1704             elems[0].onclick = function() { printTab(0); };
1705             elems[1].onclick = function() { printTab(1); };
1706             elems[2].onclick = function() { printTab(2); };
1707             printTab(currentTab);
1708         }
1709
1710         function execSearch(query, searchWords, filterCrates) {
1711             function getSmallest(arrays, positions, notDuplicates) {
1712                 var start = null;
1713
1714                 for (var it = 0, len = positions.length; it < len; ++it) {
1715                     if (arrays[it].length > positions[it] &&
1716                         (start === null || start > arrays[it][positions[it]].lev) &&
1717                         !notDuplicates[arrays[it][positions[it]].fullPath]) {
1718                         start = arrays[it][positions[it]].lev;
1719                     }
1720                 }
1721                 return start;
1722             }
1723
1724             function mergeArrays(arrays) {
1725                 var ret = [];
1726                 var positions = [];
1727                 var notDuplicates = {};
1728
1729                 for (var x = 0, arrays_len = arrays.length; x < arrays_len; ++x) {
1730                     positions.push(0);
1731                 }
1732                 while (ret.length < MAX_RESULTS) {
1733                     var smallest = getSmallest(arrays, positions, notDuplicates);
1734
1735                     if (smallest === null) {
1736                         break;
1737                     }
1738                     for (x = 0; x < arrays_len && ret.length < MAX_RESULTS; ++x) {
1739                         if (arrays[x].length > positions[x] &&
1740                                 arrays[x][positions[x]].lev === smallest &&
1741                                 !notDuplicates[arrays[x][positions[x]].fullPath]) {
1742                             ret.push(arrays[x][positions[x]]);
1743                             notDuplicates[arrays[x][positions[x]].fullPath] = true;
1744                             positions[x] += 1;
1745                         }
1746                     }
1747                 }
1748                 return ret;
1749             }
1750
1751             var queries = query.raw.split(",");
1752             var results = {
1753                 "in_args": [],
1754                 "returned": [],
1755                 "others": [],
1756             };
1757
1758             for (var i = 0, len = queries.length; i < len; ++i) {
1759                 query = queries[i].trim();
1760                 if (query.length !== 0) {
1761                     var tmp = execQuery(getQuery(query), searchWords, filterCrates);
1762
1763                     results.in_args.push(tmp.in_args);
1764                     results.returned.push(tmp.returned);
1765                     results.others.push(tmp.others);
1766                 }
1767             }
1768             if (queries.length > 1) {
1769                 return {
1770                     "in_args": mergeArrays(results.in_args),
1771                     "returned": mergeArrays(results.returned),
1772                     "others": mergeArrays(results.others),
1773                 };
1774             }
1775             return {
1776                 "in_args": results.in_args[0],
1777                 "returned": results.returned[0],
1778                 "others": results.others[0],
1779             };
1780         }
1781
1782         function getFilterCrates() {
1783             var elem = document.getElementById("crate-search");
1784
1785             if (elem && elem.value !== "All crates" && hasOwnProperty(rawSearchIndex, elem.value)) {
1786                 return elem.value;
1787             }
1788             return undefined;
1789         }
1790
1791         function search(e, forced) {
1792             var params = getQueryStringParams();
1793             var query = getQuery(search_input.value.trim());
1794
1795             if (e) {
1796                 e.preventDefault();
1797             }
1798
1799             if (query.query.length === 0) {
1800                 return;
1801             }
1802             if (forced !== true && query.id === currentResults) {
1803                 if (query.query.length > 0) {
1804                     putBackSearch(search_input);
1805                 }
1806                 return;
1807             }
1808
1809             // Update document title to maintain a meaningful browser history
1810             searchTitle = "Results for " + query.query + " - Rust";
1811
1812             // Because searching is incremental by character, only the most
1813             // recent search query is added to the browser history.
1814             if (browserSupportsHistoryApi()) {
1815                 var newURL = getNakedUrl() + "?search=" + encodeURIComponent(query.raw) +
1816                     window.location.hash;
1817                 if (!history.state && !params.search) {
1818                     history.pushState(query, "", newURL);
1819                 } else {
1820                     history.replaceState(query, "", newURL);
1821                 }
1822             }
1823
1824             var filterCrates = getFilterCrates();
1825             showResults(execSearch(query, index, filterCrates));
1826         }
1827
1828         function buildIndex(rawSearchIndex) {
1829             searchIndex = [];
1830             var searchWords = [];
1831             var i;
1832             var currentIndex = 0;
1833
1834             for (var crate in rawSearchIndex) {
1835                 if (!hasOwnProperty(rawSearchIndex, crate)) { continue; }
1836
1837                 var crateSize = 0;
1838
1839                 searchWords.push(crate);
1840                 searchIndex.push({
1841                     crate: crate,
1842                     ty: 1, // == ExternCrate
1843                     name: crate,
1844                     path: "",
1845                     desc: rawSearchIndex[crate].doc,
1846                     type: null,
1847                 });
1848                 currentIndex += 1;
1849
1850                 // an array of [(Number) item type,
1851                 //              (String) name,
1852                 //              (String) full path or empty string for previous path,
1853                 //              (String) description,
1854                 //              (Number | null) the parent path index to `paths`]
1855                 //              (Object | null) the type of the function (if any)
1856                 var items = rawSearchIndex[crate].i;
1857                 // an array of [(Number) item type,
1858                 //              (String) name]
1859                 var paths = rawSearchIndex[crate].p;
1860                 // a array of [(String) alias name
1861                 //             [Number] index to items]
1862                 var aliases = rawSearchIndex[crate].a;
1863
1864                 // convert `rawPaths` entries into object form
1865                 var len = paths.length;
1866                 for (i = 0; i < len; ++i) {
1867                     paths[i] = {ty: paths[i][0], name: paths[i][1]};
1868                 }
1869
1870                 // convert `items` into an object form, and construct word indices.
1871                 //
1872                 // before any analysis is performed lets gather the search terms to
1873                 // search against apart from the rest of the data.  This is a quick
1874                 // operation that is cached for the life of the page state so that
1875                 // all other search operations have access to this cached data for
1876                 // faster analysis operations
1877                 len = items.length;
1878                 var lastPath = "";
1879                 for (i = 0; i < len; ++i) {
1880                     var rawRow = items[i];
1881                     if (!rawRow[2]) {
1882                         rawRow[2] = lastPath;
1883                     }
1884                     var row = {
1885                         crate: crate,
1886                         ty: rawRow[0],
1887                         name: rawRow[1],
1888                         path: rawRow[2],
1889                         desc: rawRow[3],
1890                         parent: paths[rawRow[4]],
1891                         type: rawRow[5],
1892                     };
1893                     searchIndex.push(row);
1894                     if (typeof row.name === "string") {
1895                         var word = row.name.toLowerCase();
1896                         searchWords.push(word);
1897                     } else {
1898                         searchWords.push("");
1899                     }
1900                     lastPath = row.path;
1901                     crateSize += 1;
1902                 }
1903
1904                 if (aliases) {
1905                     ALIASES[crate] = {};
1906                     var j, local_aliases;
1907                     for (var alias_name in aliases) {
1908                         if (!aliases.hasOwnProperty(alias_name)) { continue; }
1909
1910                         if (!ALIASES[crate].hasOwnProperty(alias_name)) {
1911                             ALIASES[crate][alias_name] = [];
1912                         }
1913                         local_aliases = aliases[alias_name];
1914                         for (j = 0, len = local_aliases.length; j < len; ++j) {
1915                             ALIASES[crate][alias_name].push(local_aliases[j] + currentIndex);
1916                         }
1917                     }
1918                 }
1919                 currentIndex += crateSize;
1920             }
1921             return searchWords;
1922         }
1923
1924         function registerSearchEvents() {
1925             var searchAfter500ms = function() {
1926                 clearInputTimeout();
1927                 if (search_input.value.length === 0) {
1928                     if (browserSupportsHistoryApi()) {
1929                         history.replaceState("", window.currentCrate + " - Rust",
1930                             getNakedUrl() + window.location.hash);
1931                     }
1932                     hideSearchResults();
1933                 } else {
1934                     searchTimeout = setTimeout(search, 500);
1935                 }
1936             };
1937             search_input.onkeyup = searchAfter500ms;
1938             search_input.oninput = searchAfter500ms;
1939             document.getElementsByClassName("search-form")[0].onsubmit = function(e) {
1940                 e.preventDefault();
1941                 clearInputTimeout();
1942                 search();
1943             };
1944             search_input.onchange = function(e) {
1945                 if (e.target !== document.activeElement) {
1946                     // To prevent doing anything when it's from a blur event.
1947                     return;
1948                 }
1949                 // Do NOT e.preventDefault() here. It will prevent pasting.
1950                 clearInputTimeout();
1951                 // zero-timeout necessary here because at the time of event handler execution the
1952                 // pasted content is not in the input field yet. Shouldn’t make any difference for
1953                 // change, though.
1954                 setTimeout(search, 0);
1955             };
1956             search_input.onpaste = search_input.onchange;
1957
1958             var selectCrate = document.getElementById("crate-search");
1959             if (selectCrate) {
1960                 selectCrate.onchange = function() {
1961                     updateLocalStorage("rustdoc-saved-filter-crate", selectCrate.value);
1962                     search(undefined, true);
1963                 };
1964             }
1965
1966             // Push and pop states are used to add search results to the browser
1967             // history.
1968             if (browserSupportsHistoryApi()) {
1969                 // Store the previous <title> so we can revert back to it later.
1970                 var previousTitle = document.title;
1971
1972                 window.addEventListener("popstate", function(e) {
1973                     var params = getQueryStringParams();
1974                     // Revert to the previous title manually since the History
1975                     // API ignores the title parameter.
1976                     document.title = previousTitle;
1977                     // When browsing forward to search results the previous
1978                     // search will be repeated, so the currentResults are
1979                     // cleared to ensure the search is successful.
1980                     currentResults = null;
1981                     // Synchronize search bar with query string state and
1982                     // perform the search. This will empty the bar if there's
1983                     // nothing there, which lets you really go back to a
1984                     // previous state with nothing in the bar.
1985                     if (params.search && params.search.length > 0) {
1986                         search_input.value = params.search;
1987                         // Some browsers fire "onpopstate" for every page load
1988                         // (Chrome), while others fire the event only when actually
1989                         // popping a state (Firefox), which is why search() is
1990                         // called both here and at the end of the startSearch()
1991                         // function.
1992                         search(e);
1993                     } else {
1994                         search_input.value = "";
1995                         // When browsing back from search results the main page
1996                         // visibility must be reset.
1997                         hideSearchResults();
1998                     }
1999                 });
2000             }
2001
2002             // This is required in firefox to avoid this problem: Navigating to a search result
2003             // with the keyboard, hitting enter, and then hitting back would take you back to
2004             // the doc page, rather than the search that should overlay it.
2005             // This was an interaction between the back-forward cache and our handlers
2006             // that try to sync state between the URL and the search input. To work around it,
2007             // do a small amount of re-init on page show.
2008             window.onpageshow = function(){
2009                 var qSearch = getQueryStringParams().search;
2010                 if (search_input.value === "" && qSearch) {
2011                     search_input.value = qSearch;
2012                 }
2013                 search();
2014             };
2015         }
2016
2017         index = buildIndex(rawSearchIndex);
2018         registerSearchEvents();
2019         // If there's a search term in the URL, execute the search now.
2020         if (getQueryStringParams().search) {
2021             search();
2022         }
2023     };
2024
2025     function addSidebarCrates(crates) {
2026         // Draw a convenient sidebar of known crates if we have a listing
2027         if (window.rootPath === "../" || window.rootPath === "./") {
2028             var sidebar = document.getElementsByClassName("sidebar-elems")[0];
2029             if (sidebar) {
2030                 var div = document.createElement("div");
2031                 div.className = "block crate";
2032                 div.innerHTML = "<h3>Crates</h3>";
2033                 var ul = document.createElement("ul");
2034                 div.appendChild(ul);
2035
2036                 for (var i = 0; i < crates.length; ++i) {
2037                     var klass = "crate";
2038                     if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
2039                         klass += " current";
2040                     }
2041                     var link = document.createElement("a");
2042                     link.href = window.rootPath + crates[i] + "/index.html";
2043                     link.className = klass;
2044                     link.textContent = crates[i];
2045
2046                     var li = document.createElement("li");
2047                     li.appendChild(link);
2048                     ul.appendChild(li);
2049                 }
2050                 sidebar.appendChild(div);
2051             }
2052         }
2053     }
2054
2055     // delayed sidebar rendering.
2056     window.initSidebarItems = function(items) {
2057         var sidebar = document.getElementsByClassName("sidebar-elems")[0];
2058         var current = window.sidebarCurrent;
2059
2060         function block(shortty, longty) {
2061             var filtered = items[shortty];
2062             if (!filtered) {
2063                 return;
2064             }
2065
2066             var div = document.createElement("div");
2067             div.className = "block " + shortty;
2068             var h3 = document.createElement("h3");
2069             h3.textContent = longty;
2070             div.appendChild(h3);
2071             var ul = document.createElement("ul");
2072
2073             for (var i = 0, len = filtered.length; i < len; ++i) {
2074                 var item = filtered[i];
2075                 var name = item[0];
2076                 var desc = item[1]; // can be null
2077
2078                 var klass = shortty;
2079                 if (name === current.name && shortty === current.ty) {
2080                     klass += " current";
2081                 }
2082                 var path;
2083                 if (shortty === "mod") {
2084                     path = name + "/index.html";
2085                 } else {
2086                     path = shortty + "." + name + ".html";
2087                 }
2088                 var link = document.createElement("a");
2089                 link.href = current.relpath + path;
2090                 link.title = desc;
2091                 link.className = klass;
2092                 link.textContent = name;
2093                 var li = document.createElement("li");
2094                 li.appendChild(link);
2095                 ul.appendChild(li);
2096             }
2097             div.appendChild(ul);
2098             if (sidebar) {
2099                 sidebar.appendChild(div);
2100             }
2101         }
2102
2103         block("primitive", "Primitive Types");
2104         block("mod", "Modules");
2105         block("macro", "Macros");
2106         block("struct", "Structs");
2107         block("enum", "Enums");
2108         block("union", "Unions");
2109         block("constant", "Constants");
2110         block("static", "Statics");
2111         block("trait", "Traits");
2112         block("fn", "Functions");
2113         block("type", "Type Definitions");
2114         block("foreigntype", "Foreign Types");
2115         block("keyword", "Keywords");
2116         block("traitalias", "Trait Aliases");
2117     };
2118
2119     window.register_implementors = function(imp) {
2120         var implementors = document.getElementById("implementors-list");
2121         var synthetic_implementors = document.getElementById("synthetic-implementors-list");
2122
2123         if (synthetic_implementors) {
2124             // This `inlined_types` variable is used to avoid having the same implementation
2125             // showing up twice. For example "String" in the "Sync" doc page.
2126             //
2127             // By the way, this is only used by and useful for traits implemented automatically
2128             // (like "Send" and "Sync").
2129             var inlined_types = new Set();
2130             onEachLazy(synthetic_implementors.getElementsByClassName("impl"), function(el) {
2131                 var aliases = el.getAttribute("aliases");
2132                 if (!aliases) {
2133                     return;
2134                 }
2135                 aliases.split(",").forEach(function(alias) {
2136                     inlined_types.add(alias);
2137                 });
2138             });
2139         }
2140
2141         var libs = Object.getOwnPropertyNames(imp);
2142         for (var i = 0, llength = libs.length; i < llength; ++i) {
2143             if (libs[i] === window.currentCrate) { continue; }
2144             var structs = imp[libs[i]];
2145
2146             struct_loop:
2147             for (var j = 0, slength = structs.length; j < slength; ++j) {
2148                 var struct = structs[j];
2149
2150                 var list = struct.synthetic ? synthetic_implementors : implementors;
2151
2152                 if (struct.synthetic) {
2153                     for (var k = 0, stlength = struct.types.length; k < stlength; k++) {
2154                         if (inlined_types.has(struct.types[k])) {
2155                             continue struct_loop;
2156                         }
2157                         inlined_types.add(struct.types[k]);
2158                     }
2159                 }
2160
2161                 var code = document.createElement("code");
2162                 code.innerHTML = struct.text;
2163
2164                 onEachLazy(code.getElementsByTagName("a"), function(elem) {
2165                     var href = elem.getAttribute("href");
2166
2167                     if (href && href.indexOf("http") !== 0) {
2168                         elem.setAttribute("href", window.rootPath + href);
2169                     }
2170                 });
2171
2172                 var display = document.createElement("h3");
2173                 addClass(display, "impl");
2174                 display.innerHTML = "<span class=\"in-band\"><table class=\"table-display\">" +
2175                     "<tbody><tr><td><code>" + code.outerHTML + "</code></td><td></td></tr>" +
2176                     "</tbody></table></span>";
2177                 list.appendChild(display);
2178             }
2179         }
2180     };
2181     if (window.pending_implementors) {
2182         window.register_implementors(window.pending_implementors);
2183     }
2184
2185     function labelForToggleButton(sectionIsCollapsed) {
2186         if (sectionIsCollapsed) {
2187             // button will expand the section
2188             return "+";
2189         }
2190         // button will collapse the section
2191         // note that this text is also set in the HTML template in render.rs
2192         return "\u2212"; // "\u2212" is "−" minus sign
2193     }
2194
2195     function onEveryMatchingChild(elem, className, func) {
2196         if (elem && className && func) {
2197             var length = elem.childNodes.length;
2198             var nodes = elem.childNodes;
2199             for (var i = 0; i < length; ++i) {
2200                 if (hasClass(nodes[i], className)) {
2201                     func(nodes[i]);
2202                 } else {
2203                     onEveryMatchingChild(nodes[i], className, func);
2204                 }
2205             }
2206         }
2207     }
2208
2209     function toggleAllDocs(fromAutoCollapse) {
2210         var innerToggle = document.getElementById(toggleAllDocsId);
2211         if (!innerToggle) {
2212             return;
2213         }
2214         if (hasClass(innerToggle, "will-expand")) {
2215             updateLocalStorage("rustdoc-collapse", "false");
2216             removeClass(innerToggle, "will-expand");
2217             onEveryMatchingChild(innerToggle, "inner", function(e) {
2218                 e.innerHTML = labelForToggleButton(false);
2219             });
2220             innerToggle.title = "collapse all docs";
2221             if (fromAutoCollapse !== true) {
2222                 onEachLazy(document.getElementsByClassName("collapse-toggle"), function(e) {
2223                     collapseDocs(e, "show");
2224                 });
2225             }
2226         } else {
2227             updateLocalStorage("rustdoc-collapse", "true");
2228             addClass(innerToggle, "will-expand");
2229             onEveryMatchingChild(innerToggle, "inner", function(e) {
2230                 var parent = e.parentNode;
2231                 var superParent = null;
2232
2233                 if (parent) {
2234                     superParent = parent.parentNode;
2235                 }
2236                 if (!parent || !superParent || superParent.id !== "main" ||
2237                     hasClass(parent, "impl") === false) {
2238                     e.innerHTML = labelForToggleButton(true);
2239                 }
2240             });
2241             innerToggle.title = "expand all docs";
2242             if (fromAutoCollapse !== true) {
2243                 onEachLazy(document.getElementsByClassName("collapse-toggle"), function(e) {
2244                     var parent = e.parentNode;
2245                     var superParent = null;
2246
2247                     if (parent) {
2248                         superParent = parent.parentNode;
2249                     }
2250                     if (!parent || !superParent || superParent.id !== "main" ||
2251                         hasClass(parent, "impl") === false) {
2252                         collapseDocs(e, "hide");
2253                     }
2254                 });
2255             }
2256         }
2257     }
2258
2259     function collapseDocs(toggle, mode) {
2260         if (!toggle || !toggle.parentNode) {
2261             return;
2262         }
2263
2264         function adjustToggle(arg) {
2265             return function(e) {
2266                 if (hasClass(e, "toggle-label")) {
2267                     if (arg) {
2268                         e.style.display = "inline-block";
2269                     } else {
2270                         e.style.display = "none";
2271                     }
2272                 }
2273                 if (hasClass(e, "inner")) {
2274                     e.innerHTML = labelForToggleButton(arg);
2275                 }
2276             };
2277         }
2278
2279         function implHider(addOrRemove, fullHide) {
2280             return function(n) {
2281                 var shouldHide =
2282                     fullHide === true ||
2283                     hasClass(n, "method") === true ||
2284                     hasClass(n, "associatedconstant") === true;
2285                 if (shouldHide === true || hasClass(n, "type") === true) {
2286                     if (shouldHide === true) {
2287                         if (addOrRemove) {
2288                             addClass(n, "hidden-by-impl-hider");
2289                         } else {
2290                             removeClass(n, "hidden-by-impl-hider");
2291                         }
2292                     }
2293                     var ns = n.nextElementSibling;
2294                     while (ns && (hasClass(ns, "docblock") || hasClass(ns, "item-info"))) {
2295                         if (addOrRemove) {
2296                             addClass(ns, "hidden-by-impl-hider");
2297                         } else {
2298                             removeClass(ns, "hidden-by-impl-hider");
2299                         }
2300                         ns = ns.nextElementSibling;
2301                     }
2302                 }
2303             };
2304         }
2305
2306         var relatedDoc;
2307         var action = mode;
2308         if (hasClass(toggle.parentNode, "impl") === false) {
2309             relatedDoc = toggle.parentNode.nextElementSibling;
2310             if (hasClass(relatedDoc, "item-info")) {
2311                 relatedDoc = relatedDoc.nextElementSibling;
2312             }
2313             if (hasClass(relatedDoc, "docblock") || hasClass(relatedDoc, "sub-variant")) {
2314                 if (mode === "toggle") {
2315                     if (hasClass(relatedDoc, "hidden-by-usual-hider")) {
2316                         action = "show";
2317                     } else {
2318                         action = "hide";
2319                     }
2320                 }
2321                 if (action === "hide") {
2322                     addClass(relatedDoc, "hidden-by-usual-hider");
2323                     onEachLazy(toggle.childNodes, adjustToggle(true));
2324                     addClass(toggle.parentNode, "collapsed");
2325                 } else if (action === "show") {
2326                     removeClass(relatedDoc, "hidden-by-usual-hider");
2327                     removeClass(toggle.parentNode, "collapsed");
2328                     onEachLazy(toggle.childNodes, adjustToggle(false));
2329                 }
2330             }
2331         } else {
2332             // we are collapsing the impl block(s).
2333
2334             var parentElem = toggle.parentNode;
2335             relatedDoc = parentElem;
2336             var docblock = relatedDoc.nextElementSibling;
2337
2338             while (hasClass(relatedDoc, "impl-items") === false) {
2339                 relatedDoc = relatedDoc.nextElementSibling;
2340             }
2341
2342             if (!relatedDoc && hasClass(docblock, "docblock") === false) {
2343                 return;
2344             }
2345
2346             // Hide all functions, but not associated types/consts.
2347
2348             if (mode === "toggle") {
2349                 if (hasClass(relatedDoc, "fns-now-collapsed") ||
2350                     hasClass(docblock, "hidden-by-impl-hider")) {
2351                     action = "show";
2352                 } else {
2353                     action = "hide";
2354                 }
2355             }
2356
2357             var dontApplyBlockRule = toggle.parentNode.parentNode.id !== "main";
2358             if (action === "show") {
2359                 removeClass(relatedDoc, "fns-now-collapsed");
2360                 // Stability/deprecation/portability information is never hidden.
2361                 if (hasClass(docblock, "item-info") === false) {
2362                     removeClass(docblock, "hidden-by-usual-hider");
2363                 }
2364                 onEachLazy(toggle.childNodes, adjustToggle(false, dontApplyBlockRule));
2365                 onEachLazy(relatedDoc.childNodes, implHider(false, dontApplyBlockRule));
2366             } else if (action === "hide") {
2367                 addClass(relatedDoc, "fns-now-collapsed");
2368                 // Stability/deprecation/portability information should be shown even when detailed
2369                 // info is hidden.
2370                 if (hasClass(docblock, "item-info") === false) {
2371                     addClass(docblock, "hidden-by-usual-hider");
2372                 }
2373                 onEachLazy(toggle.childNodes, adjustToggle(true, dontApplyBlockRule));
2374                 onEachLazy(relatedDoc.childNodes, implHider(true, dontApplyBlockRule));
2375             }
2376         }
2377     }
2378
2379     function collapser(e, collapse) {
2380         // inherent impl ids are like "impl" or impl-<number>'.
2381         // they will never be hidden by default.
2382         var n = e.parentElement;
2383         if (n.id.match(/^impl(?:-\d+)?$/) === null) {
2384             // Automatically minimize all non-inherent impls
2385             if (collapse || hasClass(n, "impl")) {
2386                 collapseDocs(e, "hide");
2387             }
2388         }
2389     }
2390
2391     function autoCollapse(collapse) {
2392         if (collapse) {
2393             toggleAllDocs(true);
2394         } else if (getSettingValue("auto-hide-trait-implementations") !== "false") {
2395             var impl_list = document.getElementById("trait-implementations-list");
2396
2397             if (impl_list !== null) {
2398                 onEachLazy(impl_list.getElementsByClassName("collapse-toggle"), function(e) {
2399                     collapser(e, collapse);
2400                 });
2401             }
2402
2403             var blanket_list = document.getElementById("blanket-implementations-list");
2404
2405             if (blanket_list !== null) {
2406                 onEachLazy(blanket_list.getElementsByClassName("collapse-toggle"), function(e) {
2407                     collapser(e, collapse);
2408                 });
2409             }
2410         }
2411     }
2412
2413     function insertAfter(newNode, referenceNode) {
2414         referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
2415     }
2416
2417     function createSimpleToggle(sectionIsCollapsed) {
2418         var toggle = document.createElement("a");
2419         toggle.href = "javascript:void(0)";
2420         toggle.className = "collapse-toggle";
2421         toggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(sectionIsCollapsed) +
2422                            "</span>]";
2423         return toggle;
2424     }
2425
2426     function createToggle(toggle, otherMessage, fontSize, extraClass, show) {
2427         var span = document.createElement("span");
2428         span.className = "toggle-label";
2429         if (show) {
2430             span.style.display = "none";
2431         }
2432         if (!otherMessage) {
2433             span.innerHTML = "&nbsp;Expand&nbsp;description";
2434         } else {
2435             span.innerHTML = otherMessage;
2436         }
2437
2438         if (fontSize) {
2439             span.style.fontSize = fontSize;
2440         }
2441
2442         var mainToggle = toggle.cloneNode(true);
2443         mainToggle.appendChild(span);
2444
2445         var wrapper = document.createElement("div");
2446         wrapper.className = "toggle-wrapper";
2447         if (!show) {
2448             addClass(wrapper, "collapsed");
2449             var inner = mainToggle.getElementsByClassName("inner");
2450             if (inner && inner.length > 0) {
2451                 inner[0].innerHTML = "+";
2452             }
2453         }
2454         if (extraClass) {
2455             addClass(wrapper, extraClass);
2456         }
2457         wrapper.appendChild(mainToggle);
2458         return wrapper;
2459     }
2460
2461     (function() {
2462         var toggles = document.getElementById(toggleAllDocsId);
2463         if (toggles) {
2464             toggles.onclick = toggleAllDocs;
2465         }
2466
2467         var toggle = createSimpleToggle(false);
2468         var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
2469         var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
2470
2471         var func = function(e) {
2472             var next = e.nextElementSibling;
2473             if (next && hasClass(next, "item-info")) {
2474               next = next.nextElementSibling;
2475             }
2476             if (!next) {
2477                 return;
2478             }
2479             if (hasClass(next, "docblock")) {
2480                 var newToggle = toggle.cloneNode(true);
2481                 insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
2482                 if (hideMethodDocs === true && hasClass(e, "method") === true) {
2483                     collapseDocs(newToggle, "hide");
2484                 }
2485             }
2486         };
2487
2488         var funcImpl = function(e) {
2489             var next = e.nextElementSibling;
2490             if (next && hasClass(next, "item-info")) {
2491                 next = next.nextElementSibling;
2492             }
2493             if (next && hasClass(next, "docblock")) {
2494                 next = next.nextElementSibling;
2495             }
2496             if (!next) {
2497                 return;
2498             }
2499             if (hasClass(e, "impl") &&
2500                 (next.getElementsByClassName("method").length > 0 ||
2501                  next.getElementsByClassName("associatedconstant").length > 0)) {
2502                 var newToggle = toggle.cloneNode(true);
2503                 insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
2504                 // In case the option "auto-collapse implementors" is not set to false, we collapse
2505                 // all implementors.
2506                 if (hideImplementors === true && e.parentNode.id === "implementors-list") {
2507                     collapseDocs(newToggle, "hide");
2508                 }
2509             }
2510         };
2511
2512         onEachLazy(document.getElementsByClassName("method"), func);
2513         onEachLazy(document.getElementsByClassName("associatedconstant"), func);
2514         onEachLazy(document.getElementsByClassName("impl"), funcImpl);
2515         var impl_call = function() {};
2516         if (hideMethodDocs === true) {
2517             impl_call = function(e, newToggle) {
2518                 if (e.id.match(/^impl(?:-\d+)?$/) === null) {
2519                     // Automatically minimize all non-inherent impls
2520                     if (hasClass(e, "impl") === true) {
2521                         collapseDocs(newToggle, "hide");
2522                     }
2523                 }
2524             };
2525         }
2526         var newToggle = document.createElement("a");
2527         newToggle.href = "javascript:void(0)";
2528         newToggle.className = "collapse-toggle hidden-default collapsed";
2529         newToggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
2530                               "</span>] Show hidden undocumented items";
2531         function toggleClicked() {
2532             if (hasClass(this, "collapsed")) {
2533                 removeClass(this, "collapsed");
2534                 onEachLazy(this.parentNode.getElementsByClassName("hidden"), function(x) {
2535                     if (hasClass(x, "content") === false) {
2536                         removeClass(x, "hidden");
2537                         addClass(x, "x");
2538                     }
2539                 }, true);
2540                 this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(false) +
2541                                  "</span>] Hide undocumented items";
2542             } else {
2543                 addClass(this, "collapsed");
2544                 onEachLazy(this.parentNode.getElementsByClassName("x"), function(x) {
2545                     if (hasClass(x, "content") === false) {
2546                         addClass(x, "hidden");
2547                         removeClass(x, "x");
2548                     }
2549                 }, true);
2550                 this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
2551                                  "</span>] Show hidden undocumented items";
2552             }
2553         }
2554         onEachLazy(document.getElementsByClassName("impl-items"), function(e) {
2555             onEachLazy(e.getElementsByClassName("associatedconstant"), func);
2556             // We transform the DOM iterator into a vec of DOM elements to prevent performance
2557             // issues on webkit browsers.
2558             var hiddenElems = Array.prototype.slice.call(e.getElementsByClassName("hidden"));
2559             var needToggle = hiddenElems.some(function(hiddenElem) {
2560                 return hasClass(hiddenElem, "content") === false &&
2561                     hasClass(hiddenElem, "docblock") === false;
2562             });
2563             if (needToggle === true) {
2564                 var inner_toggle = newToggle.cloneNode(true);
2565                 inner_toggle.onclick = toggleClicked;
2566                 e.insertBefore(inner_toggle, e.firstChild);
2567                 impl_call(e.previousSibling, inner_toggle);
2568             }
2569         });
2570
2571         var currentType = document.getElementsByClassName("type-decl")[0];
2572         var className = null;
2573         if (currentType) {
2574             currentType = currentType.getElementsByClassName("rust")[0];
2575             if (currentType) {
2576                 currentType.classList.forEach(function(item) {
2577                     if (item !== "main") {
2578                         className = item;
2579                         return true;
2580                     }
2581                 });
2582             }
2583         }
2584         var showItemDeclarations = getSettingValue("auto-hide-" + className);
2585         if (showItemDeclarations === null) {
2586             if (className === "enum" || className === "macro") {
2587                 showItemDeclarations = "false";
2588             } else if (className === "struct" || className === "union" || className === "trait") {
2589                 showItemDeclarations = "true";
2590             } else {
2591                 // In case we found an unknown type, we just use the "parent" value.
2592                 showItemDeclarations = getSettingValue("auto-hide-declarations");
2593             }
2594         }
2595         showItemDeclarations = showItemDeclarations === "false";
2596         function buildToggleWrapper(e) {
2597             if (hasClass(e, "autohide")) {
2598                 var wrap = e.previousElementSibling;
2599                 if (wrap && hasClass(wrap, "toggle-wrapper")) {
2600                     var inner_toggle = wrap.childNodes[0];
2601                     var extra = e.childNodes[0].tagName === "H3";
2602
2603                     e.style.display = "none";
2604                     addClass(wrap, "collapsed");
2605                     onEachLazy(inner_toggle.getElementsByClassName("inner"), function(e) {
2606                         e.innerHTML = labelForToggleButton(true);
2607                     });
2608                     onEachLazy(inner_toggle.getElementsByClassName("toggle-label"), function(e) {
2609                         e.style.display = "inline-block";
2610                         if (extra === true) {
2611                             e.innerHTML = " Show " + e.childNodes[0].innerHTML;
2612                         }
2613                     });
2614                 }
2615             }
2616             if (e.parentNode.id === "main") {
2617                 var otherMessage = "";
2618                 var fontSize;
2619                 var extraClass;
2620
2621                 if (hasClass(e, "type-decl")) {
2622                     fontSize = "20px";
2623                     otherMessage = "&nbsp;Show&nbsp;declaration";
2624                     if (showItemDeclarations === false) {
2625                         extraClass = "collapsed";
2626                     }
2627                 } else if (hasClass(e, "sub-variant")) {
2628                     otherMessage = "&nbsp;Show&nbsp;fields";
2629                 } else if (hasClass(e, "non-exhaustive")) {
2630                     otherMessage = "&nbsp;This&nbsp;";
2631                     if (hasClass(e, "non-exhaustive-struct")) {
2632                         otherMessage += "struct";
2633                     } else if (hasClass(e, "non-exhaustive-enum")) {
2634                         otherMessage += "enum";
2635                     } else if (hasClass(e, "non-exhaustive-variant")) {
2636                         otherMessage += "enum variant";
2637                     } else if (hasClass(e, "non-exhaustive-type")) {
2638                         otherMessage += "type";
2639                     }
2640                     otherMessage += "&nbsp;is&nbsp;marked&nbsp;as&nbsp;non-exhaustive";
2641                 } else if (hasClass(e.childNodes[0], "impl-items")) {
2642                     extraClass = "marg-left";
2643                 }
2644
2645                 e.parentNode.insertBefore(
2646                     createToggle(
2647                         toggle,
2648                         otherMessage,
2649                         fontSize,
2650                         extraClass,
2651                         hasClass(e, "type-decl") === false || showItemDeclarations === true),
2652                     e);
2653                 if (hasClass(e, "type-decl") === true && showItemDeclarations === true) {
2654                     collapseDocs(e.previousSibling.childNodes[0], "toggle");
2655                 }
2656                 if (hasClass(e, "non-exhaustive") === true) {
2657                     collapseDocs(e.previousSibling.childNodes[0], "toggle");
2658                 }
2659             }
2660         }
2661
2662         onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper);
2663         onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper);
2664
2665         autoCollapse(getSettingValue("collapse") === "true");
2666
2667         var pageId = getPageId();
2668         if (pageId !== null) {
2669             expandSection(pageId);
2670         }
2671     }());
2672
2673     function createToggleWrapper(tog) {
2674         var span = document.createElement("span");
2675         span.className = "toggle-label";
2676         span.style.display = "none";
2677         span.innerHTML = "&nbsp;Expand&nbsp;attributes";
2678         tog.appendChild(span);
2679
2680         var wrapper = document.createElement("div");
2681         wrapper.className = "toggle-wrapper toggle-attributes";
2682         wrapper.appendChild(tog);
2683         return wrapper;
2684     }
2685
2686     (function() {
2687         // To avoid checking on "rustdoc-item-attributes" value on every loop...
2688         var itemAttributesFunc = function() {};
2689         if (getSettingValue("auto-hide-attributes") !== "false") {
2690             itemAttributesFunc = function(x) {
2691                 collapseDocs(x.previousSibling.childNodes[0], "toggle");
2692             };
2693         }
2694         var attributesToggle = createToggleWrapper(createSimpleToggle(false));
2695         onEachLazy(main.getElementsByClassName("attributes"), function(i_e) {
2696             var attr_tog = attributesToggle.cloneNode(true);
2697             if (hasClass(i_e, "top-attr") === true) {
2698                 addClass(attr_tog, "top-attr");
2699             }
2700             i_e.parentNode.insertBefore(attr_tog, i_e);
2701             itemAttributesFunc(i_e);
2702         });
2703     }());
2704
2705     (function() {
2706         // To avoid checking on "rustdoc-line-numbers" value on every loop...
2707         var lineNumbersFunc = function() {};
2708         if (getSettingValue("line-numbers") === "true") {
2709             lineNumbersFunc = function(x) {
2710                 var count = x.textContent.split("\n").length;
2711                 var elems = [];
2712                 for (var i = 0; i < count; ++i) {
2713                     elems.push(i + 1);
2714                 }
2715                 var node = document.createElement("pre");
2716                 addClass(node, "line-number");
2717                 node.innerHTML = elems.join("\n");
2718                 x.parentNode.insertBefore(node, x);
2719             };
2720         }
2721         onEachLazy(document.getElementsByClassName("rust-example-rendered"), function(e) {
2722             if (hasClass(e, "compile_fail")) {
2723                 e.addEventListener("mouseover", function() {
2724                     this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
2725                 });
2726                 e.addEventListener("mouseout", function() {
2727                     this.parentElement.previousElementSibling.childNodes[0].style.color = "";
2728                 });
2729             } else if (hasClass(e, "ignore")) {
2730                 e.addEventListener("mouseover", function() {
2731                     this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
2732                 });
2733                 e.addEventListener("mouseout", function() {
2734                     this.parentElement.previousElementSibling.childNodes[0].style.color = "";
2735                 });
2736             }
2737             lineNumbersFunc(e);
2738         });
2739     }());
2740
2741     onEachLazy(document.getElementsByClassName("notable-traits"), function(e) {
2742         e.onclick = function() {
2743             this.getElementsByClassName('notable-traits-tooltiptext')[0]
2744                 .classList.toggle("force-tooltip");
2745         };
2746     });
2747
2748     // In the search display, allows to switch between tabs.
2749     function printTab(nb) {
2750         if (nb === 0 || nb === 1 || nb === 2) {
2751             currentTab = nb;
2752         }
2753         var nb_copy = nb;
2754         onEachLazy(document.getElementById("titles").childNodes, function(elem) {
2755             if (nb_copy === 0) {
2756                 addClass(elem, "selected");
2757             } else {
2758                 removeClass(elem, "selected");
2759             }
2760             nb_copy -= 1;
2761         });
2762         onEachLazy(document.getElementById("results").childNodes, function(elem) {
2763             if (nb === 0) {
2764                 elem.style.display = "";
2765             } else {
2766                 elem.style.display = "none";
2767             }
2768             nb -= 1;
2769         });
2770     }
2771
2772     function putBackSearch(search_input) {
2773         var search = getSearchElement();
2774         if (search_input.value !== "" && hasClass(search, "hidden")) {
2775             showSearchResults(search);
2776             if (browserSupportsHistoryApi()) {
2777                 var extra = "?search=" + encodeURIComponent(search_input.value);
2778                 history.replaceState(search_input.value, "",
2779                     getNakedUrl() + extra + window.location.hash);
2780             }
2781             document.title = searchTitle;
2782         }
2783     }
2784
2785     function getSearchLoadingText() {
2786         return "Loading search results...";
2787     }
2788
2789     if (search_input) {
2790         search_input.onfocus = function() {
2791             putBackSearch(this);
2792         };
2793     }
2794
2795     var params = getQueryStringParams();
2796     if (params && params.search) {
2797         var search = getSearchElement();
2798         search.innerHTML = "<h3 style=\"text-align: center;\">" + getSearchLoadingText() + "</h3>";
2799         showSearchResults(search);
2800     }
2801
2802     var sidebar_menu = document.getElementsByClassName("sidebar-menu")[0];
2803     if (sidebar_menu) {
2804         sidebar_menu.onclick = function() {
2805             var sidebar = document.getElementsByClassName("sidebar")[0];
2806             if (hasClass(sidebar, "mobile") === true) {
2807                 hideSidebar();
2808             } else {
2809                 showSidebar();
2810             }
2811         };
2812     }
2813
2814     if (main) {
2815         onEachLazy(main.getElementsByClassName("loading-content"), function(e) {
2816             e.remove();
2817         });
2818         onEachLazy(main.childNodes, function(e) {
2819             // Unhide the actual content once loading is complete. Headers get
2820             // flex treatment for their horizontal layout, divs get block treatment
2821             // for vertical layout (column-oriented flex layout for divs caused
2822             // errors in mobile browsers).
2823             if (e.tagName === "H2" || e.tagName === "H3") {
2824                 var nextTagName = e.nextElementSibling.tagName;
2825                 if (nextTagName == "H2" || nextTagName == "H3") {
2826                     e.nextElementSibling.style.display = "flex";
2827                 } else {
2828                     e.nextElementSibling.style.display = "block";
2829                 }
2830             }
2831         });
2832     }
2833
2834     function enableSearchInput() {
2835         if (search_input) {
2836             search_input.removeAttribute('disabled');
2837         }
2838     }
2839
2840     function addSearchOptions(crates) {
2841         var elem = document.getElementById("crate-search");
2842
2843         if (!elem) {
2844             enableSearchInput();
2845             return;
2846         }
2847         var savedCrate = getSettingValue("saved-filter-crate");
2848         for (var i = 0, len = crates.length; i < len; ++i) {
2849             var option = document.createElement("option");
2850             option.value = crates[i];
2851             option.innerText = crates[i];
2852             elem.appendChild(option);
2853             // Set the crate filter from saved storage, if the current page has the saved crate
2854             // filter.
2855             //
2856             // If not, ignore the crate filter -- we want to support filtering for crates on sites
2857             // like doc.rust-lang.org where the crates may differ from page to page while on the
2858             // same domain.
2859             if (crates[i] === savedCrate) {
2860                 elem.value = savedCrate;
2861             }
2862         }
2863         enableSearchInput();
2864     };
2865
2866     function buildHelperPopup() {
2867         var popup = document.createElement("aside");
2868         addClass(popup, "hidden");
2869         popup.id = "help";
2870
2871         var book_info = document.createElement("span");
2872         book_info.innerHTML = "You can find more information in \
2873             <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
2874
2875         var container = document.createElement("div");
2876         var shortcuts = [
2877             ["?", "Show this help dialog"],
2878             ["S", "Focus the search field"],
2879             ["T", "Focus the theme picker menu"],
2880             ["↑", "Move up in search results"],
2881             ["↓", "Move down in search results"],
2882             ["ctrl + ↑ / ↓", "Switch result tab"],
2883             ["&#9166;", "Go to active search result"],
2884             ["+", "Expand all sections"],
2885             ["-", "Collapse all sections"],
2886         ].map(function(x) {
2887             return "<dt>" +
2888                 x[0].split(" ")
2889                     .map(function(y, index) {
2890                         return (index & 1) === 0 ? "<kbd>" + y + "</kbd>" : " " + y + " ";
2891                     })
2892                     .join("") + "</dt><dd>" + x[1] + "</dd>";
2893         }).join("");
2894         var div_shortcuts = document.createElement("div");
2895         addClass(div_shortcuts, "shortcuts");
2896         div_shortcuts.innerHTML = "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts + "</dl></div>";
2897
2898         var infos = [
2899             "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
2900              restrict the search to a given item kind.",
2901             "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \
2902              <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
2903              and <code>const</code>.",
2904             "Search functions by type signature (e.g., <code>vec -&gt; usize</code> or \
2905              <code>* -&gt; vec</code>)",
2906             "Search multiple things at once by splitting your query with comma (e.g., \
2907              <code>str,u8</code> or <code>String,struct:Vec,test</code>)",
2908             "You can look for items with an exact name by putting double quotes around \
2909              your request: <code>\"string\"</code>",
2910             "Look for items inside another one by searching for a path: <code>vec::Vec</code>",
2911         ].map(function(x) {
2912             return "<p>" + x + "</p>";
2913         }).join("");
2914         var div_infos = document.createElement("div");
2915         addClass(div_infos, "infos");
2916         div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;
2917
2918         container.appendChild(book_info);
2919         container.appendChild(div_shortcuts);
2920         container.appendChild(div_infos);
2921
2922         popup.appendChild(container);
2923         insertAfter(popup, getSearchElement());
2924         // So that it's only built once and then it'll do nothing when called!
2925         buildHelperPopup = function() {};
2926     }
2927
2928     function loadScript(url) {
2929         var script = document.createElement('script');
2930         script.src = url;
2931         document.head.append(script);
2932     }
2933
2934     function setupSearchLoader() {
2935         var searchLoaded = false;
2936         function loadSearch() {
2937             if (!searchLoaded) {
2938                 searchLoaded = true;
2939                 loadScript(window.searchJS);
2940             }
2941         }
2942
2943         // `crates{version}.js` should always be loaded before this script, so we can use it safely.
2944         addSearchOptions(window.ALL_CRATES);
2945         addSidebarCrates(window.ALL_CRATES);
2946
2947         search_input.addEventListener("focus", function() {
2948             search_input.origPlaceholder = search_input.placeholder;
2949             search_input.placeholder = "Type your search here.";
2950             loadSearch();
2951         });
2952         search_input.addEventListener("blur", function() {
2953             search_input.placeholder = search_input.origPlaceholder;
2954         });
2955         enableSearchInput();
2956
2957         var crateSearchDropDown = document.getElementById("crate-search");
2958         crateSearchDropDown.addEventListener("focus", loadSearch);
2959         var params = getQueryStringParams();
2960         if (params.search !== undefined) {
2961             loadSearch();
2962         }
2963     }
2964
2965     onHashChange(null);
2966     window.onhashchange = onHashChange;
2967     setupSearchLoader();
2968 }());