use crate::FileId;
use crate::parsing::Import;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Arc, RwLock};
#[derive(Debug, Clone)]
pub struct BehaviorState {
inner: Arc<RwLock<BehaviorStateInner>>,
}
#[derive(Debug, Default)]
struct BehaviorStateInner {
imports_by_file: HashMap<FileId, Vec<Import>>,
file_to_module: HashMap<PathBuf, String>,
module_to_file: HashMap<String, PathBuf>,
path_to_file_id: HashMap<PathBuf, FileId>,
file_id_to_module: HashMap<FileId, String>,
project_roots: HashMap<FileId, PathBuf>,
}
impl BehaviorState {
pub fn new() -> Self {
Self {
inner: Arc::new(RwLock::new(BehaviorStateInner::default())),
}
}
pub fn register_file(&self, path: PathBuf, file_id: FileId, module_path: String) {
let mut state = self.inner.write().unwrap();
state
.file_to_module
.insert(path.clone(), module_path.clone());
state
.module_to_file
.insert(module_path.clone(), path.clone());
state.path_to_file_id.insert(path, file_id);
state.file_id_to_module.insert(file_id, module_path);
}
pub fn add_import(&self, import: Import) {
let mut state = self.inner.write().unwrap();
state
.imports_by_file
.entry(import.file_id)
.or_default()
.push(import);
}
pub fn get_imports_for_file(&self, file_id: FileId) -> Vec<Import> {
let state = self.inner.read().unwrap();
state
.imports_by_file
.get(&file_id)
.cloned()
.unwrap_or_default()
}
pub fn get_module_path(&self, file_id: FileId) -> Option<String> {
let state = self.inner.read().unwrap();
state.file_id_to_module.get(&file_id).cloned()
}
pub fn resolve_module_to_file(&self, module_path: &str) -> Option<PathBuf> {
let state = self.inner.read().unwrap();
state.module_to_file.get(module_path).cloned()
}
pub fn get_file_id(&self, path: &Path) -> Option<FileId> {
let state = self.inner.read().unwrap();
state.path_to_file_id.get(path).copied()
}
pub fn get_file_path(&self, file_id: FileId) -> Option<PathBuf> {
let state = self.inner.read().unwrap();
for (path, &id) in &state.path_to_file_id {
if id == file_id {
return Some(path.clone());
}
}
None
}
pub fn set_project_root(&self, file_id: FileId, project_root: PathBuf) {
let mut state = self.inner.write().unwrap();
state.project_roots.insert(file_id, project_root);
}
pub fn get_project_root(&self, file_id: FileId) -> Option<PathBuf> {
let state = self.inner.read().unwrap();
state.project_roots.get(&file_id).cloned()
}
pub fn clear(&self) {
let mut state = self.inner.write().unwrap();
state.imports_by_file.clear();
state.file_to_module.clear();
state.module_to_file.clear();
state.path_to_file_id.clear();
state.file_id_to_module.clear();
state.project_roots.clear();
}
}
impl Default for BehaviorState {
fn default() -> Self {
Self::new()
}
}
pub trait StatefulBehavior {
fn state(&self) -> &BehaviorState;
fn register_file_with_state(&self, path: PathBuf, file_id: FileId, module_path: String) {
self.state().register_file(path, file_id, module_path);
}
fn add_import_with_state(&self, import: Import) {
self.state().add_import(import);
}
fn get_imports_from_state(&self, file_id: FileId) -> Vec<Import> {
self.state().get_imports_for_file(file_id)
}
}