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