1use crate::design::Treatment as Design;
2use crate::designer::{Reference, Treatment as Designer};
3use crate::error::{LogicError, LogicResult};
4use core::fmt::{Display, Formatter, Result as FmtResult};
5use melodium_common::descriptor::{
6 Attribuable, Attribute, Attributes, Buildable, Collection, Context, Documented, Entry, Generic,
7 Generics, Identified, Identifier, Input, Model, Output, Parameter, Parameterized, Status,
8 Treatment as TreatmentDescriptor, TreatmentBuildMode,
9};
10use std::collections::HashMap;
11use std::sync::{Arc, Mutex, RwLock, Weak};
12
13#[derive(Debug)]
14pub struct Treatment {
15 identifier: Identifier,
16 #[cfg(feature = "doc")]
17 documentation: String,
18 attributes: Attributes,
19 generics: Vec<Generic>,
20 models: HashMap<String, Arc<dyn Model>>,
21 parameters: HashMap<String, Parameter>,
22 inputs: HashMap<String, Input>,
23 outputs: HashMap<String, Output>,
24 contexts: HashMap<String, Arc<dyn Context>>,
25 designer: Mutex<Option<Arc<RwLock<Designer>>>>,
26 design: Mutex<Option<Arc<Design>>>,
27 auto_reference: Weak<Self>,
28}
29
30impl Treatment {
31 pub fn new(identifier: Identifier) -> Self {
32 Self {
33 identifier,
34 #[cfg(feature = "doc")]
35 documentation: String::new(),
36 attributes: Attributes::default(),
37 generics: Vec::new(),
38 models: HashMap::new(),
39 parameters: HashMap::new(),
40 inputs: HashMap::new(),
41 outputs: HashMap::new(),
42 contexts: HashMap::new(),
43 designer: Mutex::new(None),
44 design: Mutex::new(None),
45 auto_reference: Weak::default(),
46 }
47 }
48
49 pub fn set_identifier(&mut self, identifier: Identifier) {
50 self.identifier = identifier;
51 }
52
53 pub fn reset_designer(&self) {
54 let mut option_designer = self.designer.lock().expect("Mutex poisoned");
55 *option_designer = None;
56 }
57
58 pub fn designer(
59 &self,
60 collection: Arc<Collection>,
61 design_reference: Option<Arc<dyn Reference>>,
62 ) -> LogicResult<Arc<RwLock<Designer>>> {
63 if self.auto_reference.strong_count() == 0 {
64 return Status::new_failure(
65 LogicError::uncommited_descriptor(3, self.identifier.clone(), None).into(),
66 );
67 }
68
69 let mut option_designer = self.designer.lock().expect("Mutex poisoned");
70
71 if let Some(designer_ref) = &*option_designer {
72 Status::new_success(designer_ref.clone())
73 } else {
74 let new_designer = Designer::new(
75 &self.auto_reference.upgrade().unwrap(),
76 collection,
77 design_reference,
78 );
79
80 *option_designer = Some(new_designer.clone());
81
82 Status::new_success(new_designer)
83 }
84 }
85
86 pub fn commit_design(&self) -> LogicResult<()> {
87 let option_designer = self.designer.lock().expect("Mutex poisoned");
88 let mut option_design = self.design.lock().expect("Mutex poisoned");
89
90 if let Some(designer_ref) = &*option_designer {
91 let designer = designer_ref.read().unwrap();
92 let mut result_design = designer.design();
93
94 if result_design.is_success() && result_design.has_errors() {
95 result_design =
96 result_design.and(Status::new_failure(LogicError::erroneous_design(
97 68,
98 self.identifier.clone(),
99 designer.design_reference().clone(),
100 )));
101 }
102
103 result_design.and_then(|design| {
104 *option_design = Some(Arc::new(design));
105 Status::new_success(())
106 })
107 } else {
108 Status::new_failure(LogicError::no_designer(67, self.identifier.clone(), None))
109 }
110 }
111
112 pub fn design(&self) -> LogicResult<Arc<Design>> {
113 let option_design = self.design.lock().expect("Mutex poisoned");
114
115 option_design
116 .as_ref()
117 .map(|design| Arc::clone(design))
118 .ok_or_else(|| LogicError::unavailable_design(5, self.identifier.clone(), None).into())
119 .into()
120 }
121
122 pub fn update_with_collection(
123 &mut self,
124 collection: &Collection,
125 replace: &HashMap<Identifier, Identifier>,
126 ) -> LogicResult<()> {
127 let mut result = LogicResult::new_success(());
128
129 let mut new_models = HashMap::new();
130 for (name, model) in &self.models {
131 let model_identifier = replace
132 .get(model.identifier())
133 .unwrap_or_else(|| model.identifier());
134 if let Some(Entry::Model(model)) = collection.get(&model_identifier.into()) {
135 new_models.insert(name.clone(), model.clone());
136 } else {
137 result.errors_mut().push(LogicError::unexisting_model(
138 206,
139 self.identifier.clone(),
140 model_identifier.into(),
141 None,
142 ))
143 }
144 }
145 self.models = new_models;
146
147 let mut new_contexts = HashMap::new();
148 for (name, context) in &self.contexts {
149 let context_identifier = replace
150 .get(context.identifier())
151 .unwrap_or_else(|| context.identifier());
152 if let Some(Entry::Context(context)) = collection.get(&context_identifier.into()) {
153 new_contexts.insert(name.clone(), context.clone());
154 } else {
155 result.errors_mut().push(LogicError::unexisting_context(
156 207,
157 self.identifier.clone(),
158 context_identifier.into(),
159 None,
160 ))
161 }
162 }
163 self.contexts = new_contexts;
164
165 result
166 }
167
168 pub fn set_documentation(&mut self, documentation: &str) {
169 #[cfg(feature = "doc")]
170 {
171 self.documentation = String::from(documentation);
172 }
173 #[cfg(not(feature = "doc"))]
174 let _ = documentation;
175 }
176
177 pub fn add_attribute(&mut self, name: String, attribute: Attribute) {
178 self.attributes.insert(name, attribute);
179 }
180
181 pub fn remove_attribute(&mut self, name: &str) -> bool {
182 match self.attributes.remove(name) {
183 Some(_) => true,
184 None => false,
185 }
186 }
187
188 pub fn add_generic(&mut self, generic: Generic) {
189 self.generics.retain(|gen| gen.name != generic.name);
190 self.generics.push(generic);
191 }
192
193 pub fn remove_generic(&mut self, name: &str) -> bool {
194 let mut found = false;
195 self.generics.retain(|gen| {
196 if gen.name != name {
197 found = true;
198 false
199 } else {
200 true
201 }
202 });
203 found
204 }
205
206 pub fn add_model(&mut self, name: &str, model: &Arc<dyn Model>) {
207 self.models.insert(name.to_string(), Arc::clone(model));
208 }
209
210 pub fn remove_model(&mut self, name: &str) -> bool {
211 self.models.remove(name).is_some()
212 }
213
214 pub fn add_parameter(&mut self, parameter: Parameter) {
215 self.parameters
216 .insert(parameter.name().to_string(), parameter);
217 }
218
219 pub fn remove_parameter(&mut self, name: &str) -> bool {
220 self.parameters.remove(name).is_some()
221 }
222
223 pub fn add_input(&mut self, input: Input) {
224 self.inputs.insert(input.name().to_string(), input);
225 }
226
227 pub fn remove_input(&mut self, name: &str) -> bool {
228 match self.inputs.remove(name) {
229 Some(_) => true,
230 None => false,
231 }
232 }
233
234 pub fn add_output(&mut self, output: Output) {
235 self.outputs.insert(output.name().to_string(), output);
236 }
237
238 pub fn remove_output(&mut self, name: &str) -> bool {
239 match self.outputs.remove(name) {
240 Some(_) => true,
241 None => false,
242 }
243 }
244
245 pub fn add_context(&mut self, context: &Arc<dyn Context>) {
246 self.contexts
247 .insert(context.name().to_string(), context.clone());
248 }
249
250 pub fn remove_context(&mut self, name: &str) -> bool {
251 match self.contexts.remove(name) {
252 Some(_) => true,
253 None => false,
254 }
255 }
256
257 pub fn commit(self) -> Arc<Self> {
258 Arc::new_cyclic(|me| Self {
259 identifier: self.identifier,
260 #[cfg(feature = "doc")]
261 documentation: self.documentation,
262 attributes: self.attributes,
263 generics: self.generics,
264 models: self.models,
265 parameters: self.parameters,
266 inputs: self.inputs,
267 outputs: self.outputs,
268 contexts: self.contexts,
269 designer: self.designer,
270 design: self.design,
271 auto_reference: me.clone(),
272 })
273 }
274}
275
276impl Attribuable for Treatment {
277 fn attributes(&self) -> &Attributes {
278 &self.attributes
279 }
280}
281
282impl Identified for Treatment {
283 fn identifier(&self) -> &Identifier {
284 &self.identifier
285 }
286
287 fn make_use(&self, identifier: &Identifier) -> bool {
288 self.models
289 .iter()
290 .any(|(_, model)| model.identifier() == identifier || model.make_use(identifier))
291 || self
292 .contexts
293 .values()
294 .any(|context| context.identifier() == identifier || context.make_use(identifier))
295 || self.inputs.values().any(|input| {
296 input
297 .described_type()
298 .final_type()
299 .data()
300 .map(|data| data.identifier() == identifier || data.make_use(identifier))
301 .unwrap_or(false)
302 })
303 || self.outputs.values().any(|output| {
304 output
305 .described_type()
306 .final_type()
307 .data()
308 .map(|data| data.identifier() == identifier || data.make_use(identifier))
309 .unwrap_or(false)
310 })
311 || self.parameters.values().any(|parameter| {
312 parameter
313 .described_type()
314 .final_type()
315 .data()
316 .map(|data| data.identifier() == identifier || data.make_use(identifier))
317 .unwrap_or(false)
318 })
319 || self
320 .design
321 .lock()
322 .unwrap()
323 .as_ref()
324 .map(|design| design.make_use(identifier))
325 .unwrap_or(false)
326 || self
327 .designer
328 .lock()
329 .unwrap()
330 .as_ref()
331 .map(|designer| designer.read().unwrap().make_use(identifier))
332 .unwrap_or(false)
333 }
334
335 fn uses(&self) -> Vec<Identifier> {
336 let mut uses = Vec::new();
337 self.models.values().for_each(|model| {
338 uses.push(model.identifier().clone());
339 uses.extend(model.uses());
340 });
341 self.contexts.values().for_each(|context| {
342 uses.push(context.identifier().clone());
343 uses.extend(context.uses());
344 });
345 self.inputs.values().for_each(|input| {
346 if let Some(data) = input.described_type().final_type().data() {
347 uses.push(data.identifier().clone());
348 uses.extend(data.uses());
349 }
350 });
351 self.outputs.values().for_each(|output| {
352 if let Some(data) = output.described_type().final_type().data() {
353 uses.push(data.identifier().clone());
354 uses.extend(data.uses());
355 }
356 });
357 self.parameters.values().for_each(|parameter| {
358 if let Some(data) = parameter.described_type().final_type().data() {
359 uses.push(data.identifier().clone());
360 uses.extend(data.uses());
361 }
362 });
363 if let Some(design) = self.design.lock().unwrap().as_ref() {
364 uses.extend(design.uses());
365 }
366 if let Some(designer) = self.designer.lock().unwrap().as_ref() {
367 uses.extend(designer.read().unwrap().uses());
368 }
369 uses
370 }
371}
372
373impl Documented for Treatment {
374 fn documentation(&self) -> &str {
375 #[cfg(feature = "doc")]
376 {
377 &self.documentation
378 }
379 #[cfg(not(feature = "doc"))]
380 {
381 &""
382 }
383 }
384}
385
386impl Parameterized for Treatment {
387 fn parameters(&self) -> &HashMap<String, Parameter> {
388 &self.parameters
389 }
390
391 fn as_identified(&self) -> Arc<dyn Identified> {
392 self.auto_reference.upgrade().unwrap()
393 }
394}
395
396impl Buildable<TreatmentBuildMode> for Treatment {
397 fn build_mode(&self) -> TreatmentBuildMode {
398 TreatmentBuildMode::Designed()
399 }
400}
401
402impl Clone for Treatment {
403 fn clone(&self) -> Self {
410 Self {
411 identifier: self.identifier.clone(),
412 #[cfg(feature = "doc")]
413 documentation: self.documentation.clone(),
414 attributes: self.attributes.clone(),
415 generics: self.generics.clone(),
416 models: self.models.clone(),
417 parameters: self.parameters.clone(),
418 inputs: self.inputs.clone(),
419 outputs: self.outputs.clone(),
420 contexts: self.contexts.clone(),
421 designer: Mutex::new(None),
422 design: Mutex::new(None),
423 auto_reference: Weak::default(),
424 }
425 }
426}
427
428impl Display for Treatment {
429 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
430 write!(f, "treatment {}", self.identifier.to_string())?;
431
432 if !self.models.is_empty() {
433 write!(
434 f,
435 "[{}]",
436 self.models
437 .iter()
438 .map(|(n, m)| format!("{}: {}", n, m.identifier().to_string()))
439 .collect::<Vec<_>>()
440 .join(", "),
441 )?;
442 }
443
444 write!(
445 f,
446 "({})",
447 self.parameters()
448 .iter()
449 .map(|(_, p)| p.to_string())
450 .collect::<Vec<_>>()
451 .join(", ")
452 )?;
453
454 Ok(())
455 }
456}
457
458impl TreatmentDescriptor for Treatment {
459 fn inputs(&self) -> &HashMap<String, Input> {
460 &self.inputs
461 }
462
463 fn outputs(&self) -> &HashMap<String, Output> {
464 &self.outputs
465 }
466
467 fn models(&self) -> &HashMap<String, Arc<dyn Model>> {
468 &self.models
469 }
470
471 fn contexts(&self) -> &HashMap<String, Arc<dyn Context>> {
472 &self.contexts
473 }
474
475 fn source_from(&self) -> &HashMap<String, Vec<String>> {
476 lazy_static! {
477 static ref HASHMAP: HashMap<String, Vec<String>> = HashMap::new();
478 };
479 &HASHMAP
480 }
481
482 fn as_identified(&self) -> Arc<dyn Identified> {
483 self.auto_reference.upgrade().unwrap()
484 }
485
486 fn as_buildable(&self) -> Arc<dyn Buildable<TreatmentBuildMode>> {
487 self.auto_reference.upgrade().unwrap()
488 }
489
490 fn as_parameterized(&self) -> Arc<dyn Parameterized> {
491 self.auto_reference.upgrade().unwrap()
492 }
493}
494
495impl Generics for Treatment {
496 fn generics(&self) -> &Vec<Generic> {
497 &self.generics
498 }
499}