1use serde::{Deserialize, Serialize};
7
8use crate::ids::FileId;
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14pub struct Span {
15 pub file_id: FileId,
17
18 pub byte_start: u32,
20
21 pub byte_end: u32,
23
24 pub line_start: u32,
26
27 pub col_start: u32,
29
30 pub line_end: u32,
32
33 pub col_end: u32,
35}
36
37impl Span {
38 #[must_use]
40 pub const fn new(
41 file_id: FileId,
42 byte_start: u32,
43 byte_end: u32,
44 line_start: u32,
45 col_start: u32,
46 line_end: u32,
47 col_end: u32,
48 ) -> Self {
49 Self {
50 file_id,
51 byte_start,
52 byte_end,
53 line_start,
54 col_start,
55 line_end,
56 col_end,
57 }
58 }
59
60 #[must_use]
62 pub const fn point(file_id: FileId, byte_offset: u32, line: u32, col: u32) -> Self {
63 Self {
64 file_id,
65 byte_start: byte_offset,
66 byte_end: byte_offset + 1,
67 line_start: line,
68 col_start: col,
69 line_end: line,
70 col_end: col + 1,
71 }
72 }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
80pub struct Symbol {
81 pub display_name: String,
83
84 #[serde(default, skip_serializing_if = "Option::is_none")]
86 pub mangled_name: Option<String>,
87
88 #[serde(default, skip_serializing_if = "Vec::is_empty")]
90 pub namespace_path: Vec<String>,
91}
92
93impl Symbol {
94 #[must_use]
96 pub fn simple(name: impl Into<String>) -> Self {
97 Self {
98 display_name: name.into(),
99 mangled_name: None,
100 namespace_path: Vec::new(),
101 }
102 }
103
104 #[must_use]
106 pub fn with_mangled(display: impl Into<String>, mangled: impl Into<String>) -> Self {
107 Self {
108 display_name: display.into(),
109 mangled_name: Some(mangled.into()),
110 namespace_path: Vec::new(),
111 }
112 }
113
114 #[must_use]
116 pub fn qualified(
117 display: impl Into<String>,
118 mangled: Option<String>,
119 namespace: Vec<String>,
120 ) -> Self {
121 Self {
122 display_name: display.into(),
123 mangled_name: mangled,
124 namespace_path: namespace,
125 }
126 }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
131pub struct SourceFile {
132 pub id: FileId,
134
135 pub path: String,
137
138 #[serde(default, skip_serializing_if = "Option::is_none")]
140 pub checksum: Option<String>,
141}
142
143impl SourceFile {
144 #[must_use]
146 pub fn new(id: FileId, path: impl Into<String>) -> Self {
147 Self {
148 id,
149 path: path.into(),
150 checksum: None,
151 }
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158
159 #[test]
160 fn span_serialization_roundtrip() {
161 let span = Span::new(FileId::new(42), 100, 150, 10, 5, 12, 20);
162 let json = serde_json::to_string(&span).expect("serialize");
163 let parsed: Span = serde_json::from_str(&json).expect("deserialize");
164 assert_eq!(span, parsed);
165 }
166
167 #[test]
168 fn symbol_simple() {
169 let sym = Symbol::simple("main");
170 assert_eq!(sym.display_name, "main");
171 assert!(sym.mangled_name.is_none());
172 assert!(sym.namespace_path.is_empty());
173 }
174
175 #[test]
176 fn symbol_with_mangled_serialization() {
177 let sym = Symbol::with_mangled("MyClass::method", "_ZN7MyClass6methodEv");
178 let json = serde_json::to_string(&sym).expect("serialize");
179 assert!(json.contains("_ZN7MyClass6methodEv"));
180 let parsed: Symbol = serde_json::from_str(&json).expect("deserialize");
181 assert_eq!(sym, parsed);
182 }
183
184 #[test]
185 fn symbol_namespace_path() {
186 let sym = Symbol::qualified(
187 "HashMap",
188 None,
189 vec!["std".to_string(), "collections".to_string()],
190 );
191 assert_eq!(sym.namespace_path.len(), 2);
192 }
193}