sway_types/
source_engine.rsuse crate::{ProgramId, SourceId};
use parking_lot::RwLock;
use std::{
collections::{BTreeSet, HashMap},
path::PathBuf,
};
#[derive(Debug, Default)]
pub struct SourceEngine {
next_source_id: RwLock<u32>,
path_to_source_map: RwLock<HashMap<PathBuf, SourceId>>,
source_to_path_map: RwLock<HashMap<SourceId, PathBuf>>,
next_program_id: RwLock<u16>,
manifest_path_to_program_map: RwLock<HashMap<PathBuf, ProgramId>>,
module_to_sources_map: RwLock<HashMap<ProgramId, BTreeSet<SourceId>>>,
}
impl Clone for SourceEngine {
fn clone(&self) -> Self {
SourceEngine {
next_source_id: RwLock::new(*self.next_source_id.read()),
path_to_source_map: RwLock::new(self.path_to_source_map.read().clone()),
source_to_path_map: RwLock::new(self.source_to_path_map.read().clone()),
next_program_id: RwLock::new(*self.next_program_id.read()),
manifest_path_to_program_map: RwLock::new(
self.manifest_path_to_program_map.read().clone(),
),
module_to_sources_map: RwLock::new(self.module_to_sources_map.read().clone()),
}
}
}
impl SourceEngine {
const AUTOGENERATED_PATH: &'static str = "<autogenerated>";
pub fn is_span_in_autogenerated(&self, span: &crate::Span) -> Option<bool> {
span.source_id().map(|s| self.is_source_id_autogenerated(s))
}
pub fn is_source_id_autogenerated(&self, source_id: &SourceId) -> bool {
self.get_path(source_id).starts_with("<autogenerated>")
}
pub fn get_source_id(&self, path: &PathBuf) -> SourceId {
{
let source_map = self.path_to_source_map.read();
if source_map.contains_key(path) {
return source_map.get(path).copied().unwrap();
}
}
let manifest_path = sway_utils::find_parent_manifest_dir(path).unwrap_or(path.clone());
let program_id = {
let mut module_map = self.manifest_path_to_program_map.write();
*module_map.entry(manifest_path.clone()).or_insert_with(|| {
let mut next_id = self.next_program_id.write();
*next_id += 1;
ProgramId::new(*next_id)
})
};
self.get_source_id_with_program_id(path, program_id)
}
pub fn get_source_id_with_program_id(&self, path: &PathBuf, program_id: ProgramId) -> SourceId {
{
let source_map = self.path_to_source_map.read();
if source_map.contains_key(path) {
return source_map.get(path).copied().unwrap();
}
}
let source_id = SourceId::new(program_id.0, *self.next_source_id.read());
{
let mut next_id = self.next_source_id.write();
*next_id += 1;
let mut source_map = self.path_to_source_map.write();
source_map.insert(path.clone(), source_id);
let mut path_map = self.source_to_path_map.write();
path_map.insert(source_id, path.clone());
}
let mut module_map = self.module_to_sources_map.write();
module_map.entry(program_id).or_default().insert(source_id);
source_id
}
pub fn get_autogenerated_source_id(&self, program_id: ProgramId) -> SourceId {
self.get_source_id_with_program_id(&Self::AUTOGENERATED_PATH.into(), program_id)
}
pub fn get_path(&self, source_id: &SourceId) -> PathBuf {
self.source_to_path_map
.read()
.get(source_id)
.unwrap()
.clone()
}
pub fn get_program_id(&self, path: &PathBuf) -> Option<ProgramId> {
self.manifest_path_to_program_map.read().get(path).copied()
}
pub fn get_manifest_path_from_program_id(&self, program_id: &ProgramId) -> Option<PathBuf> {
let path_to_module_map = self.manifest_path_to_program_map.read();
path_to_module_map
.iter()
.find(|(_, &id)| id == *program_id)
.map(|(path, _)| path.clone())
}
pub fn get_file_name(&self, source_id: &SourceId) -> Option<String> {
self.get_path(source_id)
.as_path()
.file_name()
.map(|file_name| file_name.to_string_lossy())
.map(|file_name| file_name.to_string())
}
pub fn all_files(&self) -> Vec<PathBuf> {
let s = self.source_to_path_map.read();
let mut v = s.values().cloned().collect::<Vec<_>>();
v.sort();
v
}
pub fn get_source_ids_from_program_id(
&self,
program_id: ProgramId,
) -> Option<BTreeSet<SourceId>> {
let s = self.module_to_sources_map.read();
s.get(&program_id).cloned()
}
}