1pub mod compare;
2pub mod query;
3pub mod search;
4pub mod types;
5
6use bincode::{Decode, Encode};
7use serde::{Deserialize, Serialize};
8
9use crate::types::{Crate, CrateMetadata};
10use std::fmt::Display;
11
12use std::collections::HashMap;
13
14#[derive(Debug, Default)]
15pub struct Index {
16 pub crates: HashMap<CrateMetadata, Crate>,
17 pub parents: HashMap<CrateMetadata, HashMap<types::Id, Parent>>,
18}
19#[derive(Clone, Copy, Debug, Encode, Decode)]
20pub enum Parent {
21 Module(types::Id),
22 Struct(types::Id),
23 Trait(types::Id),
24 Impl(types::Id),
25}
26
27#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
28pub struct Path {
29 pub name: String,
30 pub modules: Vec<types::Item>,
31 pub owner: Option<types::Item>,
32 pub item: types::Item,
33}
34
35impl Display for Path {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 for m in &self.modules {
38 if let Some(name) = &m.name {
39 write!(f, "{}::", name)?;
40 }
41 }
42 if let Some(owner) = &self.owner {
43 if let Some(name) = &owner.name {
44 write!(f, "{}::", name)?;
45 }
46 }
47
48 write!(f, "{}", self.item.name.as_deref().unwrap_or(""))?;
49
50 Ok(())
51 }
52}
53
54impl Path {
55 pub fn pathify(&self) -> Vec<String> {
56 let mut path = Vec::new();
57 for m in &self.modules {
58 if let Some(name) = &m.name {
59 path.push(name.clone());
60 }
61 }
62 if let Some(owner) = &self.owner {
63 if let Some(name) = &owner.name {
64 path.push(name.clone());
65 }
66 }
67 if let Some(name) = &self.item.name {
68 path.push(name.clone());
69 }
70 path
71 }
72 pub fn link(&self) -> String {
73 let mut link = String::new();
74 if self.name == "std" || self.name == "core" || self.name == "alloc" {
75 link.push_str("https://doc.rust-lang.org/");
76 } else {
77 link.push_str(format!("https://docs.rs/{}/latest/", self.name).as_str());
78 }
79 for m in &self.modules {
80 if let Some(name) = &m.name {
81 link.push_str(&format!("{}/", name));
82 }
83 }
84 if let Some(owner) = &self.owner {
85 match &owner.inner {
86 types::ItemEnum::Struct(_) => {
87 link.push_str("struct.");
88 }
89 types::ItemEnum::Trait(_) => {
90 link.push_str("trait.");
91 }
92 types::ItemEnum::Impl(_) => {
93 link.push_str("impl.");
94 }
95 _ => {}
96 }
97 link.push_str(&format!("{}.html#", owner.name.as_deref().unwrap_or("")));
98 link.push_str(&format!(
99 "method.{}.html",
100 self.item.name.as_deref().unwrap_or("")
101 ));
102 } else {
103 link.push_str(&format!(
104 "fn.{}.html",
105 self.item.name.as_deref().unwrap_or("")
106 ));
107 }
108 link
109 }
110}
111
112pub fn build_parent_index(krate: &types::Crate) -> HashMap<types::Id, Parent> {
113 let mut parent = HashMap::new();
114 for (id, item) in &krate.index {
115 match &item.inner {
116 types::ItemEnum::Primitive(p) => {
117 for child in &p.impls {
118 parent.insert(*child, Parent::Module(*id));
119 }
120 }
121 types::ItemEnum::Module(m) => {
122 for child in &m.items {
123 parent.insert(*child, Parent::Module(*id));
124 }
125 }
126 types::ItemEnum::Struct(s) => {
127 for child in &s.impls {
128 parent.insert(*child, Parent::Struct(*id));
129 }
130 }
131 types::ItemEnum::Trait(t) => {
132 for child in &t.items {
133 parent.insert(*child, Parent::Trait(*id));
134 }
135 }
136 types::ItemEnum::Impl(i) => {
137 for child in &i.items {
138 parent.insert(*child, Parent::Impl(*id));
139 }
140 }
141 _ => {}
142 }
143 }
144 tracing::info!(
145 "Built parent index for crate {}",
146 krate.name.clone().unwrap()
147 );
148 parent
150}
151
152fn reconstruct_path_for_local(
154 krate: &types::Crate,
155 id: &types::Id,
156 parents: &HashMap<types::Id, Parent>,
157) -> Option<Path> {
158 let mut cur = *id;
160 let item = krate.index.get(&cur).unwrap().clone();
161
162 let mut path = Path {
163 name: krate.name.clone().unwrap_or_default(),
164 modules: vec![],
165 owner: None,
166 item: item.clone(),
167 };
168
169 let mut walker = Some(cur);
171 while let Some(here) = walker {
172 match parents.get(&here) {
173 Some(Parent::Module(mid)) => {
174 cur = *mid;
175 let mi = &krate.index[mid];
176 if let types::ItemEnum::Module(m) = &mi.inner {
177 if m.is_crate {
178 path.modules.push(mi.clone());
180 break;
181 }
182 }
183 if let Some(_mname) = mi.name.as_deref() {
184 path.modules.push(mi.clone());
185 }
186 walker = Some(cur);
187 }
188 Some(Parent::Trait(tid)) | Some(Parent::Impl(tid)) | Some(Parent::Struct(tid)) => {
191 walker = Some(*tid);
192 path.owner = Some(krate.index.get(tid).unwrap().clone());
193 }
194 None => break,
195 }
196 }
197
198 path.modules.reverse();
199 Some(path)
200}