use crate::cache::AssembleCache;
use crate::dependencies::file_dependency::FileSystem;
use crate::dependencies::DependencyType;
use std::collections::hash_map::IntoValues;
use std::collections::{HashMap, HashSet};
use std::fmt::{Debug, Formatter};
use std::path::PathBuf;
use url::Url;
pub trait Registry {
fn url(&self) -> Url;
fn supported(&self) -> Vec<DependencyType>;
}
assert_obj_safe!(Registry);
pub struct RegistryContainer {
type_to_registry_index: HashMap<DependencyType, HashSet<usize>>,
registries: Vec<Box<dyn Registry>>,
cache_location: PathBuf,
}
impl Debug for RegistryContainer {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RegistryContainer")
.field("len", &self.registries.len())
.finish()
}
}
unsafe impl Send for RegistryContainer {}
unsafe impl Sync for RegistryContainer {}
impl Default for RegistryContainer {
fn default() -> Self {
Self::new()
}
}
impl RegistryContainer {
pub fn new() -> Self {
let mut container = Self {
type_to_registry_index: Default::default(),
registries: vec![],
cache_location: AssembleCache::default().to_path_buf(),
};
container.add_registry(FileSystem::default());
container
}
pub fn add_registry<R: Registry + 'static>(&mut self, registry: R) {
let index = self.registries.len();
let boxed = Box::new(registry) as Box<dyn Registry>;
let dependency_types = boxed.supported();
self.registries.push(boxed);
for dependency_type in dependency_types {
self.type_to_registry_index
.entry(dependency_type)
.or_default()
.insert(index);
}
}
pub fn len(&self) -> usize {
self.registries.len()
}
pub fn supported_registries(&self, ty: &DependencyType) -> RegistrySet {
if let Some(entry) = self.type_to_registry_index.get(ty) {
entry
.iter()
.copied()
.map(|index| &*self.registries[index])
.collect()
} else {
RegistrySet::default()
}
}
pub fn supported_registries_intersection<'a, I>(&'a self, ty: I) -> RegistrySet<'a>
where
I: IntoIterator<Item = &'a DependencyType>,
{
ty.into_iter()
.map(|ty| self.supported_registries(ty))
.fold(RegistrySet::default(), RegistrySet::intersection)
}
pub fn set_cache_location(&mut self, cache_location: PathBuf) {
self.cache_location = cache_location;
}
pub fn cache_location(&self) -> &PathBuf {
&self.cache_location
}
}
#[derive(Default)]
pub struct RegistrySet<'a> {
map: HashMap<Url, &'a dyn Registry>,
}
impl<'a> IntoIterator for RegistrySet<'a> {
type Item = &'a dyn Registry;
type IntoIter = IntoValues<Url, &'a dyn Registry>;
fn into_iter(self) -> Self::IntoIter {
self.map.into_values()
}
}
impl<'a> RegistrySet<'a> {
pub fn intersection(self, other: Self) -> Self {
let mut map = HashMap::new();
for (url, reg) in self.map {
if other.map.contains_key(&url) {
map.insert(url, reg);
}
}
Self { map }
}
pub fn registries(&self) -> impl IntoIterator<Item = &'a dyn Registry> {
self.map.values().copied().collect::<Vec<_>>()
}
}
impl<'a> FromIterator<&'a dyn Registry> for RegistrySet<'a> {
fn from_iter<T: IntoIterator<Item = &'a dyn Registry>>(iter: T) -> Self {
Self {
map: iter
.into_iter()
.map(|reg: &dyn Registry| (reg.url(), reg))
.collect(),
}
}
}