melodium_engine/designer/
model_instanciation.rs1use 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 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 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 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}