From fc7221689e6dcb32dbf72befa465d851d92263d8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 13 Dec 2023 12:14:46 +0100 Subject: [PATCH] Use Map instead of Object for source files and search index --- src/librustdoc/html/render/search_index.rs | 2 +- src/librustdoc/html/render/write_shared.rs | 19 +-- src/librustdoc/html/static/js/search.js | 141 +++++++++----------- src/librustdoc/html/static/js/src-script.js | 8 +- 4 files changed, 77 insertions(+), 93 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index b3ae720fcf609..a1029320d2d27 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -488,7 +488,7 @@ pub(crate) fn build_index<'tcx>( // Collect the index into a string format!( - r#""{}":{}"#, + r#"["{}",{}]"#, krate.name(tcx), serde_json::to_string(&CrateData { doc: crate_doc, diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index b04776e91dc74..4b5d1c0d87c7f 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -167,23 +167,24 @@ pub(super) fn write_shared( let mut krates = Vec::new(); if path.exists() { - let prefix = format!("\"{krate}\""); + let prefix = format!("[\"{krate}\""); for line in BufReader::new(File::open(path)?).lines() { let line = line?; - if !line.starts_with('"') { + if !line.starts_with("[\"") { continue; } if line.starts_with(&prefix) { continue; } - if line.ends_with(",\\") { + if line.ends_with("],\\") { ret.push(line[..line.len() - 2].to_string()); } else { // Ends with "\\" (it's the case for the last added crate line) ret.push(line[..line.len() - 1].to_string()); } krates.push( - line.split('"') + line[1..] // We skip the `[` parent at the beginning of the line. + .split('"') .find(|s| !s.is_empty()) .map(|s| s.to_owned()) .unwrap_or_else(String::new), @@ -285,7 +286,7 @@ pub(super) fn write_shared( let (mut all_sources, _krates) = try_err!(collect_json(&dst, krate.name(cx.tcx()).as_str()), &dst); all_sources.push(format!( - r#""{}":{}"#, + r#"["{}",{}]"#, &krate.name(cx.tcx()), hierarchy .to_json_string() @@ -296,9 +297,9 @@ pub(super) fn write_shared( .replace("\\\"", "\\\\\"") )); all_sources.sort(); - let mut v = String::from("var srcIndex = JSON.parse('{\\\n"); + let mut v = String::from("const srcIndex = new Map(JSON.parse('[\\\n"); v.push_str(&all_sources.join(",\\\n")); - v.push_str("\\\n}');\ncreateSrcSidebar();\n"); + v.push_str("\\\n]'));\ncreateSrcSidebar();\n"); Ok(v.into_bytes()) }; write_invocation_specific("src-files.js", &make_sources)?; @@ -316,11 +317,11 @@ pub(super) fn write_shared( // with rustdoc running in parallel. all_indexes.sort(); write_invocation_specific("search-index.js", &|| { - let mut v = String::from("var searchIndex = JSON.parse('{\\\n"); + let mut v = String::from("const searchIndex = new Map(JSON.parse('[\\\n"); v.push_str(&all_indexes.join(",\\\n")); v.push_str( r#"\ -}'); +]')); if (typeof window !== 'undefined' && window.initSearch) {window.initSearch(searchIndex)}; if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; "#, diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 6fce7650b4c14..ccb54e14a5cb2 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -80,10 +80,6 @@ const longItemTypes = [ const TY_GENERIC = itemTypes.indexOf("generic"); const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../"; -function hasOwnPropertyRustdoc(obj, property) { - return Object.prototype.hasOwnProperty.call(obj, property); -} - // In the search display, allows to switch between tabs. function printTab(nb) { let iter = 0; @@ -1074,7 +1070,7 @@ function initSearch(rawSearchIndex) { if (elem && elem.value !== "all crates" && - hasOwnPropertyRustdoc(rawSearchIndex, elem.value) + rawSearchIndex.has(elem.value) ) { return elem.value; } @@ -2524,11 +2520,10 @@ ${item.displayPath}${name}\ } let crates = ""; - const crates_list = Object.keys(rawSearchIndex); - if (crates_list.length > 1) { + if (rawSearchIndex.size > 1) { crates = " in 
"; @@ -2945,81 +2940,70 @@ ${item.displayPath}${name}\ // Function type fingerprints are 128-bit bloom filters that are used to // estimate the distance between function and query. // This loop counts the number of items to allocate a fingerprint for. - for (const crate in rawSearchIndex) { - if (!hasOwnPropertyRustdoc(rawSearchIndex, crate)) { - continue; - } + for (const crate of rawSearchIndex.values()) { // Each item gets an entry in the fingerprint array, and the crate // does, too - id += rawSearchIndex[crate].t.length + 1; + id += crate.t.length + 1; } functionTypeFingerprint = new Uint32Array((id + 1) * 4); // This loop actually generates the search item indexes, including // normalized names, type signature objects and fingerprints, and aliases. id = 0; - for (const crate in rawSearchIndex) { - if (!hasOwnPropertyRustdoc(rawSearchIndex, crate)) { - continue; - } - - let crateSize = 0; - - /** - * The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f` - * are arrays with the same length. `q`, `a`, and `c` use a sparse - * representation for compactness. - * - * `n[i]` contains the name of an item. - * - * `t[i]` contains the type of that item - * (as a string of characters that represent an offset in `itemTypes`). - * - * `d[i]` contains the description of that item. - * - * `q` contains the full paths of the items. For compactness, it is a set of - * (index, path) pairs used to create a map. If a given index `i` is - * not present, this indicates "same as the last index present". - * - * `i[i]` contains an item's parent, usually a module. For compactness, - * it is a set of indexes into the `p` array. - * - * `f[i]` contains function signatures, or `0` if the item isn't a function. - * Functions are themselves encoded as arrays. The first item is a list of - * types representing the function's inputs, and the second list item is a list - * of types representing the function's output. Tuples are flattened. - * Types are also represented as arrays; the first item is an index into the `p` - * array, while the second is a list of types representing any generic parameters. - * - * b[i] contains an item's impl disambiguator. This is only present if an item - * is defined in an impl block and, the impl block's type has more than one associated - * item with the same name. - * - * `a` defines aliases with an Array of pairs: [name, offset], where `offset` - * points into the n/t/d/q/i/f arrays. - * - * `doc` contains the description of the crate. - * - * `p` is a list of path/type pairs. It is used for parents and function parameters. - * - * `c` is an array of item indices that are deprecated. - * - * @type {{ - * doc: string, - * a: Object, - * n: Array, - * t: String, - * d: Array, - * q: Array<[Number, string]>, - * i: Array, - * f: Array, - * p: Array, - * b: Array<[Number, String]>, - * c: Array - * }} - */ - const crateCorpus = rawSearchIndex[crate]; - + /** + * The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f` + * are arrays with the same length. `q`, `a`, and `c` use a sparse + * representation for compactness. + * + * `n[i]` contains the name of an item. + * + * `t[i]` contains the type of that item + * (as a string of characters that represent an offset in `itemTypes`). + * + * `d[i]` contains the description of that item. + * + * `q` contains the full paths of the items. For compactness, it is a set of + * (index, path) pairs used to create a map. If a given index `i` is + * not present, this indicates "same as the last index present". + * + * `i[i]` contains an item's parent, usually a module. For compactness, + * it is a set of indexes into the `p` array. + * + * `f[i]` contains function signatures, or `0` if the item isn't a function. + * Functions are themselves encoded as arrays. The first item is a list of + * types representing the function's inputs, and the second list item is a list + * of types representing the function's output. Tuples are flattened. + * Types are also represented as arrays; the first item is an index into the `p` + * array, while the second is a list of types representing any generic parameters. + * + * b[i] contains an item's impl disambiguator. This is only present if an item + * is defined in an impl block and, the impl block's type has more than one associated + * item with the same name. + * + * `a` defines aliases with an Array of pairs: [name, offset], where `offset` + * points into the n/t/d/q/i/f arrays. + * + * `doc` contains the description of the crate. + * + * `p` is a list of path/type pairs. It is used for parents and function parameters. + * + * `c` is an array of item indices that are deprecated. + * + * @type {{ + * doc: string, + * a: Object, + * n: Array, + * t: String, + * d: Array, + * q: Array<[Number, string]>, + * i: Array, + * f: Array, + * p: Array, + * b: Array<[Number, String]>, + * c: Array + * }} + */ + for (const [crate, crateCorpus] of rawSearchIndex) { searchWords.push(crate); // This object should have exactly the same set of fields as the "row" // object defined below. Your JavaScript runtime will thank you. @@ -3145,14 +3129,13 @@ ${item.displayPath}${name}\ id += 1; searchIndex.push(row); lastPath = row.path; - crateSize += 1; } if (aliases) { const currentCrateAliases = new Map(); ALIASES.set(crate, currentCrateAliases); for (const alias_name in aliases) { - if (!hasOwnPropertyRustdoc(aliases, alias_name)) { + if (!Object.prototype.hasOwnProperty.call(aliases, alias_name)) { continue; } @@ -3168,7 +3151,7 @@ ${item.displayPath}${name}\ } } } - currentIndex += crateSize; + currentIndex += itemTypes.length; } return searchWords; } @@ -3377,7 +3360,7 @@ if (typeof window !== "undefined") { } else { // Running in Node, not a browser. Run initSearch just to produce the // exports. - initSearch({}); + initSearch(new Map()); } diff --git a/src/librustdoc/html/static/js/src-script.js b/src/librustdoc/html/static/js/src-script.js index 679c2341f02ba..27b5cf1e2aef3 100644 --- a/src/librustdoc/html/static/js/src-script.js +++ b/src/librustdoc/html/static/js/src-script.js @@ -118,10 +118,10 @@ function createSrcSidebar() { title.className = "title"; title.innerText = "Files"; sidebar.appendChild(title); - Object.keys(srcIndex).forEach(key => { - srcIndex[key][NAME_OFFSET] = key; - hasFoundFile = createDirEntry(srcIndex[key], sidebar, "", hasFoundFile); - }); + for (const [key, source] of srcIndex) { + source[NAME_OFFSET] = key; + hasFoundFile = createDirEntry(source, sidebar, "", hasFoundFile); + } container.appendChild(sidebar); // Focus on the current file in the source files sidebar.