about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2021-03-10 19:31:49 -0700
committerMichael Howell <michael@notriddle.com>2021-03-10 20:20:42 -0700
commit3934dd1b3e7514959202de6ca0d2636bcae21830 (patch)
tree7fbf782e112d17e18477bd09ffff4604f8646bc5
parentf98721f886ab52d32d622ad0a46216ad03f3e525 (diff)
downloadrust-3934dd1b3e7514959202de6ca0d2636bcae21830.tar.gz
rust-3934dd1b3e7514959202de6ca0d2636bcae21830.zip
rustdoc: tweak the search index format
This essentially switches search-index.js from a "array of struct"
to a "struct of array" format, like this:

    {
    "doc": "Crate documentation",
    "t": [ 1, 1, 2, 3, ... ],
    "n": [ "Something", "SomethingElse", "whatever", "do_stuff", ... ],
    "q": [ "a::b", "", "", "", ... ],
    "d": [ "A Struct That Does Something", "Another Struct", "a function", "another function", ... ],
    "i": [ 0, 0, 1, 1, ... ],
    "f": [ null, null, [], [], ... ],
    "p": ...,
    "a": ...
    }

So `{ty: 1, name: "Something", path: "a::b", desc: "A Struct That Does Something", parent_idx: 0, search_type: null}` is the first item.

This makes the uncompressed version smaller, but it really shows on the
compressed version:

    notriddle:rust$ wc -c new-search-index1.52.0.js
    2622427 new-search-index1.52.0.js
    notriddle:rust$ wc -c old-search-index1.52.0.js
    2725046 old-search-index1.52.0.js
    notriddle:rust$ gzip new-search-index1.52.0.js
    notriddle:rust$ gzip old-search-index1.52.0.js
    notriddle:rust$ wc -c new-search-index1.52.0.js.gz
    239385 new-search-index1.52.0.js.gz
    notriddle:rust$ wc -c old-search-index1.52.0.js.gz
    296328 old-search-index1.52.0.js.gz
    notriddle:rust$

That's a 4% improvement on the uncompressed version (fewer `[]`),
and 20% improvement after gzipping it, thanks to putting like-typed
data next to each other. Any compression algorithm based on a sliding
window will probably show this kind of improvement.
-rw-r--r--src/librustdoc/html/render/cache.rs60
-rw-r--r--src/librustdoc/html/render/mod.rs17
-rw-r--r--src/librustdoc/html/static/main.js39
3 files changed, 74 insertions, 42 deletions
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index a21cf5266fe..56fee2c9fec 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -4,7 +4,7 @@ use std::path::Path;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{sym, Symbol};
-use serde::Serialize;
+use serde::ser::{Serialize, SerializeStruct, Serializer};
 
 use crate::clean::types::{
     FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, TypeKind, WherePredicate,
@@ -133,21 +133,69 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
         .map(|module| module.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s)))
         .unwrap_or_default();
 
-    #[derive(Serialize)]
     struct CrateData<'a> {
         doc: String,
-        #[serde(rename = "i")]
         items: Vec<&'a IndexItem>,
-        #[serde(rename = "p")]
         paths: Vec<(ItemType, String)>,
         // The String is alias name and the vec is the list of the elements with this alias.
         //
         // To be noted: the `usize` elements are indexes to `items`.
-        #[serde(rename = "a")]
-        #[serde(skip_serializing_if = "BTreeMap::is_empty")]
         aliases: &'a BTreeMap<String, Vec<usize>>,
     }
 
+    impl<'a> Serialize for CrateData<'a> {
+        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+        where
+            S: Serializer,
+        {
+            let has_aliases = !self.aliases.is_empty();
+            let mut crate_data =
+                serializer.serialize_struct("CrateData", if has_aliases { 9 } else { 8 })?;
+            crate_data.serialize_field("doc", &self.doc)?;
+            crate_data.serialize_field(
+                "t",
+                &self.items.iter().map(|item| &item.ty).collect::<Vec<_>>(),
+            )?;
+            crate_data.serialize_field(
+                "n",
+                &self.items.iter().map(|item| &item.name).collect::<Vec<_>>(),
+            )?;
+            crate_data.serialize_field(
+                "q",
+                &self.items.iter().map(|item| &item.path).collect::<Vec<_>>(),
+            )?;
+            crate_data.serialize_field(
+                "d",
+                &self.items.iter().map(|item| &item.desc).collect::<Vec<_>>(),
+            )?;
+            crate_data.serialize_field(
+                "i",
+                &self
+                    .items
+                    .iter()
+                    .map(|item| {
+                        assert_eq!(
+                            item.parent.is_some(),
+                            item.parent_idx.is_some(),
+                            "`{}` is missing idx",
+                            item.name
+                        );
+                        item.parent_idx.map(|x| x + 1).unwrap_or(0)
+                    })
+                    .collect::<Vec<_>>(),
+            )?;
+            crate_data.serialize_field(
+                "f",
+                &self.items.iter().map(|item| &item.search_type).collect::<Vec<_>>(),
+            )?;
+            crate_data.serialize_field("p", &self.paths)?;
+            if has_aliases {
+                crate_data.serialize_field("a", &self.aliases)?;
+            }
+            crate_data.end()
+        }
+    }
+
     // Collect the index into a string
     format!(
         r#""{}":{}"#,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index a4621fb8ed5..66c47f14655 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -166,23 +166,6 @@ crate struct IndexItem {
     crate search_type: Option<IndexItemFunctionType>,
 }
 
-impl Serialize for IndexItem {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: Serializer,
-    {
-        assert_eq!(
-            self.parent.is_some(),
-            self.parent_idx.is_some(),
-            "`{}` is missing idx",
-            self.name
-        );
-
-        (self.ty, &self.name, &self.path, &self.desc, self.parent_idx, &self.search_type)
-            .serialize(serializer)
-    }
-}
-
 /// A type used for the search index.
 #[derive(Debug)]
 crate struct RenderType {
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 42519d59622..ac2da5f779b 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -1847,13 +1847,18 @@ function defocusSearchBar() {
                 });
                 currentIndex += 1;
 
-                // an array of [(Number) item type,
-                //              (String) name,
-                //              (String) full path or empty string for previous path,
-                //              (String) description,
-                //              (Number | null) the parent path index to `paths`]
-                //              (Object | null) the type of the function (if any)
-                var items = rawSearchIndex[crate].i;
+                // an array of (Number) item types
+                var itemTypes = rawSearchIndex[crate].t;
+                // an array of (String) item names
+                var itemNames = rawSearchIndex[crate].n;
+                // an array of (String) full paths (or empty string for previous path)
+                var itemPaths = rawSearchIndex[crate].q;
+                // an array of (String) descriptions
+                var itemDescs = rawSearchIndex[crate].d;
+                // an array of (Number) the parent path index + 1 to `paths`, or 0 if none
+                var itemParentIdxs = rawSearchIndex[crate].i;
+                // an array of (Object | null) the type of the function, if any
+                var itemFunctionSearchTypes = rawSearchIndex[crate].f;
                 // an array of [(Number) item type,
                 //              (String) name]
                 var paths = rawSearchIndex[crate].p;
@@ -1867,28 +1872,24 @@ function defocusSearchBar() {
                     paths[i] = {ty: paths[i][0], name: paths[i][1]};
                 }
 
-                // convert `items` into an object form, and construct word indices.
+                // convert `item*` into an object form, and construct word indices.
                 //
                 // before any analysis is performed lets gather the search terms to
                 // search against apart from the rest of the data.  This is a quick
                 // operation that is cached for the life of the page state so that
                 // all other search operations have access to this cached data for
                 // faster analysis operations
-                len = items.length;
+                len = itemTypes.length;
                 var lastPath = "";
                 for (i = 0; i < len; ++i) {
-                    var rawRow = items[i];
-                    if (!rawRow[2]) {
-                        rawRow[2] = lastPath;
-                    }
                     var row = {
                         crate: crate,
-                        ty: rawRow[0],
-                        name: rawRow[1],
-                        path: rawRow[2],
-                        desc: rawRow[3],
-                        parent: paths[rawRow[4]],
-                        type: rawRow[5],
+                        ty: itemTypes[i],
+                        name: itemNames[i],
+                        path: itemPaths[i] ? itemPaths[i] : lastPath,
+                        desc: itemDescs[i],
+                        parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined,
+                        type: itemFunctionSearchTypes[i],
                     };
                     searchIndex.push(row);
                     if (typeof row.name === "string") {