backhopper_xref_graph/
loc.rs1use std::collections::HashMap;
12use std::path::{Path, PathBuf};
13
14use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
17#[serde(transparent)]
18pub struct PathId(u32);
19
20impl PathId {
21 pub const fn new(id: u32) -> Self {
22 Self(id)
23 }
24
25 pub const fn as_u32(self) -> u32 {
26 self.0
27 }
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
31pub struct Position {
32 pub line: u32,
33 pub column: u32,
34 pub byte_offset: u32,
35}
36
37impl Position {
38 pub const fn new(line: u32, column: u32, byte_offset: u32) -> Self {
39 Self {
40 line,
41 column,
42 byte_offset,
43 }
44 }
45
46 pub const fn zero() -> Self {
48 Self::new(1, 1, 0)
49 }
50}
51
52impl Default for Position {
53 fn default() -> Self {
54 Self::zero()
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
59pub struct Loc {
60 pub path: PathId,
61 pub start: Position,
62 pub end: Position,
63}
64
65impl Loc {
66 pub fn point(path: PathId, pos: Position) -> Self {
67 Self {
68 path,
69 start: pos,
70 end: pos,
71 }
72 }
73
74 pub fn span(path: PathId, start: Position, end: Position) -> Self {
75 Self { path, start, end }
76 }
77}
78
79#[derive(Debug, Default, Clone)]
80pub struct PathInterner {
81 paths: Vec<PathBuf>,
82 index: HashMap<PathBuf, PathId>,
83}
84
85impl PathInterner {
86 pub fn new() -> Self {
87 Self::default()
88 }
89
90 pub fn intern(&mut self, p: &Path) -> PathId {
91 if let Some(id) = self.index.get(p) {
92 return *id;
93 }
94 let id = PathId::new(u32::try_from(self.paths.len()).expect("path id overflow"));
95 let owned = p.to_path_buf();
96 self.paths.push(owned.clone());
97 self.index.insert(owned, id);
98 id
99 }
100
101 pub fn get(&self, id: PathId) -> Option<&Path> {
102 self.paths.get(id.as_u32() as usize).map(PathBuf::as_path)
103 }
104
105 pub fn len(&self) -> usize {
106 self.paths.len()
107 }
108
109 pub fn is_empty(&self) -> bool {
110 self.paths.is_empty()
111 }
112}