assemble_core/flow/
output.rs1use crate::dependencies::file_dependency::FILE_SYSTEM_TYPE;
4use crate::dependencies::{
5 AcquisitionError, Dependency, DependencyType, Registry, ResolvedDependency,
6 ResolvedDependencyBuilder,
7};
8use crate::file_collection::FileSet;
9use crate::flow::shared::{Artifact, ConfigurableArtifact, IntoArtifact};
10use crate::identifier::Id;
11
12use crate::lazy_evaluation::{Prop, Provider};
13use crate::project::buildable::{BuildableObject, GetBuildable, IntoBuildable};
14use crate::task::{BuildableTask, HasTaskId, TaskHandle};
15use crate::{Executable, Task};
16use once_cell::sync::Lazy;
17use std::collections::HashMap;
18
19use std::path::{Path, PathBuf};
20
21#[derive(Default, Debug)]
23pub struct VariantHandler {
24 default_variant: Option<String>,
25 variant_map: HashMap<String, Prop<ConfigurableArtifact>>,
26}
27
28impl VariantHandler {
29 pub fn new() -> Self {
30 Self {
31 default_variant: None,
32 variant_map: Default::default(),
33 }
34 }
35
36 pub fn set_default(&mut self, default: &str) {
38 self.default_variant = Some(default.to_string());
39 }
40
41 pub fn default(&self) -> String {
43 self.default_variant
44 .as_ref()
45 .cloned()
46 .or_else(|| {
47 if self.variant_map.len() == 1 {
48 self.variant_map.keys().next().cloned()
49 } else {
50 None
51 }
52 })
53 .expect("no default variant could be determined")
54 }
55
56 pub fn add<S, A>(&mut self, variant: S, artifact: A)
58 where
59 S: AsRef<str>,
60 A: IntoArtifact + Send + 'static,
61 A::IntoArtifact: 'static,
62 {
63 let config_name = variant.as_ref().to_string();
64 let mut prop = Prop::<ConfigurableArtifact>::new(Id::from(&*config_name));
65 prop.set_with(Lazy::new(move || {
66 let artifact = artifact.into_artifact();
67 let buildable = artifact.buildable();
68 let mut output = ConfigurableArtifact::from_artifact(artifact);
69 if let Some(buildable) = buildable {
70 output.built_by(buildable);
71 }
72 output
73 }))
74 .unwrap();
75
76 self.variant_map.insert(config_name, prop);
77 }
78
79 pub fn add_with<S, A, F>(&mut self, configuration: S, artifact: A, config: F)
80 where
81 S: AsRef<str>,
82 A: IntoArtifact + Send,
83 A::IntoArtifact: 'static,
84 F: FnOnce(&mut ConfigurableArtifact) + Send,
85 {
86 let config_name = configuration.as_ref().to_string();
87 let mut prop = Prop::<ConfigurableArtifact>::new(Id::from(&*config_name));
88 let artifact = artifact.into_artifact();
89 let mut configurable = ConfigurableArtifact::from_artifact(artifact);
90 (config)(&mut configurable);
91 prop.set(configurable).unwrap();
92 self.variant_map.insert(config_name, prop);
93 }
94
95 pub(crate) fn get_artifact(
96 &self,
97 configuration: &str,
98 ) -> Option<impl Provider<ConfigurableArtifact>> {
99 self.variant_map.get(configuration).cloned()
100 }
101}
102
103pub trait SinglePathOutputTask: Task + Send + Sync + 'static {
104 fn get_path(task: &Executable<Self>) -> PathBuf;
105}
106
107impl<T: SinglePathOutputTask> ArtifactTask for T {
108 fn get_artifact(task: &Executable<Self>) -> ConfigurableArtifact {
109 let mut output = ConfigurableArtifact::from_artifact(T::get_path(task));
110 output.built_by(task.task_id());
111 output
112 }
113}
114
115impl<T: SinglePathOutputTask> Provider<PathBuf> for TaskHandle<T> {
116 fn try_get(&self) -> Option<PathBuf> {
117 self.provides(|e| T::get_path(e)).try_get()
118 }
119}
120
121pub trait ArtifactTask: Task + Send + Sync + 'static {
123 fn get_artifact(task: &Executable<Self>) -> ConfigurableArtifact;
125}
126
127impl<A: ArtifactTask> IntoArtifact for TaskHandle<A> {
128 type IntoArtifact = ConfigurableArtifact;
129
130 fn into_artifact(self) -> Self::IntoArtifact {
131 (&self).into_artifact()
132 }
133}
134
135impl<A: ArtifactTask> IntoArtifact for &TaskHandle<A> {
136 type IntoArtifact = ConfigurableArtifact;
137
138 fn into_artifact(self) -> Self::IntoArtifact {
139 self.provides(|s| A::get_artifact(s)).get()
140 }
141}
142
143impl<AT: ArtifactTask> GetBuildable for Executable<AT> {
144 fn as_buildable(&self) -> BuildableObject {
145 BuildableObject::new(self.clone().into_buildable())
146 }
147}
148
149impl<AT: ArtifactTask> Dependency for Executable<AT> {
150 fn id(&self) -> String {
151 AT::get_artifact(self).file().to_str().unwrap().to_string()
152 }
153
154 fn dep_type(&self) -> DependencyType {
155 FILE_SYSTEM_TYPE.clone()
156 }
157
158 fn try_resolve(
159 &self,
160 _: &dyn Registry,
161 _: &Path,
162 ) -> Result<ResolvedDependency, AcquisitionError> {
163 Ok(ResolvedDependencyBuilder::new(AT::get_artifact(self))
164 .built_by(self.built_by())
165 .finish())
166 }
167
168 }
172
173impl<AT: ArtifactTask + Send + 'static> Dependency for TaskHandle<AT> {
174 fn id(&self) -> String {
175 self.provides(|s| s.id()).get()
176 }
177
178 fn dep_type(&self) -> DependencyType {
179 FILE_SYSTEM_TYPE.clone()
180 }
181
182 fn try_resolve(
183 &self,
184 _: &dyn Registry,
185 _: &Path,
186 ) -> Result<ResolvedDependency, AcquisitionError> {
187 Ok(
188 ResolvedDependencyBuilder::new(self.provides(|s| AT::get_artifact(s)).get())
189 .built_by(self.clone())
190 .finish(),
191 )
192 }
193
194 }
198
199impl<T: ArtifactTask> From<TaskHandle<T>> for FileSet {
200 fn from(t: TaskHandle<T>) -> Self {
201 let artifact = t.provides(|e| T::get_artifact(e)).get();
202 let mut set = FileSet::from(artifact.file());
203 set.built_by(t);
204 set
205 }
206}
207