Skip to content

Commit 3f21c90

Browse files
committed
rustdoc-search: use stringdex partitioned search tree
1 parent d9de05f commit 3f21c90

File tree

94 files changed

+6991
-4257
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+6991
-4257
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4725,6 +4725,7 @@ dependencies = [
47254725
"serde_json",
47264726
"sha2",
47274727
"smallvec",
4728+
"stringdex",
47284729
"tempfile",
47294730
"threadpool",
47304731
"tracing",
@@ -5132,6 +5133,15 @@ dependencies = [
51325133
"quote",
51335134
]
51345135

5136+
[[package]]
5137+
name = "stringdex"
5138+
version = "0.0.1-alpha1"
5139+
source = "registry+https://github.com/rust-lang/crates.io-index"
5140+
checksum = "0a9ed1635ee8462c251e9c85aa1dd345419bd004bb75ac9a96e4c442a7974683"
5141+
dependencies = [
5142+
"stacker",
5143+
]
5144+
51355145
[[package]]
51365146
name = "strsim"
51375147
version = "0.11.1"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8.6.0
1+
8.6.0

src/etc/htmldocck.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import re
1616
import shlex
1717
from collections import namedtuple
18+
from pathlib import Path
1819

1920
try:
2021
from html.parser import HTMLParser
@@ -242,6 +243,11 @@ def resolve_path(self, path):
242243
return self.last_path
243244

244245
def get_absolute_path(self, path):
246+
if "*" in path:
247+
paths = list(Path(self.root).glob(path))
248+
if len(paths) != 1:
249+
raise FailedCheck("glob path does not resolve to one file")
250+
path = str(paths[0])
245251
return os.path.join(self.root, path)
246252

247253
def get_file(self, path):

src/librustdoc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ rustdoc-json-types = { path = "../rustdoc-json-types" }
2121
serde = { version = "1.0", features = ["derive"] }
2222
serde_json = "1.0"
2323
smallvec = "1.8.1"
24+
stringdex = "0.0.1-alpha1"
2425
tempfile = "3"
2526
threadpool = "1.8.1"
2627
tracing = "0.1"

src/librustdoc/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ fn main() {
1010
"static/css/normalize.css",
1111
"static/js/main.js",
1212
"static/js/search.js",
13+
"static/js/stringdex.js",
1314
"static/js/settings.js",
1415
"static/js/src-script.js",
1516
"static/js/storage.js",

src/librustdoc/formats/cache.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::mem;
22

3-
use rustc_ast::join_path_syms;
43
use rustc_attr_data_structures::StabilityLevel;
54
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
65
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet};
@@ -558,7 +557,6 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
558557
clean::ItemKind::ImportItem(import) => import.source.did.unwrap_or(item_def_id),
559558
_ => item_def_id,
560559
};
561-
let path = join_path_syms(parent_path);
562560
let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() {
563561
item_id.as_def_id()
564562
} else {
@@ -577,11 +575,11 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
577575
ty: item.type_(),
578576
defid: Some(defid),
579577
name,
580-
path,
578+
module_path: parent_path.to_vec(),
581579
desc,
582580
parent: parent_did,
583581
parent_idx: None,
584-
exact_path: None,
582+
exact_module_path: None,
585583
impl_id,
586584
search_type,
587585
aliases,

src/librustdoc/formats/item_type.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::fmt;
44

55
use rustc_hir::def::{CtorOf, DefKind};
66
use rustc_span::hygiene::MacroKind;
7-
use serde::{Serialize, Serializer};
7+
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
88

99
use crate::clean;
1010

@@ -68,6 +68,52 @@ impl Serialize for ItemType {
6868
}
6969
}
7070

71+
impl<'de> Deserialize<'de> for ItemType {
72+
fn deserialize<D>(deserializer: D) -> Result<ItemType, D::Error>
73+
where
74+
D: Deserializer<'de>,
75+
{
76+
struct ItemTypeVisitor;
77+
impl<'de> de::Visitor<'de> for ItemTypeVisitor {
78+
type Value = ItemType;
79+
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80+
write!(formatter, "an integer between 0 and 25")
81+
}
82+
fn visit_u64<E: de::Error>(self, v: u64) -> Result<ItemType, E> {
83+
Ok(match v {
84+
0 => ItemType::Keyword,
85+
1 => ItemType::Primitive,
86+
2 => ItemType::Module,
87+
3 => ItemType::ExternCrate,
88+
4 => ItemType::Import,
89+
5 => ItemType::Struct,
90+
6 => ItemType::Enum,
91+
7 => ItemType::Function,
92+
8 => ItemType::TypeAlias,
93+
9 => ItemType::Static,
94+
10 => ItemType::Trait,
95+
11 => ItemType::Impl,
96+
12 => ItemType::TyMethod,
97+
13 => ItemType::Method,
98+
14 => ItemType::StructField,
99+
15 => ItemType::Variant,
100+
16 => ItemType::Macro,
101+
17 => ItemType::AssocType,
102+
18 => ItemType::Constant,
103+
19 => ItemType::AssocConst,
104+
20 => ItemType::Union,
105+
21 => ItemType::ForeignType,
106+
23 => ItemType::ProcAttribute,
107+
24 => ItemType::ProcDerive,
108+
25 => ItemType::TraitAlias,
109+
_ => return Err(E::missing_field("unknown number")),
110+
})
111+
}
112+
}
113+
deserializer.deserialize_any(ItemTypeVisitor)
114+
}
115+
}
116+
71117
impl<'a> From<&'a clean::Item> for ItemType {
72118
fn from(item: &'a clean::Item) -> ItemType {
73119
let kind = match &item.kind {

src/librustdoc/html/render/mod.rs

Lines changed: 122 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,11 @@ pub(crate) struct IndexItem {
132132
pub(crate) ty: ItemType,
133133
pub(crate) defid: Option<DefId>,
134134
pub(crate) name: Symbol,
135-
pub(crate) path: String,
135+
pub(crate) module_path: Vec<Symbol>,
136136
pub(crate) desc: String,
137137
pub(crate) parent: Option<DefId>,
138-
pub(crate) parent_idx: Option<isize>,
139-
pub(crate) exact_path: Option<String>,
138+
pub(crate) parent_idx: Option<usize>,
139+
pub(crate) exact_module_path: Option<Vec<Symbol>>,
140140
pub(crate) impl_id: Option<DefId>,
141141
pub(crate) search_type: Option<IndexItemFunctionType>,
142142
pub(crate) aliases: Box<[Symbol]>,
@@ -193,6 +193,62 @@ impl RenderType {
193193
write_optional_id(self.id, string);
194194
}
195195
}
196+
fn read_from_bytes(string: &[u8]) -> (RenderType, usize) {
197+
let mut i = 0;
198+
if string[i] == b'{' {
199+
i += 1;
200+
let (id, offset) = RenderTypeId::read_from_bytes(&string[i..]);
201+
i += offset;
202+
let generics = if string[i] == b'{' {
203+
i += 1;
204+
let mut generics = Vec::new();
205+
while string[i] != b'}' {
206+
let (ty, offset) = RenderType::read_from_bytes(&string[i..]);
207+
i += offset;
208+
generics.push(ty);
209+
}
210+
assert!(string[i] == b'}');
211+
i += 1;
212+
Some(generics)
213+
} else {
214+
None
215+
};
216+
let bindings = if string[i] == b'{' {
217+
i += 1;
218+
let mut bindings = Vec::new();
219+
while string[i] == b'{' {
220+
i += 1;
221+
let (binding, boffset) = RenderTypeId::read_from_bytes(&string[i..]);
222+
i += boffset;
223+
let mut bconstraints = Vec::new();
224+
assert!(string[i] == b'{');
225+
i += 1;
226+
while string[i] != b'}' {
227+
let (constraint, coffset) = RenderType::read_from_bytes(&string[i..]);
228+
i += coffset;
229+
bconstraints.push(constraint);
230+
}
231+
assert!(string[i] == b'}');
232+
i += 1;
233+
bindings.push((binding.unwrap(), bconstraints));
234+
assert!(string[i] == b'}');
235+
i += 1;
236+
}
237+
assert!(string[i] == b'}');
238+
i += 1;
239+
Some(bindings)
240+
} else {
241+
None
242+
};
243+
assert!(string[i] == b'}');
244+
i += 1;
245+
(RenderType { id, generics, bindings }, i)
246+
} else {
247+
let (id, offset) = RenderTypeId::read_from_bytes(string);
248+
i += offset;
249+
(RenderType { id, generics: None, bindings: None }, i)
250+
}
251+
}
196252
}
197253

198254
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -214,7 +270,20 @@ impl RenderTypeId {
214270
RenderTypeId::Index(idx) => (*idx).try_into().unwrap(),
215271
_ => panic!("must convert render types to indexes before serializing"),
216272
};
217-
search_index::encode::write_vlqhex_to_string(id, string);
273+
search_index::encode::write_signed_vlqhex_to_string(id, string);
274+
}
275+
fn read_from_bytes(string: &[u8]) -> (Option<RenderTypeId>, usize) {
276+
let Some((value, offset)) = search_index::encode::read_signed_vlqhex_from_string(string)
277+
else {
278+
return (None, 0);
279+
};
280+
let value = isize::try_from(value).unwrap();
281+
let ty = match value {
282+
..0 => Some(RenderTypeId::Index(value)),
283+
0 => None,
284+
1.. => Some(RenderTypeId::Index(value - 1)),
285+
};
286+
(ty, offset)
218287
}
219288
}
220289

@@ -228,12 +297,55 @@ pub(crate) struct IndexItemFunctionType {
228297
}
229298

230299
impl IndexItemFunctionType {
231-
fn write_to_string<'a>(
232-
&'a self,
233-
string: &mut String,
234-
backref_queue: &mut VecDeque<&'a IndexItemFunctionType>,
235-
) {
236-
assert!(backref_queue.len() <= 16);
300+
fn read_from_string_without_param_names(string: &[u8]) -> (IndexItemFunctionType, usize) {
301+
let mut i = 0;
302+
if string[i] == b'`' {
303+
return (
304+
IndexItemFunctionType {
305+
inputs: Vec::new(),
306+
output: Vec::new(),
307+
where_clause: Vec::new(),
308+
param_names: Vec::new(),
309+
},
310+
1,
311+
);
312+
}
313+
assert_eq!(b'{', string[i]);
314+
i += 1;
315+
fn read_args_from_string(string: &[u8]) -> (Vec<RenderType>, usize) {
316+
let mut i = 0;
317+
let mut params = Vec::new();
318+
if string[i] == b'{' {
319+
// multiple params
320+
i += 1;
321+
while string[i] != b'}' {
322+
let (ty, offset) = RenderType::read_from_bytes(&string[i..]);
323+
i += offset;
324+
params.push(ty);
325+
}
326+
i += 1;
327+
} else if string[i] != b'}' {
328+
let (tyid, offset) = RenderTypeId::read_from_bytes(&string[i..]);
329+
params.push(RenderType { id: tyid, generics: None, bindings: None });
330+
i += offset;
331+
}
332+
(params, i)
333+
}
334+
let (inputs, offset) = read_args_from_string(&string[i..]);
335+
i += offset;
336+
let (output, offset) = read_args_from_string(&string[i..]);
337+
i += offset;
338+
let mut where_clause = Vec::new();
339+
while string[i] != b'}' {
340+
let (constraint, offset) = read_args_from_string(&string[i..]);
341+
i += offset;
342+
where_clause.push(constraint);
343+
}
344+
assert_eq!(b'}', string[i], "{} {}", String::from_utf8_lossy(&string), i);
345+
i += 1;
346+
(IndexItemFunctionType { inputs, output, where_clause, param_names: Vec::new() }, i)
347+
}
348+
fn write_to_string_without_param_names<'a>(&'a self, string: &mut String) {
237349
// If we couldn't figure out a type, just write 0,
238350
// which is encoded as `` ` `` (see RenderTypeId::write_to_string).
239351
let has_missing = self
@@ -243,18 +355,7 @@ impl IndexItemFunctionType {
243355
.any(|i| i.id.is_none() && i.generics.is_none());
244356
if has_missing {
245357
string.push('`');
246-
} else if let Some(idx) = backref_queue.iter().position(|other| *other == self) {
247-
// The backref queue has 16 items, so backrefs use
248-
// a single hexit, disjoint from the ones used for numbers.
249-
string.push(
250-
char::try_from('0' as u32 + u32::try_from(idx).unwrap())
251-
.expect("last possible value is '?'"),
252-
);
253358
} else {
254-
backref_queue.push_front(self);
255-
if backref_queue.len() > 16 {
256-
backref_queue.pop_back();
257-
}
258359
string.push('{');
259360
match &self.inputs[..] {
260361
[one] if one.generics.is_none() && one.bindings.is_none() => {

0 commit comments

Comments
 (0)