use crate::content::Content;
use crate::package::package::PackageTrait;
use crate::{Loader, PackageInfo};
use melodium_common::descriptor::{
Collection, Identifier, IdentifierRequirement, LoadingError, LoadingResult,
Package as CommonPackage, PackageRequirement,
};
use semver::Version;
use std::collections::{BTreeMap, HashMap};
use std::sync::{Arc, OnceLock, RwLock};
#[derive(Debug)]
pub struct CorePackage {
package: Arc<dyn CommonPackage>,
requirements: Vec<PackageRequirement>,
embedded_collection: RwLock<Option<Collection>>,
contents: RwLock<HashMap<String, Arc<Content>>>,
}
impl CorePackage {
pub fn new(package: Arc<dyn CommonPackage>) -> Self {
Self {
requirements: package.requirements().iter().map(|pr| pr.clone()).collect(),
package,
embedded_collection: RwLock::new(None),
contents: RwLock::new(HashMap::new()),
}
}
fn insure_content(&self, designation: &str) -> LoadingResult<()> {
match self.package.embedded().get(designation) {
Some(data) => {
if self.contents.read().unwrap().contains_key(designation) {
LoadingResult::new_success(())
} else {
Content::new(
designation,
data,
self.version(),
&self
.requirements
.iter()
.map(|pkg_req| {
(pkg_req.package.clone(), pkg_req.version_requirement.clone())
})
.collect(),
)
.convert_failure_errors(|err| LoadingError::content_error(158, Arc::new(err)))
.and_then(|content| {
self.contents
.write()
.unwrap()
.insert(designation.to_string(), Arc::new(content));
LoadingResult::new_success(())
})
}
}
None => LoadingResult::new_failure(LoadingError::not_found(
159,
designation.trim_end_matches(".mel").to_string(),
)),
}
}
fn all_contents(&self) -> LoadingResult<()> {
let mut result = LoadingResult::new_success(());
let embedded = self.package.embedded();
for (designation, _) in embedded {
result = result.and_degrade_failure(self.insure_content(designation));
}
result
}
fn insure_loading(
loader: &Loader,
identifiers: Vec<IdentifierRequirement>,
) -> LoadingResult<()> {
let mut result = LoadingResult::new_success(());
for identifier in &identifiers {
result = result.and_degrade_failure(
loader
.get_with_load(identifier)
.and(LoadingResult::new_success(())),
);
}
result
}
fn designation(identifier: &IdentifierRequirement) -> String {
format!("{}.mel", identifier.path().join("/"))
}
}
impl PackageInfo for CorePackage {
fn name(&self) -> &str {
self.package.name()
}
fn version(&self) -> &Version {
self.package.version()
}
fn requirements(&self) -> &Vec<PackageRequirement> {
&self.requirements
}
fn entrypoints(&self) -> &HashMap<String, Identifier> {
static MAP: OnceLock<HashMap<String, Identifier>> = OnceLock::new();
MAP.get_or_init(|| HashMap::new())
}
}
impl PackageTrait for CorePackage {
fn embedded_collection(&self, loader: &Loader) -> LoadingResult<Collection> {
let mut embedded_collection = self.embedded_collection.write().unwrap();
if let Some(collection) = &*embedded_collection {
LoadingResult::new_success(collection.clone())
} else {
let result = self.package.collection(loader);
if let Some(collection) = result.success() {
*embedded_collection = Some(collection.clone());
}
result
}
}
fn full_collection(&self, loader: &Loader) -> LoadingResult<Collection> {
let mut results = LoadingResult::new_success(Collection::new());
results.merge(self.all_contents());
if results.is_failure() {
return results;
}
let mut collection = if let Some(collection) =
results.merge_degrade_failure(self.embedded_collection(loader))
{
collection
} else {
return results;
};
let mut all_needs = BTreeMap::new();
for (designation, content) in self.contents.read().unwrap().iter() {
let needs = content.require();
'need: for need in &needs {
let need_designation = Self::designation(need);
if let Some(other_needs) = all_needs.get(&need_designation) {
for other_need in other_needs {
if &Self::designation(other_need) == designation {
results.merge_degrade_failure::<()>(LoadingResult::new_failure(
LoadingError::circular_reference(160, need.clone()),
));
continue 'need;
}
}
}
}
all_needs.insert(designation.clone(), needs);
}
let mut external_needs: Vec<IdentifierRequirement> = Vec::new();
let mut internal_needs = Vec::new();
for (designation_requester, designation_requested, ref need) in all_needs
.into_iter()
.map(|(designation, needs)| {
needs
.into_iter()
.map(|need| (designation.clone(), Self::designation(&need), need))
.collect::<Vec<_>>()
})
.flatten()
{
if collection.get(need).is_none() {
if need.root() != self.name() {
if !external_needs
.iter()
.any(|en| en.path() == need.path() && en.name() == need.name())
{
external_needs.push(need.clone());
}
} else {
let requester_included = internal_needs.contains(&designation_requester);
let requested_included = internal_needs.contains(&designation_requested);
if !requester_included && !requested_included {
internal_needs.push(designation_requested);
internal_needs.push(designation_requester);
} else if requester_included && !requested_included {
let position = internal_needs
.iter()
.position(|d| d == &designation_requester)
.unwrap();
internal_needs.insert(position, designation_requested);
} else {
internal_needs.push(designation_requester);
}
}
}
}
for identifier_req in &external_needs {
if let Some(entry) = results.merge_degrade_failure(loader.get_with_load(identifier_req))
{
collection.insert(entry);
}
}
let contents = self.contents.read().unwrap();
for designation in &internal_needs {
if let Some(content) = contents.get(designation) {
results.merge_degrade_failure(
content
.insert_descriptors(&mut collection)
.convert_failure_errors(|err| {
LoadingError::content_error(161, Arc::new(err))
}),
);
}
}
for (designation, content) in &*contents {
if !internal_needs.contains(designation) {
results.merge_degrade_failure(
content
.insert_descriptors(&mut collection)
.convert_failure_errors(|err| {
LoadingError::content_error(162, Arc::new(err))
}),
);
}
}
results.and(LoadingResult::new_success(collection))
}
fn all_identifiers(&self, loader: &Loader) -> LoadingResult<Vec<Identifier>> {
let mut results = LoadingResult::new_success(Vec::new());
results.merge(self.all_contents());
if results.is_failure() {
return results;
}
self.embedded_collection(loader).and_then(|collection| {
let mut identifiers = collection.identifiers();
identifiers.extend(
self.contents
.read()
.unwrap()
.iter()
.map(|(_, content)| {
content
.provide()
.into_iter()
.map(|id| id.with_version(self.package.version()))
.collect::<Vec<_>>()
})
.flatten(),
);
LoadingResult::new_success(identifiers)
})
}
fn element(
&self,
loader: &Loader,
identifier_requirement: &IdentifierRequirement,
) -> LoadingResult<Collection> {
let mut result = LoadingResult::new_success(Collection::new());
if let Some(collection) = result.merge_degrade_failure(self.embedded_collection(loader)) {
if collection.get(identifier_requirement).is_some() {
return result.and_degrade_failure(LoadingResult::new_success(collection));
}
}
let designation = Self::designation(identifier_requirement);
if let None = result.merge_degrade_failure(self.insure_content(&designation)) {
return result.and_degrade_failure(LoadingResult::new_failure(
LoadingError::not_found(250, identifier_requirement.to_string()),
));
}
let content = { self.contents.read().unwrap().get(&designation).cloned() };
if let Some(content) = content {
if let Ok(_guard) = content.try_lock() {
let needs = content.require();
result.merge_degrade_failure(Self::insure_loading(loader, needs));
let mut collection = loader.collection().clone();
result.merge_degrade_failure(
content
.insert_descriptors(&mut collection)
.convert_failure_errors(|err| {
LoadingError::content_error(163, Arc::new(err))
}),
);
result = result.and_degrade_failure(LoadingResult::new_success(collection));
} else {
result.merge_degrade_failure::<()>(LoadingResult::new_failure(
LoadingError::circular_reference(164, identifier_requirement.clone()),
));
}
} else {
result.merge_degrade_failure::<()>(LoadingResult::new_failure(
LoadingError::not_found(165, identifier_requirement.to_string()),
));
}
result
}
fn make_building(&self, collection: &Arc<Collection>) -> LoadingResult<()> {
let contents = self.contents.read().unwrap();
let mut result = LoadingResult::new_success(());
for (_, content) in contents.iter() {
result.merge_degrade_failure(
content
.make_design(collection)
.convert_failure_errors(|err| LoadingError::content_error(166, Arc::new(err))),
);
}
result
}
}