assemble_core/dependencies/
registry_container.rs1use crate::cache::AssembleCache;
2use crate::dependencies::file_dependency::FileSystem;
3use crate::dependencies::DependencyType;
4use std::collections::hash_map::IntoValues;
5use std::collections::{HashMap, HashSet};
6use std::fmt::{Debug, Formatter};
7
8use std::path::PathBuf;
9use url::Url;
10
11pub trait Registry {
13 fn url(&self) -> Url;
15
16 fn supported(&self) -> Vec<DependencyType>;
18}
19
20assert_obj_safe!(Registry);
21
22pub struct RegistryContainer {
24 type_to_registry_index: HashMap<DependencyType, HashSet<usize>>,
25 registries: Vec<Box<dyn Registry>>,
26 cache_location: PathBuf,
27}
28
29impl Debug for RegistryContainer {
30 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
31 f.debug_struct("RegistryContainer")
32 .field("len", &self.registries.len())
33 .finish()
34 }
35}
36
37unsafe impl Send for RegistryContainer {}
38unsafe impl Sync for RegistryContainer {}
39
40impl Default for RegistryContainer {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl RegistryContainer {
47 pub fn new() -> Self {
49 let mut container = Self {
50 type_to_registry_index: Default::default(),
51 registries: vec![],
52 cache_location: AssembleCache::default().to_path_buf(),
53 };
54 container.add_registry(FileSystem::default());
55 container
56 }
57
58 pub fn add_registry<R: Registry + 'static>(&mut self, registry: R) {
60 let index = self.registries.len();
61 let boxed = Box::new(registry) as Box<dyn Registry>;
62 let dependency_types = boxed.supported();
63 self.registries.push(boxed);
64
65 for dependency_type in dependency_types {
66 self.type_to_registry_index
67 .entry(dependency_type)
68 .or_default()
69 .insert(index);
70 }
71 }
72
73 pub fn len(&self) -> usize {
75 self.registries.len()
76 }
77
78 pub fn supported_registries(&self, ty: &DependencyType) -> RegistrySet {
80 if let Some(entry) = self.type_to_registry_index.get(ty) {
81 entry
82 .iter()
83 .copied()
84 .map(|index| &*self.registries[index])
85 .collect()
86 } else {
87 RegistrySet::default()
88 }
89 }
90
91 pub fn supported_registries_intersection<'a, I>(&'a self, ty: I) -> RegistrySet<'a>
93 where
94 I: IntoIterator<Item = &'a DependencyType>,
95 {
96 ty.into_iter()
97 .map(|ty| self.supported_registries(ty))
98 .fold(RegistrySet::default(), RegistrySet::intersection)
99 }
100
101 pub fn set_cache_location(&mut self, cache_location: PathBuf) {
103 self.cache_location = cache_location;
104 }
105
106 pub fn cache_location(&self) -> &PathBuf {
108 &self.cache_location
109 }
110}
111
112#[derive(Default)]
113pub struct RegistrySet<'a> {
114 map: HashMap<Url, &'a dyn Registry>,
115}
116
117impl<'a> IntoIterator for RegistrySet<'a> {
118 type Item = &'a dyn Registry;
119 type IntoIter = IntoValues<Url, &'a dyn Registry>;
120
121 fn into_iter(self) -> Self::IntoIter {
122 self.map.into_values()
123 }
124}
125
126impl<'a> RegistrySet<'a> {
127 pub fn intersection(self, other: Self) -> Self {
129 let mut map = HashMap::new();
130 for (url, reg) in self.map {
131 if other.map.contains_key(&url) {
132 map.insert(url, reg);
133 }
134 }
135 Self { map }
136 }
137
138 pub fn registries(&self) -> impl IntoIterator<Item = &'a dyn Registry> {
140 self.map.values().copied().collect::<Vec<_>>()
141 }
142}
143
144impl<'a> FromIterator<&'a dyn Registry> for RegistrySet<'a> {
145 fn from_iter<T: IntoIterator<Item = &'a dyn Registry>>(iter: T) -> Self {
146 Self {
147 map: iter
148 .into_iter()
149 .map(|reg: &dyn Registry| (reg.url(), reg))
150 .collect(),
151 }
152 }
153}