1use super::{Attributes, Identifier, ModelDesign, Parameter, SharingError, SharingResult};
2use melodium_common::descriptor::{
3 Collection, Entry as CommonEntry, Identifier as CommonIdentifier, Model as CommonModel,
4};
5use melodium_engine::{descriptor::Model as DesignedModel, LogicError};
6use serde::{Deserialize, Serialize};
7use std::{
8 collections::{BTreeMap, HashMap},
9 sync::Arc,
10};
11
12#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
13#[cfg_attr(feature = "webassembly", derive(tsify::Tsify))]
14#[cfg_attr(feature = "webassembly", tsify(into_wasm_abi, from_wasm_abi))]
15pub struct Model {
16 pub identifier: Identifier,
17 pub documentation: String,
18 pub parameters: BTreeMap<String, Parameter>,
19 pub implementation_kind: ModelImplementationKind,
20 pub hierarchy: Vec<Identifier>,
21 pub sources: BTreeMap<String, Vec<Identifier>>,
22 pub attributes: Attributes,
23}
24
25impl Model {
26 pub fn make_descriptor(&self, collection: &Collection) -> SharingResult<Arc<DesignedModel>> {
27 let identifier = if let Ok(identifier) = (&self.identifier).try_into() {
28 identifier
29 } else {
30 return SharingResult::new_failure(SharingError::invalid_identifier(
31 1,
32 self.identifier.clone(),
33 ));
34 };
35
36 if self.implementation_kind.is_compiled() {
37 return SharingResult::new_failure(SharingError::compiled_model(2, identifier));
38 }
39
40 let base_identifier: CommonIdentifier = if let Some(base_identifier) = self.hierarchy.last()
41 {
42 if let Ok(base_identifier) = base_identifier.try_into() {
43 base_identifier
44 } else {
45 return SharingResult::new_failure(SharingError::invalid_identifier(
46 4,
47 self.identifier.clone(),
48 ));
49 }
50 } else {
51 return SharingResult::new_failure(SharingError::missing_base_identifier(
52 3, identifier,
53 ));
54 };
55
56 let base_model = if let Some(melodium_common::descriptor::Entry::Model(base_model)) =
57 collection.get(&(&base_identifier).into())
58 {
59 base_model
60 } else {
61 return SharingResult::new_failure(
62 LogicError::unexisting_model(230, identifier.clone(), base_identifier.into(), None)
63 .into(),
64 );
65 };
66
67 let mut result = SharingResult::new_success(());
68 let mut descriptor = DesignedModel::new(identifier.clone(), base_model);
69
70 descriptor.set_documentation(&self.documentation);
71
72 for (name, attribute) in &self.attributes.0 {
73 descriptor.add_attribute(name.clone(), attribute.clone());
74 }
75
76 for (_, param) in &self.parameters {
77 if let Some(parameter) =
78 result.merge_degrade_failure(param.to_parameter(collection, &identifier))
79 {
80 descriptor.add_parameter(parameter);
81 }
82 }
83
84 result.and(SharingResult::new_success(descriptor.commit()))
85 }
86
87 pub fn make_design(&self, collection: &Arc<Collection>) -> SharingResult<()> {
88 let identifier = if let Ok(identifier) = (&self.identifier).try_into() {
89 identifier
90 } else {
91 return SharingResult::new_failure(SharingError::invalid_identifier(
92 6,
93 self.identifier.clone(),
94 ));
95 };
96
97 let design =
98 if let ModelImplementationKind::Designed(Some(design)) = &self.implementation_kind {
99 design
100 } else {
101 return SharingResult::new_failure(SharingError::no_model_design_available(
102 7, identifier,
103 ));
104 };
105
106 let descriptor = if let Some(CommonEntry::Model(model)) =
107 collection.get(&(&identifier).into())
108 {
109 if let Ok(model) = model.clone().downcast_arc::<DesignedModel>() {
110 model
111 } else {
112 return SharingResult::new_failure(
113 LogicError::unexisting_model(235, identifier.clone(), identifier.into(), None)
114 .into(),
115 );
116 }
117 } else {
118 return SharingResult::new_failure(
119 LogicError::unexisting_model(234, identifier.clone(), identifier.into(), None)
120 .into(),
121 );
122 };
123
124 let designer = match descriptor.designer(Arc::clone(collection), None) {
125 melodium_common::descriptor::Status::Success { success, errors: _ } => success,
126 melodium_common::descriptor::Status::Failure { failure, errors: _ } => {
127 return SharingResult::new_failure(failure.into())
128 }
129 };
130
131 design
132 .make_design(collection, &descriptor)
133 .and_then(|design| {
134 SharingResult::from(designer.write().unwrap().import_design(
135 &design,
136 &HashMap::new(),
137 None,
138 ))
139 })
140 .and_then(|()| SharingResult::from(descriptor.commit_design()))
141 }
142}
143
144impl From<&Arc<dyn CommonModel>> for Model {
145 fn from(value: &Arc<dyn CommonModel>) -> Self {
146 let mut hierarchy = Vec::new();
147 let mut base = value.base_model();
148 while let Some(parent) = base {
149 hierarchy.push(parent.identifier().into());
150 base = parent.base_model();
151 }
152 Self {
153 identifier: Identifier::from(value.identifier()),
154 documentation: value.documentation().to_string(),
155 parameters: value
156 .parameters()
157 .iter()
158 .map(|(name, param)| (name.clone(), Parameter::from(param)))
159 .collect(),
160 implementation_kind: match value.build_mode() {
161 melodium_common::descriptor::ModelBuildMode::Compiled(_) => {
162 ModelImplementationKind::Compiled
163 }
164 melodium_common::descriptor::ModelBuildMode::Designed() => {
165 ModelImplementationKind::Designed(
166 value
167 .clone()
168 .downcast_arc::<DesignedModel>()
169 .unwrap()
170 .design()
171 .success()
172 .map(|design| design.as_ref().into()),
173 )
174 }
175 },
176 hierarchy,
177 sources: value
178 .sources()
179 .iter()
180 .map(|(name, contexts)| {
181 (
182 name.clone(),
183 contexts
184 .iter()
185 .map(|context| Identifier::from(context.identifier()))
186 .collect(),
187 )
188 })
189 .collect(),
190 attributes: value.attributes().into(),
191 }
192 }
193}
194
195#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
196#[serde(rename_all = "snake_case")]
197#[cfg_attr(feature = "webassembly", derive(tsify::Tsify))]
198#[cfg_attr(feature = "webassembly", tsify(into_wasm_abi, from_wasm_abi))]
199pub enum ModelImplementationKind {
200 Compiled,
201 Designed(Option<ModelDesign>),
202}
203
204impl ModelImplementationKind {
205 pub fn is_compiled(&self) -> bool {
206 match self {
207 ModelImplementationKind::Compiled => true,
208 _ => false,
209 }
210 }
211}