melodium_engine/designer/
parameter.rs

1use super::{Reference, Scope, Value};
2use crate::design::Parameter as ParameterDesign;
3use crate::error::{LogicError, LogicResult};
4use melodium_common::descriptor::{Collection, DescribedType, Entry, Identifier, Parameterized};
5use std::collections::HashMap;
6use std::sync::{Arc, RwLock, Weak};
7
8#[derive(Debug)]
9pub struct Parameter {
10    scope: Weak<RwLock<dyn Scope>>,
11    scope_descriptor: Weak<dyn Parameterized>,
12    scope_generics: Arc<RwLock<HashMap<String, DescribedType>>>,
13    scope_id: Identifier,
14    parent_descriptor: Weak<dyn Parameterized>,
15    parent_generics: Arc<RwLock<HashMap<String, DescribedType>>>,
16    name: String,
17    value: Option<Value>,
18    design_reference: Option<Arc<dyn Reference>>,
19}
20
21impl Parameter {
22    pub fn new(
23        scope: &Arc<RwLock<dyn Scope>>,
24        scope_descriptor: &Arc<dyn Parameterized>,
25        scope_generics: &Arc<RwLock<HashMap<String, DescribedType>>>,
26        scope_id: Identifier,
27        parent_descriptor: &Arc<dyn Parameterized>,
28        parent_generics: &Arc<RwLock<HashMap<String, DescribedType>>>,
29        name: &str,
30        design_reference: Option<Arc<dyn Reference>>,
31    ) -> Self {
32        Self {
33            scope: Arc::downgrade(scope),
34            scope_descriptor: Arc::downgrade(scope_descriptor),
35            scope_generics: Arc::clone(scope_generics),
36            scope_id,
37            parent_descriptor: Arc::downgrade(parent_descriptor),
38            parent_generics: Arc::clone(parent_generics),
39            name: name.to_string(),
40            value: None,
41            design_reference,
42        }
43    }
44
45    pub fn scope(&self) -> &Weak<RwLock<dyn Scope>> {
46        &self.scope
47    }
48
49    pub fn parent_descriptor(&self) -> &Weak<dyn Parameterized> {
50        &self.parent_descriptor
51    }
52
53    pub fn design_reference(&self) -> &Option<Arc<dyn Reference>> {
54        &self.design_reference
55    }
56
57    pub(crate) fn import_design(
58        &mut self,
59        design: &ParameterDesign,
60        collection: &Arc<Collection>,
61        replace: &HashMap<Identifier, Identifier>,
62    ) -> LogicResult<()> {
63        fn import_value(
64            value: &Value,
65            design: &ParameterDesign,
66            collection: &Arc<Collection>,
67            replace: &HashMap<Identifier, Identifier>,
68            scope_id: &Identifier,
69            design_reference: &Option<Arc<dyn Reference>>,
70        ) -> Result<Value, LogicError> {
71            match value {
72                Value::Raw(executive_value) => Ok(Value::Raw(executive_value.clone())),
73                Value::Array(array) => {
74                    let mut new_array = Vec::with_capacity(array.len());
75                    for val in array {
76                        match import_value(
77                            val,
78                            design,
79                            collection,
80                            replace,
81                            scope_id,
82                            design_reference,
83                        ) {
84                            Ok(val) => new_array.push(val),
85                            Err(err) => return Err(err),
86                        }
87                    }
88                    Ok(Value::Array(new_array))
89                }
90                Value::Variable(variable) => Ok(Value::Variable(variable.clone())),
91                Value::Context(former_context, entry) => {
92                    if let Some(Entry::Context(new_context)) = collection.get(
93                        &replace
94                            .get(former_context.identifier())
95                            .unwrap_or_else(|| former_context.identifier())
96                            .into(),
97                    ) {
98                        Ok(Value::Context(new_context.clone(), entry.clone()))
99                    } else {
100                        Err(LogicError::unexisting_context(
101                            204,
102                            scope_id.clone(),
103                            former_context.identifier().into(),
104                            design_reference.clone(),
105                        ))
106                    }
107                }
108                Value::Function(former_function, generics, values) => {
109                    if let Some(Entry::Function(new_function)) = collection.get(
110                        &replace
111                            .get(former_function.identifier())
112                            .unwrap_or_else(|| former_function.identifier())
113                            .into(),
114                    ) {
115                        Ok(Value::Function(
116                            new_function.clone(),
117                            generics.clone(),
118                            values.clone(),
119                        ))
120                    } else {
121                        Err(LogicError::unexisting_function(
122                            205,
123                            scope_id.clone(),
124                            former_function.identifier().into(),
125                            design_reference.clone(),
126                        ))
127                    }
128                }
129            }
130        }
131
132        let value = import_value(
133            &design.value,
134            design,
135            collection,
136            replace,
137            &self.scope_id,
138            &self.design_reference,
139        );
140
141        match value {
142            Ok(value) => self.set_value(value),
143            Err(err) => LogicResult::new_failure(err),
144        }
145    }
146
147    pub fn name(&self) -> &str {
148        &self.name
149    }
150
151    pub fn set_value(&mut self, value: Value) -> LogicResult<()> {
152        let parent_descriptor = self.parent_descriptor.upgrade().unwrap();
153        let parameter = parent_descriptor.parameters().get(&self.name);
154        if let Some(parameter) = parameter {
155            let result = value.check(
156                parameter.described_type(),
157                &self.scope_descriptor.upgrade().unwrap(),
158                &self.scope_generics,
159                self.parent_descriptor.upgrade().unwrap().identifier(),
160                &self.parent_generics,
161                parameter.name(),
162                *parameter.variability(),
163                &self.design_reference,
164            );
165
166            if result.is_success() {
167                self.value = Some(value.clone());
168            }
169            result.and(LogicResult::new_success(()))
170        } else {
171            LogicResult::new_success(())
172        }
173    }
174
175    pub fn value(&self) -> &Option<Value> {
176        &self.value
177    }
178
179    pub fn described_type(&self) -> LogicResult<Option<DescribedType>> {
180        let parent_descriptor = self.parent_descriptor.upgrade().unwrap();
181        let parameter = parent_descriptor.parameters().get(&self.name);
182        match parameter.map(|parameter| {
183            parameter
184                .described_type()
185                .as_defined(&self.parent_generics.read().unwrap())
186                .ok_or_else(|| -> LogicResult<Option<DescribedType>> {
187                    LogicResult::new_failure(LogicError::undefined_generic(
188                        221,
189                        self.scope_id.clone(),
190                        parent_descriptor.identifier().clone(),
191                        parameter.described_type().clone(),
192                        self.design_reference.clone(),
193                    ))
194                })
195        }) {
196            Some(described_type) => match described_type {
197                Ok(described_type) => LogicResult::new_success(Some(described_type)),
198                Err(err) => err,
199            },
200            None => LogicResult::new_success(None),
201        }
202    }
203
204    pub fn validate(&self) -> LogicResult<()> {
205        let mut result = LogicResult::new_success(());
206
207        let parent_descriptor = self.parent_descriptor.upgrade().unwrap();
208        let parameter = parent_descriptor.parameters().get(&self.name);
209
210        if self.value.is_none() {
211            result.errors_mut().push(LogicError::no_value(
212                27,
213                self.scope_id.clone(),
214                parent_descriptor.identifier().clone(),
215                self.name.clone(),
216                self.design_reference.clone(),
217            ));
218        }
219
220        // Check parameter exists
221        if let Some(parameter) = parameter {
222            if let Some(value) = self.value.as_ref() {
223                result = result
224                    .and_degrade_failure(value.check(
225                        parameter.described_type(),
226                        &self.scope_descriptor.upgrade().unwrap(),
227                        &self.scope_generics,
228                        self.parent_descriptor.upgrade().unwrap().identifier(),
229                        &self.parent_generics,
230                        parameter.name(),
231                        *parameter.variability(),
232                        &self.design_reference,
233                    ))
234                    .and(LogicResult::new_success(()));
235            } else {
236                result.errors_mut().push(LogicError::no_value(
237                    27,
238                    self.scope_id.clone(),
239                    self.parent_descriptor
240                        .upgrade()
241                        .unwrap()
242                        .identifier()
243                        .clone(),
244                    self.name.clone(),
245                    self.design_reference.clone(),
246                ));
247            }
248        } else {
249            result.errors_mut().push(LogicError::unexisting_parameter(
250                194,
251                self.scope_id.clone(),
252                parent_descriptor.identifier().clone(),
253                self.name.clone(),
254                self.design_reference.clone(),
255            ));
256        }
257
258        result
259    }
260}