Skip to main content

cargo_litmus/
model.rs

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}