melodium_engine/designer/
model.rs

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