use crate::config::{builtin_library_cache, is_library_module};
use crate::model::definitions::Definition;
use crate::model::identifiers::{Identifier, IdentifierReference, QualifiedIdentifier};
use crate::model::modules::Module;
use crate::model::HasName;
use crate::stdlib::get_library_module_implementation;
use std::collections::HashMap;
use url::Url;
pub trait ModuleStore {
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn contains(&self, name: &Identifier) -> bool;
fn contains_by_uri(&self, uri: &Url) -> bool {
let name = self.uri_to_module_name(uri).cloned();
if let Some(name) = name {
self.contains(&name)
} else {
false
}
}
fn get(&self, name: &Identifier) -> Option<&Module>;
fn get_mut(&mut self, name: &Identifier) -> Option<&mut Module>;
fn get_by_uri(&self, uri: &Url) -> Option<&Module> {
self.uri_to_module_name(uri).and_then(|name| self.get(name))
}
fn get_by_uri_mut(&mut self, uri: &Url) -> Option<&mut Module> {
let name = self.uri_to_module_name(uri).cloned();
if let Some(name) = name {
self.get_mut(&name)
} else {
None
}
}
fn modules(&self) -> impl Iterator<Item = &Module>;
fn module_names(&self) -> impl Iterator<Item = &Identifier>;
fn insert(&mut self, module: Module);
fn remove(&mut self, name: &Identifier) -> bool;
fn remove_by_uri(&mut self, uri: &Url) -> bool {
let name = self.uri_to_module_name(uri).cloned();
if let Some(name) = name {
self.remove(&name)
} else {
false
}
}
fn uri_to_module_name(&self, url: &Url) -> Option<&Identifier>;
fn module_name_to_uri(&self, name: &Identifier) -> Option<&Url>;
fn resolve(&self, definition: &QualifiedIdentifier) -> Option<&Definition> {
if let Some(module) = self.get(definition.module()) {
module.resolve_local(definition.member())
} else {
None
}
}
fn resolve_or_in(
&self,
definition: &IdentifierReference,
in_module: &Identifier,
) -> Option<&Definition> {
match definition {
IdentifierReference::Identifier(v) => self.resolve(&v.with_module(in_module.clone())),
IdentifierReference::QualifiedIdentifier(v) => self.resolve(v),
}
}
}
#[derive(Clone, Debug)]
pub struct InMemoryModuleCache {
uri_map: HashMap<Url, Identifier>,
modules: HashMap<Identifier, Module>,
}
impl ModuleStore for InMemoryModuleCache {
fn len(&self) -> usize {
self.modules.len()
}
fn contains(&self, name: &Identifier) -> bool {
self.modules.contains_key(name) || is_library_module(name)
}
fn contains_by_uri(&self, uri: &Url) -> bool {
self.uri_map.contains_key(uri)
}
fn get(&self, name: &Identifier) -> Option<&Module> {
if let Some(module) = get_library_module_implementation(name) {
Some(module)
} else {
self.modules.get(name)
}
}
fn get_mut(&mut self, name: &Identifier) -> Option<&mut Module> {
self.modules.get_mut(name)
}
fn get_by_uri(&self, uri: &Url) -> Option<&Module> {
match self.uri_map.get(uri) {
Some(name) => self.get(name),
_ => None,
}
}
fn get_by_uri_mut(&mut self, uri: &Url) -> Option<&mut Module> {
let name = self.uri_map.get_mut(uri).map(|n| n.clone());
match name {
Some(name) => self.get_mut(&name),
_ => None,
}
}
fn modules(&self) -> impl Iterator<Item = &Module> {
self.modules.values()
}
fn module_names(&self) -> impl Iterator<Item = &Identifier> {
self.modules.keys()
}
fn insert(&mut self, module: Module) {
if let Some(base_uri) = module.base_uri() {
self.uri_map
.insert(base_uri.value().clone(), module.name().clone());
}
self.modules.insert(module.name().clone(), module);
}
fn remove(&mut self, name: &Identifier) -> bool {
if self.modules.remove(name).is_some() {
self.uri_map.retain(|_, v| v == name);
true
} else {
false
}
}
fn remove_by_uri(&mut self, uri: &Url) -> bool {
if let Some(name) = self.uri_map.remove(uri) {
self.modules.remove(&name);
true
} else {
false
}
}
fn uri_to_module_name(&self, url: &Url) -> Option<&Identifier> {
self.uri_map.get(url)
}
fn module_name_to_uri(&self, id: &Identifier) -> Option<&Url> {
self.modules
.get(id)
.map(|module| module.base_uri().map(|hv| hv.value()))
.unwrap_or_default()
}
}
impl InMemoryModuleCache {
pub fn empty() -> Self {
Self {
uri_map: Default::default(),
modules: Default::default(),
}
}
pub fn with_stdlib() -> Self {
builtin_library_cache()
}
pub fn with(self, module: Module) -> Self {
let mut self_mut = self;
self_mut.insert(module);
self_mut
}
}