solidity_language_server/
types.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub struct NodeId(pub u64);
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct FileId(pub u64);
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct SourceLoc {
19 pub offset: usize,
21 pub length: usize,
23 pub file_id: FileId,
25}
26
27impl SourceLoc {
28 pub fn parse(src: &str) -> Option<Self> {
32 let mut parts = src.split(':');
33 let offset = parts.next()?.parse::<usize>().ok()?;
34 let length = parts.next()?.parse::<usize>().ok()?;
35 let file_id = parts.next()?.parse::<u64>().ok()?;
36 if parts.next().is_some() {
38 return None;
39 }
40 Some(Self {
41 offset,
42 length,
43 file_id: FileId(file_id),
44 })
45 }
46
47 pub fn end(&self) -> usize {
49 self.offset + self.length
50 }
51
52 pub fn file_id_str(&self) -> String {
55 self.file_id.0.to_string()
56 }
57}
58
59impl std::fmt::Display for NodeId {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 write!(f, "{}", self.0)
62 }
63}
64
65impl std::fmt::Display for FileId {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(f, "{}", self.0)
68 }
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Hash)]
87pub struct FuncSelector(String);
88
89impl FuncSelector {
90 pub fn new(hex: impl Into<String>) -> Self {
92 Self(hex.into())
93 }
94
95 pub fn as_hex(&self) -> &str {
97 &self.0
98 }
99
100 pub fn to_prefixed(&self) -> String {
102 format!("0x{}", self.0)
103 }
104}
105
106impl std::fmt::Display for FuncSelector {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 write!(f, "{}", self.0)
109 }
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, Hash)]
122pub struct EventSelector(String);
123
124impl EventSelector {
125 pub fn new(hex: impl Into<String>) -> Self {
127 Self(hex.into())
128 }
129
130 pub fn as_hex(&self) -> &str {
132 &self.0
133 }
134
135 pub fn to_prefixed(&self) -> String {
137 format!("0x{}", self.0)
138 }
139}
140
141impl std::fmt::Display for EventSelector {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 write!(f, "{}", self.0)
144 }
145}
146
147#[derive(Debug, Clone, PartialEq, Eq, Hash)]
153pub enum Selector {
154 Func(FuncSelector),
156 Event(EventSelector),
158}
159
160impl Selector {
161 pub fn as_hex(&self) -> &str {
163 match self {
164 Selector::Func(s) => s.as_hex(),
165 Selector::Event(s) => s.as_hex(),
166 }
167 }
168
169 pub fn to_prefixed(&self) -> String {
171 match self {
172 Selector::Func(s) => s.to_prefixed(),
173 Selector::Event(s) => s.to_prefixed(),
174 }
175 }
176}
177
178impl std::fmt::Display for Selector {
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 match self {
181 Selector::Func(s) => write!(f, "{s}"),
182 Selector::Event(s) => write!(f, "{s}"),
183 }
184 }
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, Hash)]
198pub struct MethodId(String);
199
200impl MethodId {
201 pub fn new(sig: impl Into<String>) -> Self {
203 Self(sig.into())
204 }
205
206 pub fn as_str(&self) -> &str {
208 &self.0
209 }
210
211 pub fn name(&self) -> &str {
213 self.0.split('(').next().unwrap_or(&self.0)
214 }
215}
216
217impl std::fmt::Display for MethodId {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 write!(f, "{}", self.0)
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 #[test]
228 fn test_source_loc_parse_valid() {
229 let loc = SourceLoc::parse("100:50:3").unwrap();
230 assert_eq!(loc.offset, 100);
231 assert_eq!(loc.length, 50);
232 assert_eq!(loc.file_id, FileId(3));
233 assert_eq!(loc.end(), 150);
234 assert_eq!(loc.file_id_str(), "3");
235 }
236
237 #[test]
238 fn test_source_loc_parse_zero() {
239 let loc = SourceLoc::parse("0:0:0").unwrap();
240 assert_eq!(loc.offset, 0);
241 assert_eq!(loc.length, 0);
242 assert_eq!(loc.file_id, FileId(0));
243 }
244
245 #[test]
246 fn test_source_loc_parse_invalid_format() {
247 assert!(SourceLoc::parse("").is_none());
248 assert!(SourceLoc::parse("100").is_none());
249 assert!(SourceLoc::parse("100:50").is_none());
250 assert!(SourceLoc::parse("abc:50:3").is_none());
251 assert!(SourceLoc::parse("100:abc:3").is_none());
252 assert!(SourceLoc::parse("100:50:abc").is_none());
253 }
254
255 #[test]
256 fn test_source_loc_parse_rejects_extra_parts() {
257 assert!(SourceLoc::parse("100:50:3:extra").is_none());
258 }
259
260 #[test]
261 fn test_node_id_equality() {
262 assert_eq!(NodeId(42), NodeId(42));
263 assert_ne!(NodeId(42), NodeId(43));
264 }
265
266 #[test]
267 fn test_file_id_equality() {
268 assert_eq!(FileId(1), FileId(1));
269 assert_ne!(FileId(1), FileId(2));
270 }
271
272 #[test]
273 fn test_node_id_file_id_are_different_types() {
274 let _n: NodeId = NodeId(1);
278 let _f: FileId = FileId(1);
279 }
282
283 #[test]
286 fn test_func_selector_display() {
287 let sel = FuncSelector::new("f3cd914c");
288 assert_eq!(sel.as_hex(), "f3cd914c");
289 assert_eq!(sel.to_prefixed(), "0xf3cd914c");
290 assert_eq!(format!("{sel}"), "f3cd914c");
291 }
292
293 #[test]
294 fn test_func_selector_equality() {
295 assert_eq!(FuncSelector::new("f3cd914c"), FuncSelector::new("f3cd914c"));
296 assert_ne!(FuncSelector::new("f3cd914c"), FuncSelector::new("8da5cb5b"));
297 }
298
299 #[test]
300 fn test_event_selector_display() {
301 let sel =
302 EventSelector::new("8be0079c5114abcdef1234567890abcdef1234567890abcdef1234567890abcd");
303 assert_eq!(sel.as_hex().len(), 64);
304 assert!(sel.to_prefixed().starts_with("0x"));
305 }
306
307 #[test]
308 fn test_selector_enum_variants() {
309 let func = Selector::Func(FuncSelector::new("f3cd914c"));
310 let event = Selector::Event(EventSelector::new("a".repeat(64)));
311
312 assert_eq!(func.as_hex(), "f3cd914c");
313 assert_eq!(func.to_prefixed(), "0xf3cd914c");
314 assert_eq!(event.as_hex().len(), 64);
315 }
316
317 #[test]
318 fn test_method_id() {
319 let mid = MethodId::new(
320 "swap((address,address,uint24,int24,address),(bool,int256,uint160),bytes)",
321 );
322 assert_eq!(mid.name(), "swap");
323 assert!(mid.as_str().starts_with("swap("));
324 }
325
326 #[test]
327 fn test_method_id_no_params() {
328 let mid = MethodId::new("settle()");
329 assert_eq!(mid.name(), "settle");
330 }
331
332 #[test]
333 fn test_func_selector_hashmap_key() {
334 use std::collections::HashMap;
335 let mut map = HashMap::new();
336 map.insert(FuncSelector::new("f3cd914c"), "swap");
337 map.insert(FuncSelector::new("8da5cb5b"), "owner");
338 assert_eq!(map.get(&FuncSelector::new("f3cd914c")), Some(&"swap"));
339 assert_eq!(map.get(&FuncSelector::new("8da5cb5b")), Some(&"owner"));
340 }
341}