melodium_engine/building/treatment/
source.rs1use crate::building::{
2 BuildId, CheckBuild, CheckBuildResult, CheckEnvironment, CheckStep, ContextualEnvironment,
3 DynamicBuildResult, FeedingInputs, GenesisEnvironment, StaticBuildResult,
4};
5use crate::building::{Builder as BuilderTrait, HostTreatment};
6use crate::error::{LogicError, LogicResult};
7use crate::world::World;
8use core::fmt::Debug;
9use melodium_common::descriptor::{Status, Treatment as TreatmentDescriptor};
10use melodium_common::executive::TrackId;
11use std::collections::HashMap;
12use std::sync::{Arc, RwLock, Weak};
13
14#[derive(Debug)]
15struct BuildSample {
16 host_treatment: HostTreatment,
17 host_build_id: Option<BuildId>,
18 #[allow(unused)]
19 check: Arc<RwLock<CheckBuild>>,
20 label: String,
21}
22
23impl BuildSample {
24 pub fn new(host_treatment: &HostTreatment, host_build: &Option<BuildId>, label: &str) -> Self {
25 Self {
26 host_treatment: host_treatment.clone(),
27 host_build_id: host_build.clone(),
28 check: Arc::new(RwLock::new(CheckBuild::new(
29 host_treatment.host_id().cloned(),
30 label,
31 ))),
32 label: label.to_string(),
33 }
34 }
35}
36
37#[derive(Debug)]
38pub struct Builder {
39 world: Weak<World>,
40
41 descriptor: Weak<dyn TreatmentDescriptor>,
42
43 builds: RwLock<Vec<BuildSample>>,
44 building_inputs: RwLock<HashMap<(BuildId, TrackId), FeedingInputs>>,
45}
46
47impl Builder {
48 pub fn new(world: Weak<World>, descriptor: Weak<dyn TreatmentDescriptor>) -> Self {
49 Self {
50 world,
51 descriptor,
52 builds: RwLock::new(Vec::new()),
53 building_inputs: RwLock::new(HashMap::new()),
54 }
55 }
56}
57
58impl BuilderTrait for Builder {
59 fn static_build(
60 &self,
61 host_treatment: HostTreatment,
62 host_build: Option<BuildId>,
63 label: String,
64 environment: &GenesisEnvironment,
65 ) -> LogicResult<StaticBuildResult> {
66 let world = self.world.upgrade().unwrap();
67 let build_sample = BuildSample::new(&host_treatment, &host_build, &label);
69
70 let mut builds_writer = self.builds.write().unwrap();
71 let idx = builds_writer.len() as BuildId;
72
73 let rc_descriptor = self.descriptor.upgrade().unwrap();
74 for (model_name, sources) in rc_descriptor.source_from() {
75 let (_, matching_model) = environment
76 .models()
77 .iter()
78 .find(|(name, _)| name == &model_name)
79 .unwrap();
80
81 for source in sources {
82 world.add_source(
83 matching_model.id().unwrap(),
84 source,
85 self.descriptor.upgrade().unwrap(),
86 environment.variables().clone(),
87 idx,
88 );
89 }
90 }
91
92 builds_writer.push(build_sample);
93
94 Status::new_success(StaticBuildResult::Build(idx))
95 }
96
97 fn dynamic_build(
98 &self,
99 build: BuildId,
100 _with_inputs: Vec<String>,
101 environment: &ContextualEnvironment,
102 ) -> Option<DynamicBuildResult> {
103 let world = self.world.upgrade().unwrap();
104
105 {
107 let borrowed_building_inputs = self.building_inputs.read().unwrap();
108
109 if let Some(existing_building_inputs) =
110 borrowed_building_inputs.get(&(build, environment.track_id()))
111 {
112 let mut dynamic_result = DynamicBuildResult::new();
113 dynamic_result
114 .feeding_inputs
115 .extend(existing_building_inputs.clone());
116
117 return Some(dynamic_result);
118 }
119 }
120
121 let borrowed_builds = self.builds.read().unwrap();
123 let build_sample = borrowed_builds.get(build as usize).unwrap();
124 let descriptor = self.descriptor.upgrade().unwrap();
125
126 let mut result = DynamicBuildResult::new();
127
128 match &build_sample.host_treatment {
129 HostTreatment::Treatment(host_descriptor) => {
130 let host_build = world
131 .builder(host_descriptor.identifier())
132 .success()
133 .unwrap()
134 .give_next(
135 build_sample.host_build_id.unwrap(),
136 build_sample.label.to_string(),
137 descriptor.outputs().keys().cloned().collect(),
138 &environment.base_on(),
139 )
140 .unwrap();
141
142 result.feeding_inputs = host_build.feeding_inputs;
143 for (name, _) in descriptor.outputs() {
145 if !result.feeding_inputs.contains_key(name) {
146 result
147 .feeding_inputs
148 .insert(name.clone(), vec![world.new_blocked_input()]);
149 }
150 }
151 result.prepared_futures.extend(host_build.prepared_futures);
152 }
153 HostTreatment::Direct => {
154 panic!("Source cannot be directly instancied (nonsense, model missing)")
155 }
156 }
157
158 self.building_inputs.write().unwrap().insert(
159 (build, environment.track_id()),
160 result.feeding_inputs.clone(),
161 );
162
163 Some(result)
164 }
165
166 fn give_next(
167 &self,
168 _within_build: BuildId,
169 _for_label: String,
170 _for_outputs: Vec<String>,
171 _environment: &ContextualEnvironment,
172 ) -> Option<DynamicBuildResult> {
173 None
175 }
176
177 fn check_dynamic_build(
178 &self,
179 build: BuildId,
180 environment: CheckEnvironment,
181 previous_steps: Vec<CheckStep>,
182 ) -> Option<CheckBuildResult> {
183 let world = self.world.upgrade().unwrap();
184 let descriptor = self.descriptor.upgrade().unwrap();
185
186 let mut errors = Vec::new();
187 let check_step = CheckStep {
189 identifier: descriptor.identifier().clone(),
190 build_id: build,
191 };
192 if let Some(_existing_check_step) = previous_steps.iter().find(|&cs| cs == &check_step) {
193 errors.push(LogicError::already_included_build_step(
194 58,
195 descriptor.identifier().clone(),
196 check_step.clone(),
197 previous_steps.clone(),
198 None,
199 ));
200 }
201 let mut current_previous_steps = previous_steps.clone();
202 current_previous_steps.push(check_step);
203
204 let borrowed_builds = self.builds.read().unwrap();
206 let build_sample = borrowed_builds.get(build as usize).unwrap();
207
208 let mut all_builds = Vec::new();
209 if errors.is_empty() {
210 match &build_sample.host_treatment {
211 HostTreatment::Treatment(host_descriptor) => {
212 let build_result = world
213 .builder(host_descriptor.identifier())
214 .success()
215 .unwrap()
216 .check_give_next(
217 build_sample.host_build_id.unwrap(),
218 build_sample.label.to_string(),
219 environment.clone(),
220 current_previous_steps,
221 )
222 .unwrap();
223
224 all_builds.extend(build_result.checked_builds);
225
226 errors.extend(build_result.errors);
227 }
228 HostTreatment::Direct => {}
229 }
230 all_builds.push(Arc::clone(&build_sample.check));
231 }
232
233 let own_checked_build_result = CheckBuildResult {
235 checked_builds: all_builds,
236 build: Arc::clone(&build_sample.check),
237 errors,
238 };
239
240 Some(own_checked_build_result)
241 }
242
243 fn check_give_next(
244 &self,
245 _within_build: BuildId,
246 _for_label: String,
247 _environment: CheckEnvironment,
248 _previous_steps: Vec<CheckStep>,
249 ) -> Option<CheckBuildResult> {
250 None
252 }
253}