use crate::package::PackageTrait as Package;
use crate::package_manager::{PackageManager, PackageManagerConfiguration};
use crate::{LoadingConfig, PackageInfo};
use melodium_common::descriptor::{
Collection, Context, Entry, Function, Identified, Identifier, IdentifierRequirement,
Loader as LoaderTrait, LoadingError, LoadingResult, Model, PackageRequirement, Treatment,
};
use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockReadGuard};
#[derive(Debug)]
pub struct Loader {
collection: RwLock<Collection>,
package_manager: PackageManager,
}
impl Loader {
pub fn new(config: LoadingConfig) -> Self {
Self {
collection: RwLock::new(Collection::new()),
package_manager: PackageManager::new(PackageManagerConfiguration {
repositories: vec![
#[cfg(feature = "filesystem")]
Arc::new(std::sync::Mutex::new(melodium_repository::Repository::new(
melodium_repository::RepositoryConfig {
repository_location: {
let mut path = std::env::var_os("MELODIUM_HOME")
.map(|var| var.into())
.or_else(|| {
simple_home_dir::home_dir().map(|mut path| {
path.push(".melodium");
path
})
})
.unwrap_or_else(|| {
let mut path = std::env::temp_dir();
path.push("melodium");
path
});
path.push(env!("CARGO_PKG_VERSION"));
path
},
network: if cfg!(feature = "network") {
Some(melodium_repository::network::NetworkRepositoryConfiguration::new())
} else {
None
},
},
))),
],
core_packages: config.core_packages,
search_locations: config.search_locations,
raw_elements: config.raw_elements,
allow_network: cfg!(feature = "network"),
}),
}
}
pub fn load_package(
&self,
requirement: &PackageRequirement,
) -> LoadingResult<Arc<dyn PackageInfo>> {
self.package_manager
.get_package(requirement)
.and_then(|pkg| LoadingResult::new_success(Arc::clone(&pkg) as Arc<dyn PackageInfo>))
}
pub fn load_raw(&self, raw_content: Arc<Vec<u8>>) -> LoadingResult<Arc<dyn PackageInfo>> {
self.package_manager
.add_raw_package(raw_content)
.and_then(|pkg| LoadingResult::new_success(Arc::clone(&pkg) as Arc<dyn PackageInfo>))
}
pub fn load_mapped(
&self,
mapped_content: HashMap<String, Vec<u8>>,
) -> LoadingResult<Arc<dyn PackageInfo>> {
self.package_manager
.add_map_package(mapped_content)
.and_then(|pkg| LoadingResult::new_success(Arc::clone(&pkg) as Arc<dyn PackageInfo>))
}
pub fn load(
&self,
identifier_requirement: &IdentifierRequirement,
) -> LoadingResult<Identifier> {
self.get_with_load(identifier_requirement)
.and_then(|entry| LoadingResult::new_success(entry.identifier().clone()))
}
pub fn load_all(&self) -> LoadingResult<()> {
let mut result = LoadingResult::new_success(());
for package in self.package_manager.get_packages() {
if let Some(additions) = result.merge_degrade_failure(package.full_collection(self)) {
self.add_collection(additions);
}
}
result
}
pub fn build(&self) -> LoadingResult<Arc<Collection>> {
let mut result = LoadingResult::new_success(());
let collection = Arc::new(self.collection.read().unwrap().clone());
for package in self.package_manager.get_packages() {
result.merge_degrade_failure(package.make_building(&collection));
}
result.and(LoadingResult::new_success(collection))
}
pub fn packages(&self) -> Vec<Arc<dyn PackageInfo>> {
self.package_manager
.get_packages()
.into_iter()
.map(|pkg| Arc::clone(&pkg) as Arc<dyn PackageInfo>)
.collect()
}
pub fn collection(&'_ self) -> RwLockReadGuard<'_, Collection> {
self.collection.read().unwrap()
}
pub fn get_with_load(
&self,
identifier_requirement: &IdentifierRequirement,
) -> LoadingResult<Entry> {
let mut result = LoadingResult::new_success(());
let entry = self
.collection
.read()
.unwrap()
.get(identifier_requirement)
.cloned();
if let Some(entry) = entry {
result.and_degrade_failure(LoadingResult::new_success(entry))
} else if let Some(package) = result.merge_degrade_failure(
self.package_manager
.get_package(&identifier_requirement.package_requirement()),
) {
package
.element(self, &identifier_requirement)
.and_then(|additions| {
self.add_collection(additions);
if let Some(element) = self
.collection
.read()
.unwrap()
.get(identifier_requirement)
.cloned()
{
result.and_degrade_failure(LoadingResult::new_success(element))
} else {
result.and_degrade_failure(LoadingResult::new_failure(
LoadingError::not_found(249, identifier_requirement.to_string()),
))
}
})
} else {
result.and_degrade_failure(LoadingResult::new_failure(LoadingError::no_package(
167,
identifier_requirement.package_requirement(),
)))
}
}
fn add_collection(&self, other_collection: Collection) {
let existing = self.collection.read().unwrap().identifiers();
let mut others = other_collection.identifiers();
others.retain(|id| !existing.contains(id));
if !others.is_empty() {
let mut collection = self.collection.write().unwrap();
for id in &others {
collection.insert(other_collection.get(&id.into()).unwrap().clone());
}
}
}
}
impl LoaderTrait for Loader {
fn load_context(
&self,
identifier_requirement: &IdentifierRequirement,
) -> LoadingResult<Arc<dyn Context>> {
self.get_with_load(identifier_requirement)
.and_then(|entry| match entry {
Entry::Context(context) => LoadingResult::new_success(context),
_ => LoadingResult::new_failure(LoadingError::context_expected(
168,
None,
identifier_requirement.clone(),
)),
})
}
fn load_function(
&self,
identifier_requirement: &IdentifierRequirement,
) -> LoadingResult<Arc<dyn Function>> {
self.get_with_load(identifier_requirement)
.and_then(|entry| match entry {
Entry::Function(function) => LoadingResult::new_success(function),
_ => LoadingResult::new_failure(LoadingError::function_expected(
169,
None,
identifier_requirement.clone(),
)),
})
}
fn load_model(
&self,
identifier_requirement: &IdentifierRequirement,
) -> LoadingResult<Arc<dyn Model>> {
self.get_with_load(identifier_requirement)
.and_then(|entry| match entry {
Entry::Model(model) => LoadingResult::new_success(model),
_ => LoadingResult::new_failure(LoadingError::model_expected(
170,
None,
identifier_requirement.clone(),
)),
})
}
fn load_treatment(
&self,
identifier_requirement: &IdentifierRequirement,
) -> LoadingResult<Arc<dyn Treatment>> {
self.get_with_load(identifier_requirement)
.and_then(|entry| match entry {
Entry::Treatment(treatment) => LoadingResult::new_success(treatment),
_ => LoadingResult::new_failure(LoadingError::treatment_expected(
171,
None,
identifier_requirement.clone(),
)),
})
}
}