assemble_core/project/
buildable.rs1use crate::identifier::TaskId;
12
13use crate::project::ProjectResult;
14
15use crate::project::Project;
16
17use std::collections::HashSet;
18use std::fmt::{Debug, Formatter};
19use std::ops::{Deref, DerefMut};
20use std::sync::Arc;
21
22pub trait IntoBuildable {
24    type Buildable: Buildable;
25    fn into_buildable(self) -> Self::Buildable;
27}
28
29pub trait GetBuildable {
30    fn as_buildable(&self) -> BuildableObject;
32}
33
34assert_obj_safe!(GetBuildable);
35
36impl<B: IntoBuildable + Clone> GetBuildable for B
37where
38    <B as IntoBuildable>::Buildable: 'static,
39{
40    fn as_buildable(&self) -> BuildableObject {
41        BuildableObject::new(self.clone().into_buildable())
42    }
43}
44
45impl<B: Buildable> IntoBuildable for B {
46    type Buildable = B;
47
48    fn into_buildable(self) -> B {
49        self
50    }
51}
52
53pub trait Buildable: Send + Sync + Debug {
56    fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>>;
58}
59
60assert_obj_safe!(Buildable);
61
62impl<B: Buildable> Buildable for &B {
63    fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
64        (*self).get_dependencies(project)
65    }
66}
67
68impl Buildable for Box<dyn Buildable + '_> {
69    fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
70        self.as_ref().get_dependencies(project)
71    }
72}
73
74impl Buildable for Arc<dyn Buildable + '_> {
75    fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
76        self.as_ref().get_dependencies(project)
77    }
78}
79
80impl<B: Buildable> Buildable for Vec<B> {
81    fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
82        self.iter()
83            .map(|b| b.get_dependencies(project))
84            .collect::<Result<Vec<HashSet<_>>, _>>()
85            .map(|v| v.into_iter().flatten().collect())
86    }
87}
88
89#[derive(Default, Clone)]
91pub struct BuiltByContainer(Vec<Arc<dyn Buildable>>);
92
93impl BuiltByContainer {
94    pub const fn new() -> Self {
96        Self(Vec::new())
97    }
98
99    pub fn with_capacity(capacity: usize) -> Self {
101        Self(Vec::with_capacity(capacity))
102    }
103
104    pub fn with_buildable<B: IntoBuildable>(buildable: B) -> Self
106    where
107        <B as IntoBuildable>::Buildable: 'static,
108    {
109        let mut output = BuiltByContainer::with_capacity(1);
110        output.add(buildable);
111        output
112    }
113
114    pub fn join(self, other: Self) -> Self {
116        let mut inner = self.0;
117        inner.extend(other.0);
118        Self(inner)
119    }
120
121    pub fn add<T: IntoBuildable>(&mut self, buildable: T)
122    where
123        <T as IntoBuildable>::Buildable: 'static,
124    {
125        let buildable: Arc<dyn Buildable> = Arc::new(buildable.into_buildable());
126        self.0.push(buildable);
127    }
128}
129
130impl Debug for BuiltByContainer {
131    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
132        write!(f, "BuiltByContainer ")?;
133        f.debug_set().entries(&self.0).finish()
134    }
135}
136
137impl Buildable for BuiltByContainer {
138    fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
139        let mut output = HashSet::new();
140        for dep in &self.0 {
141            trace!("Getting dependencies for buildable: {:#?}", dep);
142            output.extend(dep.get_dependencies(project)?);
143        }
144        Ok(output)
145    }
146}
147
148#[derive(Debug)]
150pub struct BuiltBy<T: Debug> {
151    built_by: Arc<dyn Buildable>,
152    value: T,
153}
154
155impl<T: Debug + Clone> Clone for BuiltBy<T> {
156    fn clone(&self) -> Self {
157        Self {
158            built_by: self.built_by.clone(),
159            value: self.value.clone(),
160        }
161    }
162}
163
164impl<T: Debug> DerefMut for BuiltBy<T> {
165    fn deref_mut(&mut self) -> &mut Self::Target {
166        &mut self.value
167    }
168}
169
170impl<T: Debug> Deref for BuiltBy<T> {
171    type Target = T;
172
173    fn deref(&self) -> &Self::Target {
174        &self.value
175    }
176}
177
178impl<T: Debug> IntoBuildable for BuiltBy<T> {
179    type Buildable = Arc<dyn Buildable>;
180
181    fn into_buildable(self) -> Self::Buildable {
182        self.built_by
183    }
184}
185
186impl<T: Debug> BuiltBy<T> {
187    pub fn new<B: IntoBuildable + 'static>(built_by: B, value: T) -> Self {
189        Self {
190            built_by: Arc::new(built_by.into_buildable()),
191            value,
192        }
193    }
194
195    pub fn into_inner(self) -> T {
197        self.value
198    }
199
200    pub fn as_ref(&self) -> BuiltBy<&T> {
202        BuiltBy {
203            built_by: self.built_by.clone(),
204            value: &self.value,
205        }
206    }
207
208    pub fn built_by(&self) -> &dyn Buildable {
210        &self.built_by
211    }
212}
213
214#[derive(Clone, Debug)]
216pub enum BuildableObject {
217    Container(BuiltByContainer),
219    Id(TaskId),
221    Other(Arc<dyn Buildable>),
223    None,
225}
226
227impl BuildableObject {
228    pub fn new<B: IntoBuildable>(buildable: B) -> Self
230    where
231        <B as IntoBuildable>::Buildable: 'static,
232    {
233        Self::Other(Arc::new(buildable.into_buildable()))
234    }
235}
236
237impl Buildable for BuildableObject {
238    fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
239        match self {
240            BuildableObject::Container(c) => c.get_dependencies(project),
241            BuildableObject::Id(id) => id.get_dependencies(project),
242            BuildableObject::Other(o) => o.get_dependencies(project),
243            BuildableObject::None => Ok(HashSet::new()),
244        }
245    }
246}
247
248impl From<BuiltByContainer> for BuildableObject {
249    fn from(c: BuiltByContainer) -> Self {
250        BuildableObject::Container(c)
251    }
252}
253
254impl From<TaskId> for BuildableObject {
255    fn from(c: TaskId) -> Self {
256        BuildableObject::Id(c)
257    }
258}
259
260impl From<Box<dyn Buildable>> for BuildableObject {
261    fn from(boxed: Box<dyn Buildable>) -> Self {
262        let arc = Arc::from(boxed);
263        BuildableObject::Other(arc)
264    }
265}
266
267assert_impl_all!(BuildableObject: Buildable, IntoBuildable, GetBuildable);