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>>;