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