melodium_engine/designer/
model_instanciation.rs

1use super::{Parameter, Reference, Scope, Treatment, Value};
2use crate::design::ModelInstanciation as ModelInstanciationDesign;
3use crate::error::{LogicError, LogicResult};
4use core::fmt::Debug;
5use melodium_common::descriptor::{
6    Attribuable, Attribute, Attributes, Collection, Identified, Identifier,
7    Model as ModelDescriptor, Parameter as ParameterDescriptor, Treatment as TreatmentDescriptor,
8    Variability,
9};
10use std::collections::HashMap;
11use std::sync::{Arc, RwLock, Weak};
12
13#[derive(Debug)]
14pub struct ModelInstanciation {
15    host_descriptor: Weak<dyn TreatmentDescriptor>,
16    host_treatment: Weak<RwLock<Treatment>>,
17    host_id: Identifier,
18    descriptor: Weak<dyn ModelDescriptor>,
19    name: String,
20    parameters: HashMap<String, Arc<RwLock<Parameter>>>,
21    attributes: Attributes,
22    design_reference: Option<Arc<dyn Reference>>,
23
24    _auto_reference: Weak<RwLock<Self>>,
25}
26
27impl ModelInstanciation {
28    pub fn new(
29        host_descriptor: &Arc<dyn TreatmentDescriptor>,
30        host_treatment: &Arc<RwLock<Treatment>>,
31        host_id: Identifier,
32        descriptor: &Arc<dyn ModelDescriptor>,
33        name: &str,
34        design_reference: Option<Arc<dyn Reference>>,
35    ) -> Arc<RwLock<Self>> {
36        Arc::<RwLock<Self>>::new_cyclic(|me| {
37            RwLock::new(Self {
38                host_descriptor: Arc::downgrade(host_descriptor),
39                host_treatment: Arc::downgrade(host_treatment),
40                host_id,
41                descriptor: Arc::downgrade(descriptor),
42                name: name.to_string(),
43                parameters: HashMap::with_capacity(descriptor.parameters().len()),
44                attributes: Attributes::default(),
45                design_reference,
46                _auto_reference: me.clone(),
47            })
48        })
49    }
50
51    pub fn descriptor(&self) -> Arc<dyn ModelDescriptor> {
52        self.descriptor.upgrade().unwrap()
53    }
54
55    pub fn design_reference(&self) -> &Option<Arc<dyn Reference>> {
56        &self.design_reference
57    }
58
59    pub(crate) fn import_design(
60        &mut self,
61        design: &ModelInstanciationDesign,
62        collection: &Arc<Collection>,
63        replace: &HashMap<Identifier, Identifier>,
64    ) -> LogicResult<()> {
65        let mut result = LogicResult::new_success(());
66
67        for (name, parameter_design) in &design.parameters {
68            if let Some(parameter) = result
69                .merge_degrade_failure(self.add_parameter(name, self.design_reference.clone()))
70            {
71                result.merge_degrade_failure(parameter.write().unwrap().import_design(
72                    parameter_design,
73                    collection,
74                    replace,
75                ));
76            }
77        }
78
79        result
80    }
81
82    pub fn name(&self) -> &str {
83        &self.name
84    }
85
86    pub(super) fn set_name(&mut self, name: String) {
87        self.name = name;
88    }
89
90    pub fn add_attribute(&mut self, name: String, attribute: Attribute) {
91        self.attributes.insert(name, attribute);
92    }
93
94    pub fn remove_attribute(&mut self, name: &str) -> bool {
95        match self.attributes.remove(name) {
96            Some(_) => true,
97            None => false,
98        }
99    }
100
101    pub fn add_parameter(
102        &mut self,
103        name: &str,
104        design_reference: Option<Arc<dyn Reference>>,
105    ) -> LogicResult<Arc<RwLock<Parameter>>> {
106        let mut result = LogicResult::new_success(());
107
108        let host_descriptor = self.host_descriptor.upgrade().unwrap();
109        let parameter = Parameter::new(
110            &(self.host_treatment.upgrade().unwrap() as Arc<RwLock<dyn Scope>>),
111            &host_descriptor.as_parameterized(),
112            &Arc::new(RwLock::new(HashMap::new())),
113            self.host_id.clone(),
114            &self.descriptor().as_parameterized(),
115            &Arc::new(RwLock::new(HashMap::new())),
116            name,
117            design_reference.clone(),
118        );
119        let rc_parameter = Arc::new(RwLock::new(parameter));
120
121        if self
122            .parameters
123            .insert(name.to_string(), Arc::clone(&rc_parameter))
124            .is_some()
125        {
126            result = result.and_degrade_failure(LogicResult::new_failure(
127                LogicError::multiple_parameter_assignation(
128                    24,
129                    self.host_id.clone(),
130                    self.descriptor().identifier().clone(),
131                    name.to_string(),
132                    design_reference.clone(),
133                ),
134            ));
135        }
136
137        if !self.descriptor().parameters().contains_key(name) {
138            result.errors_mut().push(LogicError::unexisting_parameter(
139                10,
140                self.host_id.clone(),
141                self.descriptor().identifier().clone(),
142                self.name.clone(),
143                design_reference,
144            ));
145        }
146
147        result.and(Ok(rc_parameter).into())
148    }
149
150    pub fn remove_parameter(&mut self, name: &str) -> LogicResult<bool> {
151        if let Some(_) = self.parameters.remove(name) {
152            Ok(true).into()
153        } else {
154            Ok(false).into()
155        }
156    }
157
158    pub fn parameters(&self) -> &HashMap<String, Arc<RwLock<Parameter>>> {
159        &self.parameters
160    }
161
162    pub fn validate(&self) -> LogicResult<()> {
163        let mut result = LogicResult::new_success(());
164
165        let rc_host = self.host_treatment.upgrade().unwrap();
166        let host = rc_host.read().unwrap();
167        let descriptor = self.descriptor();
168
169        result = self
170            .parameters
171            .iter()
172            .fold(result, |mut result, (name, param)| {
173                if !self.descriptor().parameters().contains_key(name) {
174                    result.errors_mut().push(LogicError::unexisting_parameter(
175                        193,
176                        host.identifier().clone(),
177                        descriptor.identifier().clone(),
178                        self.name.clone(),
179                        self.design_reference.clone(),
180                    ));
181                }
182
183                result.and_degrade_failure(param.read().unwrap().validate())
184            });
185
186        // Check if all model parameters are filled.
187        let unset_params: Vec<&ParameterDescriptor> = descriptor
188            .parameters()
189            .iter()
190            .filter_map(|(core_param_name, core_param)| {
191                if self.parameters.contains_key(core_param_name) {
192                    None
193                } else if core_param.default().is_some() {
194                    None
195                } else {
196                    Some(core_param)
197                }
198            })
199            .collect();
200        for unset_param in unset_params {
201            result.errors_mut().push(LogicError::unset_parameter(
202                22,
203                host.descriptor().identifier().clone(),
204                descriptor.identifier().clone(),
205                unset_param.name().to_string(),
206                self.design_reference.clone(),
207            ));
208        }
209        if result.has_errors() || result.is_failure() {
210            return result;
211        }
212
213        // Check all parameters does not refers to a context.
214        for (name, param) in self.parameters.iter().filter(|&(_param_name, param)| {
215            matches!(param.read().unwrap().value(), Some(Value::Context { .. }))
216        }) {
217            result.errors_mut().push(LogicError::no_context(
218                28,
219                host.descriptor().identifier().clone(),
220                descriptor.identifier().clone(),
221                self.name.clone(),
222                name.to_string(),
223                param.read().unwrap().design_reference().clone(),
224            ));
225        }
226
227        // Check all parameters are const.
228        for (name, param) in self.parameters.iter().filter(|&(param_name, param)| {
229            *param
230                .read()
231                .unwrap()
232                .parent_descriptor()
233                .upgrade()
234                .unwrap()
235                .parameters()
236                .get(param_name)
237                .unwrap()
238                .variability()
239                != Variability::Const
240        }) {
241            result
242                .errors_mut()
243                .push(LogicError::model_instanciation_const_only(
244                    62,
245                    host.descriptor().identifier().clone(),
246                    descriptor.identifier().clone(),
247                    self.name.clone(),
248                    name.to_string(),
249                    param.read().unwrap().design_reference().clone(),
250                ));
251        }
252
253        result
254    }
255}
256
257impl Attribuable for ModelInstanciation {
258    fn attributes(&self) -> &Attributes {
259        &self.attributes
260    }
261}