melodium_engine/descriptor/
treatment.rs

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    /**
404     * Clone treatment descriptor.
405     *
406     * The descriptor and its inner descriptive elements are all cloned, but not the designer nor the related design.
407     * The cloned descriptor need to be commited.
408     */
409    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}