melodium_loader/
loader.rs

1use crate::package::PackageTrait as Package;
2use crate::package_manager::{PackageManager, PackageManagerConfiguration};
3use crate::{LoadingConfig, PackageInfo};
4use melodium_common::descriptor::{
5    Collection, Context, Entry, Function, Identified, Identifier, IdentifierRequirement,
6    Loader as LoaderTrait, LoadingError, LoadingResult, Model, PackageRequirement, Treatment,
7};
8use std::collections::HashMap;
9use std::sync::{Arc, RwLock, RwLockReadGuard};
10
11/**
12 * Manages loading of Mélodium packages.
13 *
14 * The loader take care of managing package dependencies, loading inner elements of packages,
15 * and building a coherent [Collection].
16 *
17 * Loading can be made through the `load`-ing functions, and then final collection rendered using `build()`.
18 *
19 * This loader aims to be lazy, please read carefully the behavior of each `load`-ing function in order to make best
20 * use of them.
21 */
22#[derive(Debug)]
23pub struct Loader {
24    collection: RwLock<Collection>,
25    package_manager: PackageManager,
26}
27
28impl Loader {
29    pub fn new(config: LoadingConfig) -> Self {
30        Self {
31            collection: RwLock::new(Collection::new()),
32            package_manager: PackageManager::new(PackageManagerConfiguration {
33                repositories: vec![
34                    #[cfg(feature = "filesystem")]
35                    Arc::new(std::sync::Mutex::new(melodium_repository::Repository::new(
36                        melodium_repository::RepositoryConfig {
37                            repository_location: {
38                                let mut path = std::env::var_os("MELODIUM_HOME")
39                                    .map(|var| var.into())
40                                    .or_else(|| {
41                                        simple_home_dir::home_dir().map(|mut path| {
42                                            path.push(".melodium");
43                                            path
44                                        })
45                                    })
46                                    .unwrap_or_else(|| {
47                                        let mut path = std::env::temp_dir();
48                                        path.push("melodium");
49                                        path
50                                    });
51                                path.push(env!("CARGO_PKG_VERSION"));
52                                path
53                            },
54                            network: if cfg!(feature = "network") {
55                                Some(melodium_repository::network::NetworkRepositoryConfiguration::new())
56                            } else {
57                                None
58                            },
59                        },
60                    ))),
61                ],
62                core_packages: config.core_packages,
63                search_locations: config.search_locations,
64                raw_elements: config.raw_elements,
65                allow_network: cfg!(feature = "network"),
66            }),
67        }
68    }
69
70    /**
71     * Loads the given package, according to requirements.
72     *
73     * This function _does not_ load any package content on its own, see [Self::load], [Self::load_all] or the functions of [LoaderTrait]
74     * to get elements required loaded.
75     */
76    pub fn load_package(
77        &self,
78        requirement: &PackageRequirement,
79    ) -> LoadingResult<Arc<dyn PackageInfo>> {
80        self.package_manager
81            .get_package(requirement)
82            .and_then(|pkg| LoadingResult::new_success(Arc::clone(&pkg) as Arc<dyn PackageInfo>))
83    }
84
85    /**
86     * Loads the given raw package content.
87     *
88     * This function _does not_ load any package content on its own, see [Self::load], [Self::load_all] or the functions of [LoaderTrait]
89     * to get elements required loaded.
90     */
91    pub fn load_raw(&self, raw_content: Arc<Vec<u8>>) -> LoadingResult<Arc<dyn PackageInfo>> {
92        self.package_manager
93            .add_raw_package(raw_content)
94            .and_then(|pkg| LoadingResult::new_success(Arc::clone(&pkg) as Arc<dyn PackageInfo>))
95    }
96
97    /**
98     * Loads the given mapped package content.
99     *
100     * This function _does not_ load any package content on its own, see [Self::load], [Self::load_all] or the functions of [LoaderTrait]
101     * to get elements required loaded.
102     */
103    pub fn load_mapped(
104        &self,
105        mapped_content: HashMap<String, Vec<u8>>,
106    ) -> LoadingResult<Arc<dyn PackageInfo>> {
107        self.package_manager
108            .add_map_package(mapped_content)
109            .and_then(|pkg| LoadingResult::new_success(Arc::clone(&pkg) as Arc<dyn PackageInfo>))
110    }
111
112    /**
113     * Load the given identifier.
114     */
115    pub fn load(
116        &self,
117        identifier_requirement: &IdentifierRequirement,
118    ) -> LoadingResult<Identifier> {
119        self.get_with_load(identifier_requirement)
120            .and_then(|entry| LoadingResult::new_success(entry.identifier().clone()))
121    }
122
123    /**
124     * Load all the elements from all the packages.
125     *
126     * Packages concerned have to be already loaded through [Self::load_package] of [Self::load_raw] functions.
127     */
128    pub fn load_all(&self) -> LoadingResult<()> {
129        let mut result = LoadingResult::new_success(());
130        for package in self.package_manager.get_packages() {
131            if let Some(additions) = result.merge_degrade_failure(package.full_collection(self)) {
132                self.add_collection(additions);
133            }
134        }
135        result
136    }
137
138    /**
139     * Proceed to build of coherent collection.
140     */
141    pub fn build(&self) -> LoadingResult<Arc<Collection>> {
142        let mut result = LoadingResult::new_success(());
143        let collection = Arc::new(self.collection.read().unwrap().clone());
144
145        for package in self.package_manager.get_packages() {
146            result.merge_degrade_failure(package.make_building(&collection));
147        }
148
149        result.and(LoadingResult::new_success(collection))
150    }
151
152    pub fn packages(&self) -> Vec<Arc<dyn PackageInfo>> {
153        self.package_manager
154            .get_packages()
155            .into_iter()
156            .map(|pkg| Arc::clone(&pkg) as Arc<dyn PackageInfo>)
157            .collect()
158    }
159
160    pub fn collection(&'_ self) -> RwLockReadGuard<'_, Collection> {
161        self.collection.read().unwrap()
162    }
163
164    pub fn get_with_load(
165        &self,
166        identifier_requirement: &IdentifierRequirement,
167    ) -> LoadingResult<Entry> {
168        let mut result = LoadingResult::new_success(());
169        let entry = self
170            .collection
171            .read()
172            .unwrap()
173            .get(identifier_requirement)
174            .cloned();
175        if let Some(entry) = entry {
176            result.and_degrade_failure(LoadingResult::new_success(entry))
177        } else if let Some(package) = result.merge_degrade_failure(
178            self.package_manager
179                .get_package(&identifier_requirement.package_requirement()),
180        ) {
181            package
182                .element(self, &identifier_requirement)
183                .and_then(|additions| {
184                    self.add_collection(additions);
185                    if let Some(element) = self
186                        .collection
187                        .read()
188                        .unwrap()
189                        .get(identifier_requirement)
190                        .cloned()
191                    {
192                        result.and_degrade_failure(LoadingResult::new_success(element))
193                    } else {
194                        result.and_degrade_failure(LoadingResult::new_failure(
195                            LoadingError::not_found(249, identifier_requirement.to_string()),
196                        ))
197                    }
198                })
199        } else {
200            result.and_degrade_failure(LoadingResult::new_failure(LoadingError::no_package(
201                167,
202                identifier_requirement.package_requirement(),
203            )))
204        }
205    }
206
207    fn add_collection(&self, other_collection: Collection) {
208        let existing = self.collection.read().unwrap().identifiers();
209        let mut others = other_collection.identifiers();
210
211        others.retain(|id| !existing.contains(id));
212
213        if !others.is_empty() {
214            let mut collection = self.collection.write().unwrap();
215            for id in &others {
216                collection.insert(other_collection.get(&id.into()).unwrap().clone());
217            }
218        }
219    }
220}
221
222impl LoaderTrait for Loader {
223    fn load_context(
224        &self,
225        identifier_requirement: &IdentifierRequirement,
226    ) -> LoadingResult<Arc<dyn Context>> {
227        self.get_with_load(identifier_requirement)
228            .and_then(|entry| match entry {
229                Entry::Context(context) => LoadingResult::new_success(context),
230                _ => LoadingResult::new_failure(LoadingError::context_expected(
231                    168,
232                    None,
233                    identifier_requirement.clone(),
234                )),
235            })
236    }
237
238    fn load_function(
239        &self,
240        identifier_requirement: &IdentifierRequirement,
241    ) -> LoadingResult<Arc<dyn Function>> {
242        self.get_with_load(identifier_requirement)
243            .and_then(|entry| match entry {
244                Entry::Function(function) => LoadingResult::new_success(function),
245                _ => LoadingResult::new_failure(LoadingError::function_expected(
246                    169,
247                    None,
248                    identifier_requirement.clone(),
249                )),
250            })
251    }
252
253    fn load_model(
254        &self,
255        identifier_requirement: &IdentifierRequirement,
256    ) -> LoadingResult<Arc<dyn Model>> {
257        self.get_with_load(identifier_requirement)
258            .and_then(|entry| match entry {
259                Entry::Model(model) => LoadingResult::new_success(model),
260                _ => LoadingResult::new_failure(LoadingError::model_expected(
261                    170,
262                    None,
263                    identifier_requirement.clone(),
264                )),
265            })
266    }
267
268    fn load_treatment(
269        &self,
270        identifier_requirement: &IdentifierRequirement,
271    ) -> LoadingResult<Arc<dyn Treatment>> {
272        self.get_with_load(identifier_requirement)
273            .and_then(|entry| match entry {
274                Entry::Treatment(treatment) => LoadingResult::new_success(treatment),
275                _ => LoadingResult::new_failure(LoadingError::treatment_expected(
276                    171,
277                    None,
278                    identifier_requirement.clone(),
279                )),
280            })
281    }
282}