use std::rc::Rc;
use rustc_hash::FxHashMap;
use super::module_scopes::ModuleScopes;
use crate::core::{BindingId, ModuleId, ModulePath, Namespace};
use crate::reader::Symbol;
use crate::scope::ScopeSet;
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum LoadStatus {
Loading,
Loaded,
}
#[derive(serde::Serialize, serde::Deserialize)]
pub struct ModuleRecord {
path: ModulePath,
scopes: ModuleScopes,
exports: FxHashMap<(Rc<str>, Namespace), BindingId>,
status: LoadStatus,
}
impl ModuleRecord {
pub fn path(&self) -> &ModulePath {
&self.path
}
pub fn scopes(&self) -> ModuleScopes {
self.scopes
}
pub fn symbol(&self) -> Symbol {
Symbol::with_scopes(self.path.as_str(), self.scopes.set())
}
pub fn export(&mut self, name: Rc<str>, namespace: Namespace, binding: BindingId) {
self.exports.insert((name, namespace), binding);
}
pub fn exported(&self, name: &str, namespace: Namespace) -> Option<BindingId> {
self.exports.get(&(Rc::from(name), namespace)).copied()
}
pub fn exports(&self) -> impl Iterator<Item = (&Rc<str>, Namespace, BindingId)> {
self.exports
.iter()
.map(|((name, namespace), binding)| (name, *namespace, *binding))
}
pub fn is_loading(&self) -> bool {
self.status == LoadStatus::Loading
}
}
#[derive(Default)]
pub struct ModuleRegistry {
records: Vec<ModuleRecord>,
by_path: FxHashMap<ModulePath, ModuleId>,
}
impl ModuleRegistry {
pub fn register(&mut self, path: ModulePath, scopes: ModuleScopes) -> ModuleId {
self.adopt(ModuleRecord {
path,
scopes,
exports: FxHashMap::default(),
status: LoadStatus::Loading,
})
}
pub fn adopt(&mut self, record: ModuleRecord) -> ModuleId {
let id = ModuleId::new(self.records.len());
self.by_path.insert(record.path.clone(), id);
self.records.push(record);
id
}
pub fn into_records_after(mut self, id: ModuleId) -> Vec<ModuleRecord> {
self.records.split_off(id.index() + 1)
}
pub fn find(&self, path: &ModulePath) -> Option<ModuleId> {
self.by_path.get(path).copied()
}
pub fn finish_loading(&mut self, id: ModuleId) {
self.records[id.index()].status = LoadStatus::Loaded;
}
pub fn loading_paths(&self) -> Vec<&ModulePath> {
self.records
.iter()
.filter(|record| record.is_loading())
.map(ModuleRecord::path)
.collect()
}
pub fn with_body_scopes(&self, scopes: &ScopeSet) -> Option<ModuleId> {
self.records
.iter()
.position(|record| record.scopes.set() == *scopes)
.map(ModuleId::new)
}
pub fn records(&self) -> impl Iterator<Item = &ModuleRecord> {
self.records.iter()
}
pub fn get(&self, id: ModuleId) -> &ModuleRecord {
&self.records[id.index()]
}
pub fn get_mut(&mut self, id: ModuleId) -> &mut ModuleRecord {
&mut self.records[id.index()]
}
}