Skip to content

Commit 81f673d

Browse files
committed
Simplify search-index serialization
1 parent 810a514 commit 81f673d

File tree

1 file changed

+94
-112
lines changed

1 file changed

+94
-112
lines changed

src/librustdoc/html/render.rs

Lines changed: 94 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use std::sync::Arc;
5252

5353
use externalfiles::ExternalHtml;
5454

55-
use serialize::json::as_json;
55+
use serialize::json::{ToJson, Json, as_json};
5656
use syntax::{abi, ast};
5757
use syntax::feature_gate::UnstableFeatures;
5858
use rustc::middle::cstore::LOCAL_CRATE;
@@ -290,22 +290,40 @@ struct IndexItem {
290290
path: String,
291291
desc: String,
292292
parent: Option<DefId>,
293+
parent_idx: Option<usize>,
293294
search_type: Option<IndexItemFunctionType>,
294295
}
295296

297+
impl ToJson for IndexItem {
298+
fn to_json(&self) -> Json {
299+
assert_eq!(self.parent.is_some(), self.parent_idx.is_some());
300+
301+
let mut data = Vec::with_capacity(6);
302+
data.push((self.ty as usize).to_json());
303+
data.push(self.name.to_json());
304+
data.push(self.path.to_json());
305+
data.push(self.desc.to_json());
306+
data.push(self.parent_idx.to_json());
307+
data.push(self.search_type.to_json());
308+
309+
Json::Array(data)
310+
}
311+
}
312+
296313
/// A type used for the search index.
297314
struct Type {
298315
name: Option<String>,
299316
}
300317

301-
impl fmt::Display for Type {
302-
/// Formats type as {name: $name}.
303-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
304-
// Wrapping struct fmt should never call us when self.name is None,
305-
// but just to be safe we write `null` in that case.
318+
impl ToJson for Type {
319+
fn to_json(&self) -> Json {
306320
match self.name {
307-
Some(ref n) => write!(f, "{{\"name\":\"{}\"}}", n),
308-
None => write!(f, "null")
321+
Some(ref name) => {
322+
let mut data = BTreeMap::new();
323+
data.insert("name".to_owned(), name.to_json());
324+
Json::Object(data)
325+
},
326+
None => Json::Null
309327
}
310328
}
311329
}
@@ -316,26 +334,17 @@ struct IndexItemFunctionType {
316334
output: Option<Type>
317335
}
318336

319-
impl fmt::Display for IndexItemFunctionType {
320-
/// Formats a full fn type as a JSON {inputs: [Type], outputs: Type/null}.
321-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
337+
impl ToJson for IndexItemFunctionType {
338+
fn to_json(&self) -> Json {
322339
// If we couldn't figure out a type, just write `null`.
323-
if self.inputs.iter().any(|ref i| i.name.is_none()) ||
324-
(self.output.is_some() && self.output.as_ref().unwrap().name.is_none()) {
325-
return write!(f, "null")
340+
if self.inputs.iter().chain(self.output.iter()).any(|ref i| i.name.is_none()) {
341+
Json::Null
342+
} else {
343+
let mut data = BTreeMap::new();
344+
data.insert("inputs".to_owned(), self.inputs.to_json());
345+
data.insert("output".to_owned(), self.output.to_json());
346+
Json::Object(data)
326347
}
327-
328-
let inputs: Vec<String> = self.inputs.iter().map(|ref t| {
329-
format!("{}", t)
330-
}).collect();
331-
try!(write!(f, "{{\"inputs\":[{}],\"output\":", inputs.join(",")));
332-
333-
match self.output {
334-
Some(ref t) => try!(write!(f, "{}", t)),
335-
None => try!(write!(f, "null"))
336-
};
337-
338-
Ok(try!(write!(f, "}}")))
339348
}
340349
}
341350

@@ -537,104 +546,76 @@ pub fn run(mut krate: clean::Crate,
537546
/// Build the search index from the collected metadata
538547
fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
539548
let mut nodeid_to_pathid = HashMap::new();
540-
let mut pathid_to_nodeid = Vec::new();
541-
{
542-
let Cache { ref mut search_index,
543-
ref orphan_methods,
544-
ref mut paths, .. } = *cache;
545-
546-
// Attach all orphan methods to the type's definition if the type
547-
// has since been learned.
548-
for &(did, ref item) in orphan_methods {
549-
match paths.get(&did) {
550-
Some(&(ref fqp, _)) => {
551-
// Needed to determine `self` type.
552-
let parent_basename = Some(fqp[fqp.len() - 1].clone());
553-
search_index.push(IndexItem {
554-
ty: shortty(item),
555-
name: item.name.clone().unwrap(),
556-
path: fqp[..fqp.len() - 1].join("::"),
557-
desc: Escape(&shorter(item.doc_value())).to_string(),
558-
parent: Some(did),
559-
search_type: get_index_search_type(&item, parent_basename),
560-
});
561-
},
562-
None => {}
563-
}
564-
}
565-
566-
// Reduce `NodeId` in paths into smaller sequential numbers,
567-
// and prune the paths that do not appear in the index.
568-
for item in search_index.iter() {
569-
match item.parent {
570-
Some(nodeid) => {
571-
if !nodeid_to_pathid.contains_key(&nodeid) {
572-
let pathid = pathid_to_nodeid.len();
573-
nodeid_to_pathid.insert(nodeid, pathid);
574-
pathid_to_nodeid.push(nodeid);
575-
}
576-
}
577-
None => {}
578-
}
549+
let mut crate_items = Vec::with_capacity(cache.search_index.len());
550+
let mut crate_paths = Vec::<Json>::new();
551+
552+
let Cache { ref mut search_index,
553+
ref orphan_methods,
554+
ref mut paths, .. } = *cache;
555+
556+
// Attach all orphan methods to the type's definition if the type
557+
// has since been learned.
558+
for &(did, ref item) in orphan_methods {
559+
match paths.get(&did) {
560+
Some(&(ref fqp, _)) => {
561+
// Needed to determine `self` type.
562+
let parent_basename = Some(fqp[fqp.len() - 1].clone());
563+
search_index.push(IndexItem {
564+
ty: shortty(item),
565+
name: item.name.clone().unwrap(),
566+
path: fqp[..fqp.len() - 1].join("::"),
567+
desc: Escape(&shorter(item.doc_value())).to_string(),
568+
parent: Some(did),
569+
parent_idx: None,
570+
search_type: get_index_search_type(&item, parent_basename),
571+
});
572+
},
573+
None => {}
579574
}
580-
assert_eq!(nodeid_to_pathid.len(), pathid_to_nodeid.len());
581575
}
582576

583-
// Collect the index into a string
584-
let mut w = io::Cursor::new(Vec::new());
585-
let krate_doc = krate.module.as_ref().map(|module| {
586-
Escape(&shorter(module.doc_value())).to_string()
587-
}).unwrap_or("".to_owned());
577+
// Reduce `NodeId` in paths into smaller sequential numbers,
578+
// and prune the paths that do not appear in the index.
579+
let mut lastpath = String::new();
580+
let mut lastpathid = 0usize;
581+
582+
for item in search_index {
583+
item.parent_idx = item.parent.map(|nodeid| {
584+
if nodeid_to_pathid.contains_key(&nodeid) {
585+
*nodeid_to_pathid.get(&nodeid).unwrap()
586+
} else {
587+
let pathid = lastpathid;
588+
nodeid_to_pathid.insert(nodeid, pathid);
589+
lastpathid += 1;
588590

589-
write!(&mut w, r#"searchIndex[{}] = {{doc: {}, "items":["#,
590-
as_json(&krate.name),
591-
as_json(&krate_doc)).unwrap();
591+
let &(ref fqp, short) = paths.get(&nodeid).unwrap();
592+
crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json());
593+
pathid
594+
}
595+
});
592596

593-
let mut lastpath = "".to_string();
594-
for (i, item) in cache.search_index.iter().enumerate() {
595-
// Omit the path if it is same to that of the prior item.
596-
let path;
597+
// Omit the parent path if it is same to that of the prior item.
597598
if lastpath == item.path {
598-
path = "";
599+
item.path.clear();
599600
} else {
600-
lastpath = item.path.to_string();
601-
path = &item.path;
602-
};
603-
604-
if i > 0 {
605-
write!(&mut w, ",").unwrap();
606-
}
607-
write!(&mut w, "[{},{},{},{}",
608-
item.ty as usize,
609-
as_json(&item.name), as_json(&path), as_json(&item.desc)).unwrap();
610-
match item.parent {
611-
Some(nodeid) => {
612-
let pathid = *nodeid_to_pathid.get(&nodeid).unwrap();
613-
write!(&mut w, ",{}", pathid).unwrap();
614-
}
615-
None => write!(&mut w, ",null").unwrap()
616-
}
617-
match item.search_type {
618-
Some(ref t) => write!(&mut w, ",{}", t).unwrap(),
619-
None => write!(&mut w, ",null").unwrap()
601+
lastpath = item.path.clone();
620602
}
621-
write!(&mut w, "]").unwrap();
603+
crate_items.push(item.to_json());
622604
}
623605

624-
write!(&mut w, r#"],"paths":["#).unwrap();
625-
626-
for (i, &did) in pathid_to_nodeid.iter().enumerate() {
627-
let &(ref fqp, short) = cache.paths.get(&did).unwrap();
628-
if i > 0 {
629-
write!(&mut w, ",").unwrap();
630-
}
631-
write!(&mut w, r#"[{},"{}"]"#,
632-
short as usize, *fqp.last().unwrap()).unwrap();
633-
}
606+
let crate_doc = krate.module.as_ref().map(|module| {
607+
Escape(&shorter(module.doc_value())).to_string()
608+
}).unwrap_or(String::new());
634609

635-
write!(&mut w, "]}};").unwrap();
610+
let mut crate_data = BTreeMap::new();
611+
crate_data.insert("doc".to_owned(), Json::String(crate_doc));
612+
crate_data.insert("items".to_owned(), Json::Array(crate_items));
613+
crate_data.insert("paths".to_owned(), Json::Array(crate_paths));
636614

637-
String::from_utf8(w.into_inner()).unwrap()
615+
// Collect the index into a string
616+
format!("searchIndex[{}] = {};",
617+
as_json(&krate.name),
618+
Json::Object(crate_data))
638619
}
639620

640621
fn write_shared(cx: &Context,
@@ -1073,6 +1054,7 @@ impl DocFolder for Cache {
10731054
path: path.join("::").to_string(),
10741055
desc: Escape(&shorter(item.doc_value())).to_string(),
10751056
parent: parent,
1057+
parent_idx: None,
10761058
search_type: get_index_search_type(&item, parent_basename),
10771059
});
10781060
}

0 commit comments

Comments
 (0)