1use rustdoc_types::{Crate, Id, ItemKind};
2use std::collections::HashMap;
3
4use crate::spec::{ExternalCrateRef, ItemId};
5
6pub struct LinkContext<'a> {
10 pub krate: &'a Crate,
11 pub external_crate_index: HashMap<u32, ExternalCrateRef>,
12}
13
14impl<'a> LinkContext<'a> {
15 pub fn new(krate: &'a Crate) -> Self {
16 let external_crate_index = krate
17 .external_crates
18 .iter()
19 .map(|(crate_id, ec)| {
20 (
21 *crate_id,
22 ExternalCrateRef {
23 crate_id: *crate_id,
24 name: ec.name.clone(),
25 html_root_url: ec.html_root_url.clone(),
26 },
27 )
28 })
29 .collect();
30 Self {
31 krate,
32 external_crate_index,
33 }
34 }
35
36 pub fn external_crates(&self) -> Vec<ExternalCrateRef> {
37 let mut out: Vec<_> = self.external_crate_index.values().cloned().collect();
38 out.sort_by(|a, b| a.crate_id.cmp(&b.crate_id));
39 out
40 }
41
42 pub fn resolve_id(&self, id: &Id) -> Option<ResolvedLink> {
43 if let Some(summary) = self.krate.paths.get(id) {
44 let crate_id = summary.crate_id;
45 let path = summary.path.clone();
46 let kind = summary.kind.clone();
47 let external = crate_id != 0;
48 let html_root_url = if external {
49 self.external_crate_index
50 .get(&crate_id)
51 .and_then(|ec| ec.html_root_url.clone())
52 } else {
53 None
54 };
55 return Some(ResolvedLink {
56 id: ItemId(format_id(id)),
57 crate_id,
58 path,
59 kind,
60 external,
61 html_root_url,
62 });
63 }
64 if let Some(item) = self.krate.index.get(id) {
65 return Some(ResolvedLink {
68 id: ItemId(format_id(id)),
69 crate_id: item.crate_id,
70 path: item.name.clone().map(|n| vec![n]).unwrap_or_default(),
71 kind: classify_inner_kind(item),
72 external: item.crate_id != 0,
73 html_root_url: self
74 .external_crate_index
75 .get(&item.crate_id)
76 .and_then(|ec| ec.html_root_url.clone()),
77 });
78 }
79 None
80 }
81}
82
83#[derive(Debug, Clone)]
84pub struct ResolvedLink {
85 pub id: ItemId,
86 pub crate_id: u32,
87 pub path: Vec<String>,
88 pub kind: ItemKind,
89 pub external: bool,
90 pub html_root_url: Option<String>,
91}
92
93pub fn format_id(id: &Id) -> String {
94 format!("{}", id.0)
95}
96
97fn classify_inner_kind(item: &rustdoc_types::Item) -> ItemKind {
98 use rustdoc_types::ItemEnum;
99 match &item.inner {
100 ItemEnum::Module(_) => ItemKind::Module,
101 ItemEnum::Struct(_) => ItemKind::Struct,
102 ItemEnum::StructField(_) => ItemKind::StructField,
103 ItemEnum::Union(_) => ItemKind::Union,
104 ItemEnum::Enum(_) => ItemKind::Enum,
105 ItemEnum::Variant(_) => ItemKind::Variant,
106 ItemEnum::Function(_) => ItemKind::Function,
107 ItemEnum::Trait(_) => ItemKind::Trait,
108 ItemEnum::TraitAlias(_) => ItemKind::TraitAlias,
109 ItemEnum::Impl(_) => ItemKind::Impl,
110 ItemEnum::TypeAlias(_) => ItemKind::TypeAlias,
111 ItemEnum::Constant { .. } => ItemKind::Constant,
112 ItemEnum::Static(_) => ItemKind::Static,
113 ItemEnum::Macro(_) => ItemKind::Macro,
114 ItemEnum::ProcMacro(pm) => match pm.kind {
115 rustdoc_types::MacroKind::Bang => ItemKind::Macro,
116 rustdoc_types::MacroKind::Attr => ItemKind::ProcAttribute,
117 rustdoc_types::MacroKind::Derive => ItemKind::ProcDerive,
118 },
119 ItemEnum::AssocConst { .. } => ItemKind::AssocConst,
120 ItemEnum::AssocType { .. } => ItemKind::AssocType,
121 ItemEnum::ExternCrate { .. } => ItemKind::ExternCrate,
122 ItemEnum::Use(_) => ItemKind::Use,
123 ItemEnum::Primitive(_) => ItemKind::Primitive,
124 ItemEnum::ExternType => ItemKind::ExternType,
125 }
126}