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