melodium_engine/descriptor/
model.rs1use crate::design::Model as Design;
2use crate::designer::{Model as Designer, Reference};
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, Model as ModelDescriptor, ModelBuildMode, Parameter,
8 Parameterized, Status, Variability,
9};
10use std::collections::HashMap;
11use std::sync::{Arc, Mutex, OnceLock, RwLock, Weak};
12
13#[derive(Debug)]
14pub struct Model {
15 identifier: Identifier,
16 #[cfg(feature = "doc")]
17 documentation: String,
18 attributes: Attributes,
19 base_model: Arc<dyn ModelDescriptor>,
20 parameters: HashMap<String, Parameter>,
21 designer: Mutex<Option<Arc<RwLock<Designer>>>>,
22 design: Mutex<Option<Arc<Design>>>,
23 auto_reference: Weak<Self>,
24}
25
26impl Model {
27 pub fn new(identifier: Identifier, base_model: &Arc<dyn ModelDescriptor>) -> Self {
28 Self {
29 identifier,
30 #[cfg(feature = "doc")]
31 documentation: String::new(),
32 attributes: Attributes::default(),
33 base_model: Arc::clone(base_model),
34 parameters: HashMap::new(),
35 designer: Mutex::new(None),
36 design: Mutex::new(None),
37 auto_reference: Weak::default(),
38 }
39 }
40
41 pub fn set_identifier(&mut self, identifier: Identifier) {
42 self.identifier = identifier;
43 }
44
45 pub fn reset_designer(&self) {
46 let mut option_designer = self.designer.lock().expect("Mutex poisoned");
47 *option_designer = None;
48 }
49
50 pub fn designer(
51 &self,
52 collection: Arc<Collection>,
53 design_reference: Option<Arc<dyn Reference>>,
54 ) -> LogicResult<Arc<RwLock<Designer>>> {
55 if self.auto_reference.strong_count() == 0 {
56 return Status::new_failure(
57 LogicError::uncommited_descriptor(2, self.identifier.clone(), design_reference)
58 .into(),
59 );
60 }
61
62 let mut option_designer = self.designer.lock().expect("Mutex poisoned");
63
64 if let Some(designer_ref) = &*option_designer {
65 Status::new_success(designer_ref.clone())
66 } else {
67 let new_designer = Designer::new(
68 &self.auto_reference.upgrade().unwrap(),
69 collection,
70 design_reference,
71 );
72
73 *option_designer = Some(new_designer.clone());
74
75 Status::new_success(new_designer)
76 }
77 }
78
79 pub fn commit_design(&self) -> LogicResult<()> {
80 let option_designer = self.designer.lock().expect("Mutex poisoned");
81 let mut option_design = self.design.lock().expect("Mutex poisoned");
82
83 if let Some(designer_ref) = &*option_designer {
84 let designer = designer_ref.read().unwrap();
85 let mut result_design = designer.design();
86
87 if result_design.is_success() && result_design.has_errors() {
88 result_design =
89 result_design.and(Status::new_failure(LogicError::erroneous_design(
90 66,
91 self.identifier.clone(),
92 designer.design_reference().clone(),
93 )));
94 }
95
96 result_design.and_then(|design| {
97 *option_design = Some(Arc::new(design));
98 Status::new_success(())
99 })
100 } else {
101 Status::new_failure(LogicError::no_designer(65, self.identifier.clone(), None))
102 }
103 }
104
105 pub fn design(&self) -> LogicResult<Arc<Design>> {
106 let option_design = self.design.lock().expect("Mutex poisoned");
107
108 option_design
109 .as_ref()
110 .map(|design| Arc::clone(design))
111 .ok_or_else(|| LogicError::unavailable_design(4, self.identifier.clone(), None).into())
112 .into()
113 }
114
115 pub fn update_with_collection(
116 &mut self,
117 collection: &Collection,
118 replace: &HashMap<Identifier, Identifier>,
119 ) -> LogicResult<()> {
120 let base_identifier = replace
121 .get(self.base_model.identifier())
122 .unwrap_or_else(|| self.base_model.identifier());
123 if let Some(Entry::Model(base_model)) = collection.get(&base_identifier.into()) {
124 self.base_model = base_model.clone();
125 LogicResult::new_success(())
126 } else {
127 LogicResult::new_failure(LogicError::unexisting_model(
128 208,
129 self.identifier.clone(),
130 base_identifier.into(),
131 None,
132 ))
133 }
134 }
135
136 pub fn set_documentation(&mut self, documentation: &str) {
137 #[cfg(feature = "doc")]
138 {
139 self.documentation = String::from(documentation);
140 }
141 #[cfg(not(feature = "doc"))]
142 let _ = documentation;
143 }
144
145 pub fn add_attribute(&mut self, name: String, attribute: Attribute) {
146 self.attributes.insert(name, attribute);
147 }
148
149 pub fn remove_attribute(&mut self, name: &str) -> bool {
150 match self.attributes.remove(name) {
151 Some(_) => true,
152 None => false,
153 }
154 }
155
156 pub fn add_parameter(&mut self, mut parameter: Parameter) {
157 if parameter.variability() != &Variability::Const {
158 parameter = Parameter::new(
159 parameter.name(),
160 Variability::Const,
161 parameter.described_type().clone(),
162 parameter.default().clone(),
163 parameter.attributes().clone(),
164 );
165 }
166 self.parameters
167 .insert(parameter.name().to_string(), parameter);
168 }
169
170 pub fn remove_parameter(&mut self, name: &str) -> bool {
171 match self.parameters.remove(name) {
172 Some(_) => true,
173 None => false,
174 }
175 }
176
177 pub fn commit(self) -> Arc<Self> {
178 Arc::new_cyclic(|me| Self {
179 identifier: self.identifier,
180 #[cfg(feature = "doc")]
181 documentation: self.documentation,
182 attributes: self.attributes,
183 base_model: self.base_model,
184 parameters: self.parameters,
185 designer: self.designer,
186 design: self.design,
187 auto_reference: me.clone(),
188 })
189 }
190}
191
192impl Attribuable for Model {
193 fn attributes(&self) -> &Attributes {
194 &self.attributes
195 }
196}
197
198impl Identified for Model {
199 fn identifier(&self) -> &Identifier {
200 &self.identifier
201 }
202
203 fn make_use(&self, identifier: &Identifier) -> bool {
204 self.base_model.identifier() == identifier
205 || self.base_model.make_use(identifier)
206 || self.parameters.values().any(|parameter| {
207 parameter
208 .described_type()
209 .final_type()
210 .data()
211 .map(|data| data.identifier() == identifier || data.make_use(identifier))
212 .unwrap_or(false)
213 })
214 || self
215 .design
216 .lock()
217 .unwrap()
218 .as_ref()
219 .map(|design| design.make_use(identifier))
220 .unwrap_or(false)
221 || self
222 .designer
223 .lock()
224 .unwrap()
225 .as_ref()
226 .map(|designer| designer.read().unwrap().make_use(identifier))
227 .unwrap_or(false)
228 }
229
230 fn uses(&self) -> Vec<Identifier> {
231 let mut uses = vec![self.base_model.identifier().clone()];
232 self.parameters.values().for_each(|parameter| {
233 if let Some(data) = parameter.described_type().final_type().data() {
234 uses.push(data.identifier().clone());
235 uses.extend(data.uses());
236 }
237 });
238 if let Some(design) = self.design.lock().unwrap().as_ref() {
239 uses.extend(design.uses());
240 }
241 if let Some(designer) = self.designer.lock().unwrap().as_ref() {
242 uses.extend(designer.read().unwrap().uses());
243 }
244 uses
245 }
246}
247
248impl Documented for Model {
249 fn documentation(&self) -> &str {
250 #[cfg(feature = "doc")]
251 {
252 &self.documentation
253 }
254 #[cfg(not(feature = "doc"))]
255 {
256 &""
257 }
258 }
259}
260
261impl Parameterized for Model {
262 fn parameters(&self) -> &HashMap<String, Parameter> {
263 &self.parameters
264 }
265
266 fn as_identified(&self) -> Arc<dyn Identified> {
267 self.auto_reference.upgrade().unwrap()
268 }
269}
270
271impl Generics for Model {
272 fn generics(&self) -> &Vec<Generic> {
273 static VEC: OnceLock<Vec<Generic>> = OnceLock::new();
274 VEC.get_or_init(|| Vec::new())
275 }
276}
277
278impl Buildable<ModelBuildMode> for Model {
279 fn build_mode(&self) -> ModelBuildMode {
280 ModelBuildMode::Designed()
281 }
282}
283
284impl ModelDescriptor for Model {
285 fn is_core_model(&self) -> bool {
286 false
287 }
288
289 fn base_model(&self) -> Option<Arc<dyn ModelDescriptor>> {
290 Some(Arc::clone(&self.base_model))
291 }
292
293 fn sources(&self) -> &HashMap<String, Vec<Arc<dyn Context>>> {
294 self.base_model.sources()
295 }
296
297 fn as_identified(&self) -> Arc<dyn Identified> {
298 self.auto_reference.upgrade().unwrap()
299 }
300
301 fn as_buildable(&self) -> Arc<dyn Buildable<ModelBuildMode>> {
302 self.auto_reference.upgrade().unwrap()
303 }
304
305 fn as_parameterized(&self) -> Arc<dyn Parameterized> {
306 self.auto_reference.upgrade().unwrap()
307 }
308}
309
310impl Clone for Model {
311 fn clone(&self) -> Self {
318 Self {
319 identifier: self.identifier.clone(),
320 #[cfg(feature = "doc")]
321 documentation: self.documentation.clone(),
322 attributes: self.attributes.clone(),
323 base_model: self.base_model.clone(),
324 parameters: self.parameters.clone(),
325 designer: Mutex::new(None),
326 design: Mutex::new(None),
327 auto_reference: Weak::default(),
328 }
329 }
330}
331
332impl Display for Model {
333 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
334 write!(
335 f,
336 "model {}({})",
337 self.identifier.to_string(),
338 self.parameters()
339 .iter()
340 .map(|(_, p)| p.to_string())
341 .collect::<Vec<_>>()
342 .join(", "),
343 )?;
344
345 Ok(())
346 }
347}