From ab6915d7b530a1fa50ce87f2c227b2a33e4ce61e Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Wed, 9 Apr 2014 15:52:31 +0900 Subject: [PATCH 1/5] rustdoc: Use smaller sequential numbers instead of `NodeId`s for parents. `allPaths` is now a flat array in effect. This decreases the size of the search index by about 4--5% (gzipped or not). --- src/librustdoc/html/render.rs | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ccee4f0ffc9f3..0b9a42d8e34b7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -262,6 +262,9 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { }); cache.stack.push(krate.name.clone()); krate = cache.fold_crate(krate); + + let mut nodeid_to_pathid = HashMap::new(); + let mut pathid_to_nodeid = Vec::new(); { let Cache { search_index: ref mut index, orphan_methods: ref meths, paths: ref mut paths, ..} = cache; @@ -283,17 +286,21 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { } }; - // Prune the paths that do not appear in the index. - let mut unseen: HashSet = paths.keys().map(|&id| id).collect(); + // Reduce `NodeId` in paths into smaller sequential numbers, + // and prune the paths that do not appear in the index. for item in index.iter() { match item.parent { - Some(ref pid) => { unseen.remove(pid); } + Some(nodeid) => { + if !nodeid_to_pathid.contains_key(&nodeid) { + let pathid = pathid_to_nodeid.len(); + nodeid_to_pathid.insert(nodeid, pathid); + pathid_to_nodeid.push(nodeid); + } + } None => {} } } - for pid in unseen.iter() { - paths.remove(pid); - } + assert_eq!(nodeid_to_pathid.len(), pathid_to_nodeid.len()); } // Publish the search index @@ -308,23 +315,25 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { item.ty, item.name, item.path, item.desc.to_json().to_str())); match item.parent { - Some(id) => { - try!(write!(&mut w, ",parent:'{}'", id)); + Some(nodeid) => { + let pathid = *nodeid_to_pathid.find(&nodeid).unwrap(); + try!(write!(&mut w, ",parent:{}", pathid)); } None => {} } try!(write!(&mut w, "\\}")); } try!(write!(&mut w, "];")); - try!(write!(&mut w, "allPaths['{}'] = \\{", krate.name)); - for (i, (&id, &(ref fqp, short))) in cache.paths.iter().enumerate() { + try!(write!(&mut w, "allPaths['{}'] = [", krate.name)); + for (i, &nodeid) in pathid_to_nodeid.iter().enumerate() { + let &(ref fqp, short) = cache.paths.find(&nodeid).unwrap(); if i > 0 { try!(write!(&mut w, ",")); } - try!(write!(&mut w, "'{}':\\{type:'{}',name:'{}'\\}", - id, short, *fqp.last().unwrap())); + try!(write!(&mut w, "\\{type:'{}',name:'{}'\\}", + short, *fqp.last().unwrap())); } - try!(write!(&mut w, "\\};")); + try!(write!(&mut w, "];")); str::from_utf8(w.unwrap().as_slice()).unwrap().to_owned() }; From f1de04c7609ea31f76e445e3189dc6143f959f40 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Wed, 9 Apr 2014 16:49:31 +0900 Subject: [PATCH 2/5] rustdoc: Represent item types as a small number in the search index. Has negligible improvements with gzip, but saves about 7% without it. This also has an effect of changing the tie-breaking order of item types. --- src/librustdoc/html/format.rs | 18 +++--- src/librustdoc/html/item_type.rs | 97 ++++++++++++++++++++++++++++++ src/librustdoc/html/render.rs | 55 ++++++----------- src/librustdoc/html/static/main.js | 36 +++++++++-- src/librustdoc/lib.rs | 1 + 5 files changed, 158 insertions(+), 49 deletions(-) create mode 100644 src/librustdoc/html/item_type.rs diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 1457c454c5766..ca55d1f04ad2f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -24,6 +24,8 @@ use syntax::ast; use syntax::ast_util; use clean; +use html::item_type; +use html::item_type::ItemType; use html::render; use html::render::{cache_key, current_location_key}; @@ -172,17 +174,17 @@ fn external_path(w: &mut io::Writer, p: &clean::Path, print_all: bool, }, |_cache| { Some((Vec::from_slice(fqn), match kind { - clean::TypeStruct => "struct", - clean::TypeEnum => "enum", - clean::TypeFunction => "fn", - clean::TypeTrait => "trait", + clean::TypeStruct => item_type::Struct, + clean::TypeEnum => item_type::Enum, + clean::TypeFunction => item_type::Function, + clean::TypeTrait => item_type::Trait, })) }) } fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool, root: |&render::Cache, &[~str]| -> Option<~str>, - info: |&render::Cache| -> Option<(Vec<~str> , &'static str)>) + info: |&render::Cache| -> Option<(Vec<~str> , ItemType)>) -> fmt::Result { // The generics will get written to both the title and link @@ -252,12 +254,12 @@ fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool, url.push_str("/"); } match shortty { - "mod" => { + item_type::Module => { url.push_str(*fqp.last().unwrap()); url.push_str("/index.html"); } _ => { - url.push_str(shortty); + url.push_str(shortty.to_static_str()); url.push_str("."); url.push_str(*fqp.last().unwrap()); url.push_str(".html"); diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs new file mode 100644 index 0000000000000..f59e8cb248738 --- /dev/null +++ b/src/librustdoc/html/item_type.rs @@ -0,0 +1,97 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Item types. + +use std::fmt; +use clean; + +/// Item type. Corresponds to `clean::ItemEnum` variants. +/// +/// The search index uses item types encoded as smaller numbers which equal to +/// discriminants. JavaScript then is used to decode them into the original value. +/// Consequently, every change to this type should be synchronized to +/// the `itemTypes` mapping table in `static/main.js`. +#[deriving(Eq, Clone)] +pub enum ItemType { + Module = 0, + Struct = 1, + Enum = 2, + Function = 3, + Typedef = 4, + Static = 5, + Trait = 6, + Impl = 7, + ViewItem = 8, + TyMethod = 9, + Method = 10, + StructField = 11, + Variant = 12, + ForeignFunction = 13, + ForeignStatic = 14, + Macro = 15, +} + +impl ItemType { + pub fn to_static_str(&self) -> &'static str { + match *self { + Module => "mod", + Struct => "struct", + Enum => "enum", + Function => "fn", + Typedef => "typedef", + Static => "static", + Trait => "trait", + Impl => "impl", + ViewItem => "viewitem", + TyMethod => "tymethod", + Method => "method", + StructField => "structfield", + Variant => "variant", + ForeignFunction => "ffi", + ForeignStatic => "ffs", + Macro => "macro", + } + } +} + +impl fmt::Show for ItemType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.to_static_str().fmt(f) + } +} + +impl fmt::Unsigned for ItemType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (*self as uint).fmt(f) + } +} + +pub fn shortty(item: &clean::Item) -> ItemType { + match item.inner { + clean::ModuleItem(..) => Module, + clean::StructItem(..) => Struct, + clean::EnumItem(..) => Enum, + clean::FunctionItem(..) => Function, + clean::TypedefItem(..) => Typedef, + clean::StaticItem(..) => Static, + clean::TraitItem(..) => Trait, + clean::ImplItem(..) => Impl, + clean::ViewItemItem(..) => ViewItem, + clean::TyMethodItem(..) => TyMethod, + clean::MethodItem(..) => Method, + clean::StructFieldItem(..) => StructField, + clean::VariantItem(..) => Variant, + clean::ForeignFunctionItem(..) => ForeignFunction, + clean::ForeignStaticItem(..) => ForeignStatic, + clean::MacroItem(..) => Macro, + } +} + diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 0b9a42d8e34b7..d2763f494ea4c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -52,6 +52,8 @@ use rustc::util::nodemap::NodeSet; use clean; use doctree; use fold::DocFolder; +use html::item_type; +use html::item_type::{ItemType, shortty}; use html::format::{VisSpace, Method, FnStyleSpace}; use html::layout; use html::markdown; @@ -138,7 +140,7 @@ pub struct Cache { /// URLs when a type is being linked to. External paths are not located in /// this map because the `External` type itself has all the information /// necessary. - pub paths: HashMap , &'static str)>, + pub paths: HashMap , ItemType)>, /// This map contains information about all known traits of this crate. /// Implementations of a crate should inherit the documentation of the @@ -193,7 +195,7 @@ struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, } /// Struct representing one entry in the JS search index. These are all emitted /// by hand to a large JS file at the end of cache-creation. struct IndexItem { - ty: &'static str, + ty: ItemType, name: ~str, path: ~str, desc: ~str, @@ -311,7 +313,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { if i > 0 { try!(write!(&mut w, ",")); } - try!(write!(&mut w, "\\{ty:\"{}\",name:\"{}\",path:\"{}\",desc:{}", + try!(write!(&mut w, "\\{ty:{:u},name:\"{}\",path:\"{}\",desc:{}", item.ty, item.name, item.path, item.desc.to_json().to_str())); match item.parent { @@ -330,7 +332,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { if i > 0 { try!(write!(&mut w, ",")); } - try!(write!(&mut w, "\\{type:'{}',name:'{}'\\}", + try!(write!(&mut w, "\\{type:{:u},name:'{}'\\}", short, *fqp.last().unwrap())); } try!(write!(&mut w, "];")); @@ -622,12 +624,13 @@ impl DocFolder for Cache { } else { let last = self.parent_stack.last().unwrap(); let path = match self.paths.find(last) { - Some(&(_, "trait")) => + Some(&(_, item_type::Trait)) => Some(self.stack.slice_to(self.stack.len() - 1)), // The current stack not necessarily has correlation for // where the type was defined. On the other hand, // `paths` always has the right information if present. - Some(&(ref fqp, "struct")) | Some(&(ref fqp, "enum")) => + Some(&(ref fqp, item_type::Struct)) | + Some(&(ref fqp, item_type::Enum)) => Some(fqp.slice_to(fqp.len() - 1)), Some(..) => Some(self.stack.as_slice()), None => None @@ -687,7 +690,7 @@ impl DocFolder for Cache { clean::VariantItem(..) => { let mut stack = self.stack.clone(); stack.pop(); - self.paths.insert(item.id, (stack, "enum")); + self.paths.insert(item.id, (stack, item_type::Enum)); } _ => {} } @@ -845,7 +848,7 @@ impl Context { } title.push_str(" - Rust"); let page = layout::Page { - ty: shortty(it), + ty: shortty(it).to_static_str(), root_path: cx.root_path.as_slice(), title: title.as_slice(), }; @@ -899,27 +902,6 @@ impl Context { } } -fn shortty(item: &clean::Item) -> &'static str { - match item.inner { - clean::ModuleItem(..) => "mod", - clean::StructItem(..) => "struct", - clean::EnumItem(..) => "enum", - clean::FunctionItem(..) => "fn", - clean::TypedefItem(..) => "typedef", - clean::StaticItem(..) => "static", - clean::TraitItem(..) => "trait", - clean::ImplItem(..) => "impl", - clean::ViewItemItem(..) => "viewitem", - clean::TyMethodItem(..) => "tymethod", - clean::MethodItem(..) => "method", - clean::StructFieldItem(..) => "structfield", - clean::VariantItem(..) => "variant", - clean::ForeignFunctionItem(..) => "ffi", - clean::ForeignStaticItem(..) => "ffs", - clean::MacroItem(..) => "macro", - } -} - impl<'a> Item<'a> { fn ismodule(&self) -> bool { match self.item.inner { @@ -1009,7 +991,7 @@ impl<'a> fmt::Show for Item<'a> { fn item_path(item: &clean::Item) -> ~str { match item.inner { clean::ModuleItem(..) => *item.name.get_ref() + "/index.html", - _ => shortty(item) + "." + *item.name.get_ref() + ".html" + _ => shortty(item).to_static_str() + "." + *item.name.get_ref() + ".html" } } @@ -1095,13 +1077,13 @@ fn item_module(w: &mut Writer, cx: &Context, indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2)); debug!("{:?}", indices); - let mut curty = ""; + let mut curty = None; for &idx in indices.iter() { let myitem = &items[idx]; - let myty = shortty(myitem); + let myty = Some(shortty(myitem)); if myty != curty { - if curty != "" { + if curty.is_some() { try!(write!(w, "")); } curty = myty; @@ -1704,8 +1686,9 @@ impl<'a> fmt::Show for Sidebar<'a> { }; try!(write!(w, "

{}

", short, longty)); for item in items.iter() { + let curty = shortty(cur).to_static_str(); let class = if cur.name.get_ref() == item && - short == shortty(cur) { "current" } else { "" }; + short == curty { "current" } else { "" }; try!(write!(w, " fmt::Show for Sidebar<'a> { ty = short, tysel = short, class = class, - curty = shortty(cur), + curty = curty, name = item.as_slice())); } try!(write!(w, "
")); @@ -1735,7 +1718,7 @@ impl<'a> fmt::Show for Sidebar<'a> { fn build_sidebar(m: &clean::Module) -> HashMap<~str, Vec<~str> > { let mut map = HashMap::new(); for item in m.items.iter() { - let short = shortty(item); + let short = shortty(item).to_static_str(); let myname = match item.name { None => continue, Some(ref s) => s.to_owned(), diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 1904ab27d17d9..43fb02f62be2e 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -135,7 +135,7 @@ function execQuery(query, max, searchWords) { var valLower = query.query.toLowerCase(), val = valLower, - typeFilter = query.type, + typeFilter = itemTypeFromName(query.type), results = [], split = valLower.split("::"); @@ -156,7 +156,7 @@ for (var i = 0; i < nSearchWords; i += 1) { if (searchWords[i] === val) { // filter type: ... queries - if (!typeFilter || typeFilter === searchIndex[i].ty) { + if (typeFilter < 0 || typeFilter === searchIndex[i].ty) { results.push({id: i, index: -1}); } } @@ -174,7 +174,7 @@ searchWords[j].replace(/_/g, "").indexOf(val) > -1) { // filter type: ... queries - if (!typeFilter || typeFilter === searchIndex[j].ty) { + if (typeFilter < 0 || typeFilter === searchIndex[j].ty) { results.push({id: j, index: searchWords[j].replace(/_/g, "").indexOf(val)}); } } @@ -405,7 +405,7 @@ shown.push(item); name = item.name; - type = item.ty; + type = itemTypes[item.ty]; output += ''; @@ -427,7 +427,7 @@ output += item.path + '::' + myparent.name + ':: Date: Wed, 9 Apr 2014 17:16:09 +0900 Subject: [PATCH 3/5] rustdoc: Use an array instead of an object for the search index. `buildIndex` JS function recovers them into the original object form. This greatly reduces the size of the uncompressed search index (27%), while this effect is less visible after gzipped (~5%). --- src/librustdoc/html/render.rs | 8 ++++---- src/librustdoc/html/static/main.js | 20 ++++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d2763f494ea4c..aa54642262b83 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -313,17 +313,17 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { if i > 0 { try!(write!(&mut w, ",")); } - try!(write!(&mut w, "\\{ty:{:u},name:\"{}\",path:\"{}\",desc:{}", + try!(write!(&mut w, r#"[{:u},"{}","{}",{}"#, item.ty, item.name, item.path, item.desc.to_json().to_str())); match item.parent { Some(nodeid) => { let pathid = *nodeid_to_pathid.find(&nodeid).unwrap(); - try!(write!(&mut w, ",parent:{}", pathid)); + try!(write!(&mut w, ",{}", pathid)); } None => {} } - try!(write!(&mut w, "\\}")); + try!(write!(&mut w, "]")); } try!(write!(&mut w, "];")); try!(write!(&mut w, "allPaths['{}'] = [", krate.name)); @@ -332,7 +332,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { if i > 0 { try!(write!(&mut w, ",")); } - try!(write!(&mut w, "\\{type:{:u},name:'{}'\\}", + try!(write!(&mut w, r#"[{:u},"{}"]"#, short, *fqp.last().unwrap())); } try!(write!(&mut w, "];")); diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 43fb02f62be2e..692ab5b9ac286 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -294,7 +294,7 @@ if ((validate) && (name.toLowerCase().indexOf(keys[i]) > -1 || path.toLowerCase().indexOf(keys[i]) > -1 || - parent.name.toLowerCase().indexOf(keys[i]) > -1)) + parent[1].toLowerCase().indexOf(keys[i]) > -1)) { validate = true; } else { @@ -423,12 +423,14 @@ '">' + name + ''; } else if (item.parent !== undefined) { var myparent = allPaths[item.crate][item.parent]; + var parentType = myparent[0]; + var parentName = myparent[1]; var anchor = '#' + type + '.' + name; - output += item.path + '::' + myparent.name + + output += item.path + '::' + parentName + '::' + name + ''; @@ -545,10 +547,12 @@ // all other search operations have access to this cached data for // faster analysis operations for (i = 0; i < len; i += 1) { - rawSearchIndex[crate][i].crate = crate; - searchIndex.push(rawSearchIndex[crate][i]); - if (typeof rawSearchIndex[crate][i].name === "string") { - var word = rawSearchIndex[crate][i].name.toLowerCase(); + var rawRow = rawSearchIndex[crate][i]; + var row = {crate: crate, ty: rawRow[0], name: rawRow[1], + path: rawRow[2], desc: rawRow[3], parent: rawRow[4]}; + searchIndex.push(row); + if (typeof row.name === "string") { + var word = row.name.toLowerCase(); searchWords.push(word); } else { searchWords.push(""); From 9eb336a0206178f52146d41dd152166233df703b Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Thu, 10 Apr 2014 01:27:35 +0900 Subject: [PATCH 4/5] rustdoc: Get rid of `allPaths` global variable by merging it into `searchIndex`. --- src/librustdoc/html/render.rs | 9 +++--- src/librustdoc/html/static/main.js | 44 ++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index aa54642262b83..d7739daad57e7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -308,7 +308,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { // Publish the search index let index = { let mut w = MemWriter::new(); - try!(write!(&mut w, "searchIndex['{}'] = [", krate.name)); + try!(write!(&mut w, r#"searchIndex['{}'] = \{"items":["#, krate.name)); for (i, item) in cache.search_index.iter().enumerate() { if i > 0 { try!(write!(&mut w, ",")); @@ -325,8 +325,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { } try!(write!(&mut w, "]")); } - try!(write!(&mut w, "];")); - try!(write!(&mut w, "allPaths['{}'] = [", krate.name)); + try!(write!(&mut w, r#"],"paths":["#)); for (i, &nodeid) in pathid_to_nodeid.iter().enumerate() { let &(ref fqp, short) = cache.paths.find(&nodeid).unwrap(); if i > 0 { @@ -335,7 +334,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { try!(write!(&mut w, r#"[{:u},"{}"]"#, short, *fqp.last().unwrap())); } - try!(write!(&mut w, "];")); + try!(write!(&mut w, r"]\};")); str::from_utf8(w.unwrap().as_slice()).unwrap().to_owned() }; @@ -371,7 +370,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { } } let mut w = try!(File::create(&dst)); - try!(writeln!(&mut w, r"var searchIndex = \{\}; var allPaths = \{\};")); + try!(writeln!(&mut w, r"var searchIndex = \{\};")); for index in all_indexes.iter() { try!(writeln!(&mut w, "{}", *index)); } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 692ab5b9ac286..9ef25c50206f6 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -9,7 +9,7 @@ // except according to those terms. /*jslint browser: true, es5: true */ -/*globals $: true, rootPath: true, allPaths: true */ +/*globals $: true, rootPath: true */ (function() { "use strict"; @@ -258,7 +258,7 @@ var result = results[i], name = result.item.name.toLowerCase(), path = result.item.path.toLowerCase(), - parent = allPaths[result.item.crate][result.item.parent]; + parent = result.item.parent; var valid = validateResult(name, path, split, parent); if (!valid) { @@ -294,7 +294,7 @@ if ((validate) && (name.toLowerCase().indexOf(keys[i]) > -1 || path.toLowerCase().indexOf(keys[i]) > -1 || - parent[1].toLowerCase().indexOf(keys[i]) > -1)) + parent.name.toLowerCase().indexOf(keys[i]) > -1)) { validate = true; } else { @@ -422,15 +422,13 @@ '/index.html" class="' + type + '">' + name + ''; } else if (item.parent !== undefined) { - var myparent = allPaths[item.crate][item.parent]; - var parentType = myparent[0]; - var parentName = myparent[1]; + var myparent = item.parent; var anchor = '#' + type + '.' + name; - output += item.path + '::' + parentName + + output += item.path + '::' + myparent.name + '::' + name + ''; @@ -538,18 +536,36 @@ var searchWords = []; for (var crate in rawSearchIndex) { if (!rawSearchIndex.hasOwnProperty(crate)) { continue } - var len = rawSearchIndex[crate].length; - var i = 0; + // an array of [(Number) item type, + // (String) name, + // (String) full path, + // (String) description, + // (optional Number) the parent path index to `paths`] + var items = rawSearchIndex[crate].items; + // an array of [(Number) item type, + // (String) name] + var paths = rawSearchIndex[crate].paths; + + // convert `paths` into an object form + var len = paths.length; + for (var i = 0; i < len; ++i) { + paths[i] = {ty: paths[i][0], name: paths[i][1]}; + } + + // convert `items` 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 - for (i = 0; i < len; i += 1) { - var rawRow = rawSearchIndex[crate][i]; + var len = items.length; + for (var i = 0; i < len; i += 1) { + var rawRow = items[i]; var row = {crate: crate, ty: rawRow[0], name: rawRow[1], - path: rawRow[2], desc: rawRow[3], parent: rawRow[4]}; + path: rawRow[2], desc: rawRow[3], + parent: paths[rawRow[4]]}; searchIndex.push(row); if (typeof row.name === "string") { var word = row.name.toLowerCase(); From 8f5d71cf71849bea25f87836cec1b06b476baf37 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Thu, 10 Apr 2014 02:24:00 +0900 Subject: [PATCH 5/5] rustdoc: Omit repeated paths in the search index. Since the items roughly follow the lexical order, there are many consecutive items with the same path value which can be easily compressed. For the library and compiler docs, this commit decreases the index size by 26% and 6% before and after gzip, respectively. --- src/librustdoc/html/render.rs | 16 +++++++++++++++- src/librustdoc/html/static/main.js | 6 ++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d7739daad57e7..669a489a4fb6e 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -309,12 +309,23 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { let index = { let mut w = MemWriter::new(); try!(write!(&mut w, r#"searchIndex['{}'] = \{"items":["#, krate.name)); + + let mut lastpath = ~""; for (i, item) in cache.search_index.iter().enumerate() { + // Omit the path if it is same to that of the prior item. + let path; + if lastpath == item.path { + path = ""; + } else { + lastpath = item.path.clone(); + path = item.path.as_slice(); + }; + if i > 0 { try!(write!(&mut w, ",")); } try!(write!(&mut w, r#"[{:u},"{}","{}",{}"#, - item.ty, item.name, item.path, + item.ty, item.name, path, item.desc.to_json().to_str())); match item.parent { Some(nodeid) => { @@ -325,7 +336,9 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { } try!(write!(&mut w, "]")); } + try!(write!(&mut w, r#"],"paths":["#)); + for (i, &nodeid) in pathid_to_nodeid.iter().enumerate() { let &(ref fqp, short) = cache.paths.find(&nodeid).unwrap(); if i > 0 { @@ -334,6 +347,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { try!(write!(&mut w, r#"[{:u},"{}"]"#, short, *fqp.last().unwrap())); } + try!(write!(&mut w, r"]\};")); str::from_utf8(w.unwrap().as_slice()).unwrap().to_owned() diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 9ef25c50206f6..4b79ae89eef6b 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -539,7 +539,7 @@ // an array of [(Number) item type, // (String) name, - // (String) full path, + // (String) full path or empty string for previous path, // (String) description, // (optional Number) the parent path index to `paths`] var items = rawSearchIndex[crate].items; @@ -561,10 +561,11 @@ // all other search operations have access to this cached data for // faster analysis operations var len = items.length; + var lastPath = ""; for (var i = 0; i < len; i += 1) { var rawRow = items[i]; var row = {crate: crate, ty: rawRow[0], name: rawRow[1], - path: rawRow[2], desc: rawRow[3], + path: rawRow[2] || lastPath, desc: rawRow[3], parent: paths[rawRow[4]]}; searchIndex.push(row); if (typeof row.name === "string") { @@ -573,6 +574,7 @@ } else { searchWords.push(""); } + lastPath = row.path; } } return searchWords;