sway_types/
source_engine.rs1use crate::{ProgramId, SourceId};
2use parking_lot::RwLock;
3use std::{
4 collections::{BTreeSet, HashMap},
5 path::PathBuf,
6 str::FromStr,
7};
8
9#[derive(Debug, Default)]
19pub struct SourceEngine {
20 next_source_id: RwLock<u32>,
21 path_to_source_map: RwLock<HashMap<PathBuf, SourceId>>,
22 source_to_path_map: RwLock<HashMap<SourceId, PathBuf>>,
23 next_program_id: RwLock<u16>,
24 manifest_path_to_program_map: RwLock<HashMap<PathBuf, ProgramId>>,
25 module_to_sources_map: RwLock<HashMap<ProgramId, BTreeSet<SourceId>>>,
26}
27
28impl Clone for SourceEngine {
29 fn clone(&self) -> Self {
30 SourceEngine {
31 next_source_id: RwLock::new(*self.next_source_id.read()),
32 path_to_source_map: RwLock::new(self.path_to_source_map.read().clone()),
33 source_to_path_map: RwLock::new(self.source_to_path_map.read().clone()),
34 next_program_id: RwLock::new(*self.next_program_id.read()),
35 manifest_path_to_program_map: RwLock::new(
36 self.manifest_path_to_program_map.read().clone(),
37 ),
38 module_to_sources_map: RwLock::new(self.module_to_sources_map.read().clone()),
39 }
40 }
41}
42
43impl SourceEngine {
44 const AUTOGENERATED_PATH: &'static str = "<autogenerated>";
45
46 pub fn is_span_in_autogenerated(&self, span: &crate::Span) -> Option<bool> {
47 span.source_id().map(|s| self.is_source_id_autogenerated(s))
48 }
49
50 pub fn is_source_id_autogenerated(&self, source_id: &SourceId) -> bool {
51 self.get_path(source_id)
52 .display()
53 .to_string()
54 .contains("<autogenerated>")
55 }
56
57 pub fn get_source_id(&self, path: &PathBuf) -> SourceId {
61 {
62 let source_map = self.path_to_source_map.read();
63 if source_map.contains_key(path) {
64 return source_map.get(path).copied().unwrap();
65 }
66 }
67
68 let program_id = self.get_or_create_program_id_from_manifest_path(path);
69 self.get_source_id_with_program_id(path, program_id)
70 }
71
72 pub fn get_source_id_with_program_id(&self, path: &PathBuf, program_id: ProgramId) -> SourceId {
73 {
74 let source_map = self.path_to_source_map.read();
75 if source_map.contains_key(path) {
76 return source_map.get(path).copied().unwrap();
77 }
78 }
79
80 let source_id = SourceId::new(program_id.0, *self.next_source_id.read());
81 {
82 let mut next_id = self.next_source_id.write();
83 *next_id += 1;
84
85 let mut source_map = self.path_to_source_map.write();
86 source_map.insert(path.clone(), source_id);
87
88 let mut path_map = self.source_to_path_map.write();
89 path_map.insert(source_id, path.clone());
90 }
91
92 let mut module_map = self.module_to_sources_map.write();
93 module_map.entry(program_id).or_default().insert(source_id);
94
95 source_id
96 }
97
98 pub fn get_associated_autogenerated_source_id(&self, source_id: &SourceId) -> Option<SourceId> {
103 let path = self.get_path(source_id);
104 let file_name = PathBuf::from_str(path.file_name()?.to_str()?).ok()?;
105 let path = path.with_file_name(format!(
106 "{}.{}.{}",
107 file_name.file_stem()?.to_str()?,
108 Self::AUTOGENERATED_PATH,
109 file_name.extension()?.to_str()?
110 ));
111 Some(self.get_source_id_with_program_id(&path, source_id.program_id()))
112 }
113
114 pub fn get_path(&self, source_id: &SourceId) -> PathBuf {
116 self.source_to_path_map
117 .read()
118 .get(source_id)
119 .unwrap()
120 .clone()
121 }
122
123 pub fn get_program_id_from_manifest_path(&self, path: &PathBuf) -> Option<ProgramId> {
125 let manifest_path = sway_utils::find_parent_manifest_dir(path).unwrap_or(path.clone());
126 self.manifest_path_to_program_map
127 .read()
128 .get(&manifest_path)
129 .copied()
130 }
131
132 pub fn get_or_create_program_id_from_manifest_path(&self, path: &PathBuf) -> ProgramId {
133 let manifest_path = sway_utils::find_parent_manifest_dir(path).unwrap_or(path.clone());
134 let mut module_map = self.manifest_path_to_program_map.write();
135 *module_map.entry(manifest_path.clone()).or_insert_with(|| {
136 let mut next_id = self.next_program_id.write();
137 *next_id += 1;
138 ProgramId::new(*next_id)
139 })
140 }
141
142 pub fn get_manifest_path_from_program_id(&self, program_id: &ProgramId) -> Option<PathBuf> {
144 let path_to_module_map = self.manifest_path_to_program_map.read();
145 path_to_module_map
146 .iter()
147 .find(|(_, &id)| id == *program_id)
148 .map(|(path, _)| path.clone())
149 }
150
151 pub fn get_file_name(&self, source_id: &SourceId) -> Option<String> {
153 self.get_path(source_id)
154 .as_path()
155 .file_name()
156 .map(|file_name| file_name.to_string_lossy())
157 .map(|file_name| file_name.to_string())
158 }
159
160 pub fn all_files(&self) -> Vec<PathBuf> {
161 let s = self.source_to_path_map.read();
162 let mut v = s.values().cloned().collect::<Vec<_>>();
163 v.sort();
164 v
165 }
166
167 pub fn get_source_ids_from_program_id(
168 &self,
169 program_id: ProgramId,
170 ) -> Option<BTreeSet<SourceId>> {
171 let s = self.module_to_sources_map.read();
172 s.get(&program_id).cloned()
173 }
174}