1use std::collections::BTreeMap;
2
3use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
4use serde::{Deserialize, Serialize};
5
6pub const INDEX_VERSION: u32 = 9;
7
8#[derive(
9 Archive, RkyvDeserialize, RkyvSerialize, Clone, Debug, Deserialize, PartialEq, Serialize,
10)]
11pub struct IndexMetadata {
12 pub version: u32,
13 pub tool_version: String,
14 pub repo_root_hint: String,
15 pub git_head: Option<String>,
16 pub rust_file_list_hash: String,
17 pub tracked_file_list_hash: String,
18 pub cargo_metadata_hash: String,
19 pub generated_at_unix_ms: u128,
20 pub files: Vec<FileNode>,
21 pub items: Vec<ItemNode>,
22 pub packages: Vec<PackageNode>,
23 pub targets: Vec<TargetNode>,
24 pub package_dependencies: Vec<PackageDependency>,
25 pub module_declarations: Vec<ModuleDeclarationNode>,
26 pub source_dependencies: Vec<SourceDependencyNode>,
27 pub edges: Vec<Edge>,
28}
29
30impl IndexMetadata {
31 pub fn sorted(mut self) -> Self {
32 self.files.sort_by(|a, b| a.id.cmp(&b.id));
33 self.items.sort_by(|a, b| a.id.cmp(&b.id));
34 self.packages.sort_by(|a, b| a.id.cmp(&b.id));
35 self.targets.sort_by(|a, b| a.id.cmp(&b.id));
36 self.package_dependencies.sort_by(|a, b| {
37 a.package_id
38 .cmp(&b.package_id)
39 .then_with(|| a.depends_on_package_id.cmp(&b.depends_on_package_id))
40 .then_with(|| a.kind.cmp(&b.kind))
41 .then_with(|| a.target.cmp(&b.target))
42 .then_with(|| a.name.cmp(&b.name))
43 .then_with(|| a.depends_on_path.cmp(&b.depends_on_path))
44 });
45 self.module_declarations.sort_by(|a, b| {
46 a.from_item_id
47 .cmp(&b.from_item_id)
48 .then_with(|| a.target_paths.cmp(&b.target_paths))
49 });
50 self.source_dependencies.sort_by(|a, b| {
51 a.source_path
52 .cmp(&b.source_path)
53 .then_with(|| a.target_path.cmp(&b.target_path))
54 .then_with(|| a.kind.cmp(&b.kind))
55 });
56 self.edges.sort_by(|a, b| {
57 a.from
58 .cmp(&b.from)
59 .then_with(|| a.to.cmp(&b.to))
60 .then_with(|| a.kind.cmp(&b.kind))
61 });
62 self
63 }
64
65 pub fn item_by_id(&self) -> BTreeMap<String, &ItemNode> {
66 self.items
67 .iter()
68 .map(|item| (item.id.clone(), item))
69 .collect()
70 }
71}
72
73#[derive(
74 Archive, RkyvDeserialize, RkyvSerialize, Clone, Debug, Deserialize, PartialEq, Serialize,
75)]
76pub struct SourceDependencyNode {
77 pub source_path: String,
78 pub target_path: String,
79 pub kind: SourceDependencyKind,
80}
81
82#[derive(
83 Archive,
84 RkyvDeserialize,
85 RkyvSerialize,
86 Clone,
87 Debug,
88 Deserialize,
89 Eq,
90 Ord,
91 PartialEq,
92 PartialOrd,
93 Serialize,
94)]
95#[serde(rename_all = "snake_case")]
96pub enum SourceDependencyKind {
97 PathModule,
98 Include,
99 IncludeStr,
100 IncludeBytes,
101}
102
103#[derive(
104 Archive, RkyvDeserialize, RkyvSerialize, Clone, Debug, Deserialize, PartialEq, Serialize,
105)]
106pub struct ModuleDeclarationNode {
107 pub file_id: String,
108 pub from_item_id: String,
109 pub target_paths: Vec<String>,
110}
111
112#[derive(
113 Archive, RkyvDeserialize, RkyvSerialize, Clone, Debug, Deserialize, PartialEq, Serialize,
114)]
115pub struct FileNode {
116 pub id: String,
117 pub path: String,
118 pub hash: String,
119 pub byte_len: u64,
120}
121
122#[derive(
123 Archive, RkyvDeserialize, RkyvSerialize, Clone, Debug, Deserialize, PartialEq, Serialize,
124)]
125pub struct ItemNode {
126 pub id: String,
127 pub file_id: String,
128 pub kind: ItemKind,
129 pub name: String,
130 pub visibility: String,
131 pub span: SpanRange,
132 pub parent_item_id: Option<String>,
133 pub is_test: bool,
134}
135
136impl ItemNode {
137 pub fn contains_line_range(&self, start_line: usize, end_line: usize) -> bool {
138 self.span.start_line <= end_line && self.span.end_line >= start_line
139 }
140}
141
142#[derive(
143 Archive, RkyvDeserialize, RkyvSerialize, Clone, Debug, Deserialize, PartialEq, Serialize,
144)]
145pub struct PackageNode {
146 pub id: String,
147 pub name: String,
148 pub workspace: String,
149 pub workspace_path: String,
150 pub manifest_path: String,
151 pub root_path: String,
152}
153
154#[derive(
155 Archive, RkyvDeserialize, RkyvSerialize, Clone, Debug, Deserialize, PartialEq, Serialize,
156)]
157pub struct TargetNode {
158 pub id: String,
159 pub package_id: String,
160 pub name: String,
161 pub kind: Vec<String>,
162 pub test: bool,
163 pub src_path: String,
164}
165
166impl TargetNode {
167 pub fn is_bin(&self) -> bool {
168 self.kind.iter().any(|kind| kind == "bin")
169 }
170
171 pub fn is_test(&self) -> bool {
172 self.kind.iter().any(|kind| kind == "test")
173 }
174}
175
176#[derive(
177 Archive, RkyvDeserialize, RkyvSerialize, Clone, Debug, Deserialize, PartialEq, Serialize,
178)]
179pub struct PackageDependency {
180 pub package_id: String,
181 pub depends_on_package_id: String,
182 pub name: String,
183 pub depends_on_path: String,
184 pub kind: String,
185 pub target: Option<String>,
186}
187
188#[derive(
189 Archive,
190 RkyvDeserialize,
191 RkyvSerialize,
192 Clone,
193 Debug,
194 Deserialize,
195 Eq,
196 Ord,
197 PartialEq,
198 PartialOrd,
199 Serialize,
200)]
201pub enum ItemKind {
202 Const,
203 Enum,
204 Fn,
205 ForeignMod,
206 Impl,
207 Macro,
208 Mod,
209 Static,
210 Struct,
211 Trait,
212 TraitAlias,
213 Type,
214 Union,
215 Use,
216 Verbatim,
217}
218
219#[derive(
220 Archive, RkyvDeserialize, RkyvSerialize, Clone, Debug, Deserialize, PartialEq, Serialize,
221)]
222pub struct SpanRange {
223 pub start_line: usize,
224 pub start_column: usize,
225 pub end_line: usize,
226 pub end_column: usize,
227}
228
229#[derive(
230 Archive, RkyvDeserialize, RkyvSerialize, Clone, Debug, Deserialize, PartialEq, Serialize,
231)]
232pub struct Edge {
233 pub from: String,
234 pub to: String,
235 pub kind: EdgeKind,
236}
237
238#[derive(
239 Archive,
240 RkyvDeserialize,
241 RkyvSerialize,
242 Clone,
243 Debug,
244 Deserialize,
245 Eq,
246 Ord,
247 PartialEq,
248 PartialOrd,
249 Serialize,
250)]
251pub enum EdgeKind {
252 Contains,
253 ModuleDeclares,
254}