melodium_common/descriptor/
loader.rs

1use crate::descriptor::{
2    Context, Function, Identifier, IdentifierRequirement, Model, PackageRequirement, Status,
3    Treatment,
4};
5use core::fmt::{Debug, Display, Formatter};
6use downcast_rs::{impl_downcast, Downcast};
7use std::{path::PathBuf, sync::Arc};
8
9#[derive(Debug, Clone)]
10pub enum LoadingErrorKind {
11    NoPackage {
12        package_requirement: PackageRequirement,
13    },
14    NoEntryPointProvided,
15    UnreachableFile {
16        path: PathBuf,
17        error: String,
18    },
19    WrongConfiguration {
20        package: String,
21    },
22    NotFound {
23        element: String,
24    },
25    CircularReference {
26        identifier: IdentifierRequirement,
27    },
28    RepositoryError {
29        error: Arc<dyn RepositoryError>,
30    },
31    ContentError {
32        error: Arc<dyn ContentError>,
33    },
34    ContextExpected {
35        expecter: Option<Identifier>,
36        identifier_requirement: IdentifierRequirement,
37    },
38    FunctionExpected {
39        expecter: Option<Identifier>,
40        identifier_requirement: IdentifierRequirement,
41    },
42    ModelExpected {
43        expecter: Option<Identifier>,
44        identifier_requirement: IdentifierRequirement,
45    },
46    TreatmentExpected {
47        expecter: Option<Identifier>,
48        identifier_requirement: IdentifierRequirement,
49    },
50    JeuFormatError {
51        error: String,
52    },
53    MappingFormatError {
54        error: String,
55    },
56    UncompatiblePlatform {
57        platform: String,
58    },
59    LibraryLoadingError {
60        path: PathBuf,
61        error: String,
62    },
63}
64
65impl Display for LoadingErrorKind {
66    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
67        match self {
68            LoadingErrorKind::NoPackage {
69                package_requirement,
70            } => write!(f, "No package '{package_requirement}' found"),
71            LoadingErrorKind::NoEntryPointProvided => write!(f, "No entry point provided"),
72            LoadingErrorKind::UnreachableFile { path, error } => write!(
73                f,
74                "File '{path}' cannot be read: {error}",
75                path = path.to_string_lossy()
76            ),
77            LoadingErrorKind::WrongConfiguration { package } => {
78                write!(f, "Package '{package}' have wrong configuration")
79            }
80            LoadingErrorKind::NotFound { element } => write!(f, "Element '{element}' not found"),
81            LoadingErrorKind::CircularReference { identifier } => {
82                write!(f, "Element '{identifier}' cause a circular reference")
83            }
84            LoadingErrorKind::RepositoryError { error } => write!(f, "{error}"),
85            LoadingErrorKind::ContentError { error } => write!(f, "{error}"),
86            LoadingErrorKind::ContextExpected {
87                expecter,
88                identifier_requirement,
89            } => match expecter {
90                Some(expecter) => write!(
91                    f,
92                    "'{expecter}' expected a context, but '{identifier_requirement}' is not"
93                ),
94                None => write!(f, "'{identifier_requirement}' is not a context"),
95            },
96            LoadingErrorKind::FunctionExpected {
97                expecter,
98                identifier_requirement,
99            } => match expecter {
100                Some(expecter) => write!(
101                    f,
102                    "'{expecter}' expected a function, but '{identifier_requirement}' is not"
103                ),
104                None => write!(f, "'{identifier_requirement}' is not a function"),
105            },
106            LoadingErrorKind::ModelExpected {
107                expecter,
108                identifier_requirement,
109            } => match expecter {
110                Some(expecter) => write!(
111                    f,
112                    "'{expecter}' expected a model, but '{identifier_requirement}' is not"
113                ),
114                None => write!(f, "'{identifier_requirement}' is not a model"),
115            },
116            LoadingErrorKind::TreatmentExpected {
117                expecter,
118                identifier_requirement,
119            } => match expecter {
120                Some(expecter) => write!(
121                    f,
122                    "'{expecter}' expected a treatment, but '{identifier_requirement}' is not"
123                ),
124                None => write!(f, "'{identifier_requirement}' is not a treatment"),
125            },
126            LoadingErrorKind::JeuFormatError { error } => {
127                write!(f, "Jeu data cannot be processed: {error}")
128            }
129            LoadingErrorKind::MappingFormatError { error } => {
130                write!(f, "Mapped package cannot be processed: {error}")
131            }
132            LoadingErrorKind::UncompatiblePlatform { platform } => {
133                write!(f, "Platform '{platform}' is not compatible")
134            }
135            LoadingErrorKind::LibraryLoadingError { path, error } => write!(
136                f,
137                "Loading '{path}' failed: {error}",
138                path = path.to_string_lossy()
139            ),
140        }
141    }
142}
143
144#[derive(Debug, Clone)]
145pub struct LoadingError {
146    pub id: u32,
147    pub kind: LoadingErrorKind,
148}
149
150impl LoadingError {
151    pub fn no_package(id: u32, package_requirement: PackageRequirement) -> Self {
152        Self {
153            id,
154            kind: LoadingErrorKind::NoPackage {
155                package_requirement,
156            },
157        }
158    }
159
160    pub fn no_entry_point_provided(id: u32) -> Self {
161        Self {
162            id,
163            kind: LoadingErrorKind::NoEntryPointProvided,
164        }
165    }
166
167    pub fn unreachable_file(id: u32, path: PathBuf, error: String) -> Self {
168        Self {
169            id,
170            kind: LoadingErrorKind::UnreachableFile { path, error },
171        }
172    }
173
174    pub fn wrong_configuration(id: u32, package: String) -> Self {
175        Self {
176            id,
177            kind: LoadingErrorKind::WrongConfiguration { package },
178        }
179    }
180
181    pub fn not_found(id: u32, element: String) -> Self {
182        Self {
183            id,
184            kind: LoadingErrorKind::NotFound { element },
185        }
186    }
187
188    pub fn circular_reference(id: u32, identifier: IdentifierRequirement) -> Self {
189        Self {
190            id,
191            kind: LoadingErrorKind::CircularReference { identifier },
192        }
193    }
194
195    pub fn repository_error(id: u32, error: Arc<dyn RepositoryError>) -> Self {
196        Self {
197            id,
198            kind: LoadingErrorKind::RepositoryError { error },
199        }
200    }
201
202    pub fn content_error(id: u32, error: Arc<dyn ContentError>) -> Self {
203        Self {
204            id,
205            kind: LoadingErrorKind::ContentError { error },
206        }
207    }
208
209    pub fn context_expected(
210        id: u32,
211        expecter: Option<Identifier>,
212        identifier_requirement: IdentifierRequirement,
213    ) -> Self {
214        Self {
215            id,
216            kind: LoadingErrorKind::ContextExpected {
217                expecter,
218                identifier_requirement,
219            },
220        }
221    }
222
223    pub fn function_expected(
224        id: u32,
225        expecter: Option<Identifier>,
226        identifier_requirement: IdentifierRequirement,
227    ) -> Self {
228        Self {
229            id,
230            kind: LoadingErrorKind::FunctionExpected {
231                expecter,
232                identifier_requirement,
233            },
234        }
235    }
236
237    pub fn model_expected(
238        id: u32,
239        expecter: Option<Identifier>,
240        identifier_requirement: IdentifierRequirement,
241    ) -> Self {
242        Self {
243            id,
244            kind: LoadingErrorKind::ModelExpected {
245                expecter,
246                identifier_requirement,
247            },
248        }
249    }
250
251    pub fn treatment_expected(
252        id: u32,
253        expecter: Option<Identifier>,
254        identifier_requirement: IdentifierRequirement,
255    ) -> Self {
256        Self {
257            id,
258            kind: LoadingErrorKind::TreatmentExpected {
259                expecter,
260                identifier_requirement,
261            },
262        }
263    }
264
265    pub fn jeu_format_error(id: u32, error: String) -> Self {
266        Self {
267            id,
268            kind: LoadingErrorKind::JeuFormatError { error },
269        }
270    }
271
272    pub fn mapping_format_error(id: u32, error: String) -> Self {
273        Self {
274            id,
275            kind: LoadingErrorKind::MappingFormatError { error },
276        }
277    }
278
279    pub fn uncompatible_platform(id: u32, platform: String) -> Self {
280        Self {
281            id,
282            kind: LoadingErrorKind::UncompatiblePlatform { platform },
283        }
284    }
285
286    pub fn library_loading_error(id: u32, path: PathBuf, error: String) -> Self {
287        Self {
288            id,
289            kind: LoadingErrorKind::LibraryLoadingError { path, error },
290        }
291    }
292}
293
294impl Display for LoadingError {
295    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
296        write!(f, "L{:04}: {}", self.id, self.kind)
297    }
298}
299
300pub type LoadingErrors = Vec<LoadingError>;
301pub type LoadingResult<T> = Status<T, LoadingError, LoadingError>;
302
303pub trait Loader {
304    fn load_context(
305        &self,
306        identifier_requirement: &IdentifierRequirement,
307    ) -> LoadingResult<Arc<dyn Context>>;
308    fn load_function(
309        &self,
310        identifier_requirement: &IdentifierRequirement,
311    ) -> LoadingResult<Arc<dyn Function>>;
312    fn load_model(
313        &self,
314        identifier_requirement: &IdentifierRequirement,
315    ) -> LoadingResult<Arc<dyn Model>>;
316    fn load_treatment(
317        &self,
318        identifier_requirement: &IdentifierRequirement,
319    ) -> LoadingResult<Arc<dyn Treatment>>;
320}
321
322pub trait RepositoryError: Display + Debug + Downcast + Send + Sync {}
323impl_downcast!(RepositoryError);
324
325pub type RepositoryErrors = Vec<Arc<dyn RepositoryError>>;
326
327pub trait ContentError: Display + Debug + Downcast + Send + Sync {}
328impl_downcast!(ContentError);
329
330pub type ContentErrors = Vec<Arc<dyn ContentError>>;