melodium_engine/descriptor/
model.rs

1use 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    /**
312     * Clone model descriptor.
313     *
314     * The descriptor and its inner descriptive elements are all cloned, but not the designer nor the related design.
315     * The cloned descriptor need to be commited.
316     */
317    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}