Skip to content

Commit 3f23e98

Browse files
committed
big refactor: crate IDs always go alongside item IDs now
This makes it impossible to try to access an item with the wrong crate ID. Also this change makes us pass around references much more than owned things, so it cuts down on cloning a ton, which is nice.
1 parent 9789922 commit 3f23e98

File tree

4 files changed

+115
-161
lines changed

4 files changed

+115
-161
lines changed

src/analysis.rs

+72-68
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ use std::process::Command;
77
use anyhow::Context;
88
use rayon::prelude::*;
99

10-
pub type Id = rustdoc_types::Id;
11-
1210
/// Write the analysis data to a subdirectory under target/ with this name.
1311
const SUBDIR: &str = "rsbrowse";
1412

13+
const EMPTY_ID: &rustdoc_types::Id = &rustdoc_types::Id(String::new());
14+
1515
pub struct Analysis {
1616
pub crates: HashMap<String, rustdoc_types::Crate>,
1717
}
@@ -86,93 +86,80 @@ impl Analysis {
8686
Ok(Self { crates })
8787
}
8888

89-
pub fn crate_ids(&self) -> impl Iterator<Item = CrateId> + '_ {
90-
/*let mut ids = vec![];
91-
92-
for c in self.crates.values() {
93-
let name = c.index.iter()
94-
.find_map(|(_id, item)| {
95-
match &item.inner {
96-
rustdoc_types::ItemEnum::Module(m) if m.is_crate && item.crate_id == 0 => {
97-
Some(item.name.clone().expect("crate module should have a name"))
98-
}
99-
_ => None
100-
}
101-
})
102-
.expect("should have an index item for the local crate");
103-
104-
ids.push(CrateId { name });
105-
}*/
106-
89+
pub fn crate_ids(&self) -> impl Iterator<Item = ItemId> + '_ {
10790
self.crates
10891
.values()
10992
.flat_map(|crate_| &crate_.index)
11093
.filter_map(|(_id, item)| match &item.inner {
11194
rustdoc_types::ItemEnum::Module(m) if m.is_crate && item.crate_id == 0 => {
112-
let name = item.name.clone().expect("crate module should have a name");
113-
Some(CrateId { name })
95+
let name = item.name.as_ref().expect("crate module should have a name");
96+
Some(ItemId::crate_root(CrateId { name }))
11497
}
11598
_ => None,
11699
})
117-
118-
//ids.into_iter()
119100
}
120101

121102
pub fn items<'a, 'b>(
122103
&'a self,
123-
crate_id: &'b CrateId,
124-
parent_id: Option<Id>,
125-
) -> impl Iterator<Item = Item<'a>> + 'b
104+
parent_id: &'b ItemId<'a>,
105+
) -> impl Iterator<Item = (ItemId<'a>, Item<'a>)> + 'b
126106
where
127107
'a: 'b,
128108
{
129-
let parent_id = parent_id.unwrap_or(self.crates[&crate_id.name].root.clone());
130-
let parent = self
131-
.crates
132-
.get(&crate_id.name)
133-
.unwrap_or_else(|| panic!("no crate {crate_id:?}"))
134-
.index
135-
.get(&parent_id)
136-
.unwrap_or_else(|| panic!("no id {parent_id:?} in {crate_id:?}"));
109+
let ItemId(parent_crate, parent_id) = parent_id;
110+
let parent = {
111+
let crate_ = &self
112+
.crates
113+
.get(parent_crate.name)
114+
.unwrap_or_else(|| panic!("no crate {parent_crate:?}"));
115+
let id = if parent_id == &EMPTY_ID {
116+
&crate_.root
117+
} else {
118+
parent_id
119+
};
120+
crate_
121+
.index
122+
.get(id)
123+
.unwrap_or_else(|| panic!("no id {id:?} in {parent_crate:?}"))
124+
};
137125

138126
use rustdoc_types::ItemEnum::*;
139-
let children = match &parent.inner {
140-
Module(m) => m.items.clone(),
127+
let children: Vec<&'a rustdoc_types::Id> = match &parent.inner {
128+
Module(m) => m.items.iter().collect(),
141129
ExternCrate { .. } => vec![],
142130
Import(_) => vec![],
143-
Union(u) => [&u.fields[..], &u.impls[..]].concat(),
131+
Union(u) => u.fields.iter().chain(&u.impls).collect(),
144132
Struct(s) => {
145133
let fields = match &s.kind {
146134
rustdoc_types::StructKind::Unit => vec![],
147135
rustdoc_types::StructKind::Tuple(t) => {
148-
t.iter().filter_map(|x| x.as_ref()).cloned().collect()
136+
t.iter().filter_map(|x| x.as_ref()).collect()
149137
}
150-
rustdoc_types::StructKind::Plain { fields, .. } => fields.clone(),
138+
rustdoc_types::StructKind::Plain { fields, .. } => fields.iter().collect(),
151139
};
152-
[&fields[..], &s.impls[..]].concat()
140+
fields.into_iter().chain(&s.impls).collect()
153141
}
154142
StructField(ty) => type_ids(ty),
155-
Enum(e) => [&e.variants[..], &e.impls[..]].concat(),
143+
Enum(e) => e.variants.iter().chain(&e.impls).collect(),
156144
Variant(v) => match &v.kind {
157145
rustdoc_types::VariantKind::Plain => vec![],
158146
rustdoc_types::VariantKind::Tuple(t) => {
159-
t.iter().filter_map(|id| id.clone()).collect()
147+
t.iter().filter_map(|id| id.as_ref()).collect()
160148
}
161-
rustdoc_types::VariantKind::Struct { fields, .. } => fields.clone(),
149+
rustdoc_types::VariantKind::Struct { fields, .. } => fields.iter().collect(),
162150
},
163151
Function(_) => vec![],
164152
Trait(t) => {
165153
// TODO: also find impls?
166-
t.items.clone()
154+
t.items.iter().collect()
167155
}
168156
TraitAlias(_) => vec![],
169157
Impl(i) => {
170-
let mut items = i.items.clone();
171-
// Add a reference to the trait itself too if it's not an inherent impl:
172-
if let Some(trait_) = &i.trait_ {
173-
items.push(trait_.id.clone());
174-
}
175-
items
158+
i.items
159+
.iter()
160+
// Add a reference to the trait itself too if it's not an inherent impl:
161+
.chain(i.trait_.as_ref().map(|t| &t.id))
162+
.collect()
176163
}
177164
TypeAlias(ty) => type_ids(&ty.type_),
178165
OpaqueTy(_) => vec![],
@@ -187,10 +174,18 @@ impl Analysis {
187174
};
188175

189176
children.into_iter().filter_map(move |id| {
190-
if let Some(item) = self.crates[&crate_id.name].index.get(&id) {
191-
Some(Item::Item(item))
177+
if let Some(item) = self.crates[parent_crate.name].index.get(id) {
178+
Some((
179+
ItemId(
180+
CrateId {
181+
name: parent_crate.name,
182+
},
183+
id,
184+
),
185+
Item::Item(item),
186+
))
192187
} else {
193-
let summary = self.crates[&crate_id.name].paths.get(&id)?;
188+
let summary = self.crates[parent_crate.name].paths.get(id)?;
194189
let other_crate = &summary.path[0];
195190
let other_id =
196191
self.crates
@@ -205,11 +200,9 @@ impl Analysis {
205200
}
206201
})?;
207202
let item = self.crates[other_crate].index.get(other_id)?;
208-
Some(Item::Foreign(
209-
CrateId {
210-
name: other_crate.to_owned(),
211-
},
212-
item,
203+
Some((
204+
ItemId(CrateId { name: other_crate }, other_id),
205+
Item::Item(item),
213206
))
214207
}
215208
})
@@ -222,11 +215,11 @@ fn parse_json(p: &Path) -> anyhow::Result<rustdoc_types::Crate> {
222215
Ok(data)
223216
}
224217

225-
fn type_ids(ty: &rustdoc_types::Type) -> Vec<Id> {
218+
fn type_ids(ty: &rustdoc_types::Type) -> Vec<&rustdoc_types::Id> {
226219
use rustdoc_types::Type::*;
227220
match ty {
228-
ResolvedPath(path) => vec![path.id.clone()],
229-
DynTrait(dt) => dt.traits.iter().map(|t| t.trait_.id.clone()).collect(),
221+
ResolvedPath(path) => vec![&path.id],
222+
DynTrait(dt) => dt.traits.iter().map(|t| &t.trait_.id).collect(),
230223
Generic(_) => vec![],
231224
Primitive(_) => vec![],
232225
FunctionPointer(_) => vec![],
@@ -236,7 +229,7 @@ fn type_ids(ty: &rustdoc_types::Type) -> Vec<Id> {
236229
ImplTrait(generics) => generics
237230
.iter()
238231
.filter_map(|g| match g {
239-
rustdoc_types::GenericBound::TraitBound { trait_, .. } => Some(trait_.id.clone()),
232+
rustdoc_types::GenericBound::TraitBound { trait_, .. } => Some(&trait_.id),
240233
rustdoc_types::GenericBound::Outlives(_) => None,
241234
})
242235
.collect(),
@@ -248,7 +241,7 @@ fn type_ids(ty: &rustdoc_types::Type) -> Vec<Id> {
248241
} => {
249242
let from_self = type_ids(self_type);
250243
if let Some(t) = trait_ {
251-
[&from_self[..], &[t.id.clone()]].concat()
244+
[&from_self[..], &[&t.id]].concat()
252245
} else {
253246
from_self
254247
}
@@ -257,17 +250,28 @@ fn type_ids(ty: &rustdoc_types::Type) -> Vec<Id> {
257250
}
258251

259252
#[derive(Debug, Clone)]
260-
pub struct CrateId {
261-
pub name: String,
262-
//pub id: u32,
253+
pub struct CrateId<'a> {
254+
pub name: &'a String,
255+
}
256+
257+
#[derive(Debug, Clone)]
258+
pub struct ItemId<'a>(CrateId<'a>, &'a rustdoc_types::Id);
259+
260+
impl<'a> ItemId<'a> {
261+
pub fn crate_root(crate_id: CrateId<'a>) -> Self {
262+
Self(crate_id, EMPTY_ID)
263+
}
264+
265+
pub fn crate_name(&self) -> &str {
266+
self.0.name
267+
}
263268
}
264269

265270
#[allow(clippy::large_enum_variant)]
266271
#[derive(Debug, Clone)]
267272
pub enum Item<'a> {
268273
Root,
269274
Item(&'a rustdoc_types::Item),
270-
Foreign(CrateId, &'a rustdoc_types::Item),
271275
}
272276

273277
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]

src/browser_rustdoc.rs

+17-43
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::analysis::{Analysis, CrateId, Item};
2-
use crate::browser_trait::{self, Browser};
1+
use crate::analysis::{Analysis, Item, ItemId};
2+
use crate::browser_trait::Browser;
33
use std::fmt::Write;
44

55
pub struct RustdocBrowser {
@@ -13,41 +13,30 @@ impl RustdocBrowser {
1313
}
1414

1515
impl<'a> Browser for &'a RustdocBrowser {
16-
type CrateId = CrateId;
1716
type Item = Item<'a>;
17+
type ItemId = ItemId<'a>;
1818

19-
fn list_crates(&self) -> Vec<(String, CrateId)> {
19+
fn list_crates(&self) -> Vec<(String, ItemId<'a>)> {
2020
let mut crates = self
2121
.analysis
2222
.crate_ids()
2323
//.filter(|c| !self.analysis.stdlib_crates.contains(c))
24-
.map(|c| (crate_label(&c), c))
24+
.map(|item_id| (crate_label(&item_id), item_id))
2525
.collect::<Vec<_>>();
2626

2727
sort_by_label(&mut crates);
2828

2929
crates
3030
}
3131

32-
fn list_items(&self, crate_id: &CrateId, parent: &Item<'a>) -> Vec<(String, Item<'a>)> {
33-
let parent_id = match parent {
34-
Item::Item(item) | Item::Foreign(_, item) => Some(item.id.clone()),
35-
Item::Root => None,
36-
};
37-
38-
let crate_id = match parent {
39-
Item::Foreign(other_crate, _) => other_crate,
40-
Item::Item(_) | Item::Root => crate_id,
41-
};
42-
32+
fn list_items(&self, parent_id: &ItemId<'a>) -> Vec<(String, (ItemId<'a>, Item<'a>))> {
4333
let mut items = self
4434
.analysis
45-
.items(crate_id, parent_id)
46-
.filter_map(|item| {
35+
.items(parent_id)
36+
.filter_map(|(id, item)| {
4737
let inner = match item {
4838
Item::Root => return None,
4939
Item::Item(item) => item,
50-
Item::Foreign(_, item) => item,
5140
};
5241

5342
// Remove the clutter of automatically derived, blanket, and synthetic trait impls.
@@ -57,7 +46,7 @@ impl<'a> Browser for &'a RustdocBrowser {
5746
}
5847
match &inner.inner {
5948
Impl(i) if i.blanket_impl.is_some() || i.synthetic => None,
60-
_ => Some((item_label(inner), item)),
49+
_ => Some((item_label(inner), (id, item))),
6150
}
6251
})
6352
.collect::<Vec<_>>();
@@ -66,10 +55,10 @@ impl<'a> Browser for &'a RustdocBrowser {
6655
items
6756
}
6857

69-
fn get_info(&self, crate_id: &CrateId, item: &Item<'a>) -> String {
58+
fn get_info(&self, item: &Item<'a>) -> String {
7059
let mut txt = String::new();
7160
match item {
72-
Item::Item(item) | Item::Foreign(_, item) => {
61+
Item::Item(item) => {
7362
if let Some(docs) = &item.docs {
7463
txt += &docs;
7564
txt.push('\n');
@@ -84,19 +73,19 @@ impl<'a> Browser for &'a RustdocBrowser {
8473
}
8574
}
8675
Item::Root => {
87-
write!(txt, "crate root of {crate_id:?}").unwrap();
76+
write!(txt, "crate root").unwrap();
8877
}
8978
}
9079
txt
9180
}
9281

93-
fn get_debug_info(&self, crate_id: &CrateId, item: &Item) -> String {
94-
format!("{crate_id:?}: {item:#?}")
82+
fn get_debug_info(&self, item: &Item) -> String {
83+
format!("{item:#?}")
9584
}
9685

9786
fn get_source(&self, item: &Item) -> (String, Option<usize>) {
9887
match item {
99-
Item::Item(item) | Item::Foreign(_, item) => {
88+
Item::Item(item) => {
10089
let (txt, line) = get_source_for_item(item);
10190
(txt, Some(line))
10291
}
@@ -134,15 +123,15 @@ fn sort_by_label<T>(slice: &mut [(String, T)]) {
134123
slice.sort_unstable_by(cmp_labels);
135124
}
136125

137-
fn crate_label(c: &CrateId) -> String {
126+
fn crate_label(id: &ItemId) -> String {
138127
/*match c.crate_type {
139128
CrateType::Bin => format!("{} (bin)", c.name),
140129
CrateType::ProcMacro => format!("{} (proc-macro)", c.name),
141130
CrateType::Lib => c.name.clone(),
142131
CrateType::CDylib => format!("{} (cdylib)", c.name),
143132
CrateType::Dylib => format!("{} (dylib)", c.name),
144133
}*/
145-
c.name.clone()
134+
id.crate_name().to_owned()
146135
}
147136

148137
fn item_label(item: &rustdoc_types::Item) -> String {
@@ -280,18 +269,3 @@ fn type_label(ty: &rustdoc_types::Type) -> String {
280269
}
281270
}
282271
}
283-
284-
impl<'a> browser_trait::Item for Item<'a> {
285-
type CrateId = CrateId;
286-
287-
fn crate_root() -> Self {
288-
Item::Root
289-
}
290-
291-
fn crate_id<'b>(&'b self, crate_id: &'b CrateId) -> &'b CrateId {
292-
match self {
293-
Item::Root | Item::Item(_) => crate_id,
294-
Item::Foreign(other_crate, _) => other_crate,
295-
}
296-
}
297-
}

0 commit comments

Comments
 (0)