assemble_core/lazy_evaluation/
providers.rs

1//! Provides implementations of providers
2
3use crate::__export::{ProjectResult, TaskId};
4use crate::lazy_evaluation::{IntoProvider, Provider};
5use crate::project::buildable::Buildable;
6use crate::Project;
7use once_cell::sync::Lazy;
8use std::collections::HashSet;
9use std::fmt::{Debug, Formatter};
10use std::marker::PhantomData;
11use std::sync::Arc;
12
13/// create a provider with a function
14#[macro_export]
15macro_rules! provider {
16    ($e:expr) => {
17        $crate::lazy_evaluation::providers::FnProvider::new($e)
18    };
19    ($e:expr) => {
20        $crate::lazy_evaluation::providers::FnProvider::new($e)
21    };
22}
23
24/// A provider created from a function
25pub struct FnProvider<T, R = T>
26where
27    R: Into<Option<T>>,
28    T: Send + Sync + Clone,
29{
30    func: Arc<dyn Fn() -> R + Send + Sync>,
31    _phantom: PhantomData<T>,
32}
33
34impl<T, R> Clone for FnProvider<T, R>
35where
36    R: Into<Option<T>>,
37    T: Send + Sync + Clone,
38{
39    fn clone(&self) -> Self {
40        Self {
41            func: self.func.clone(),
42            _phantom: PhantomData,
43        }
44    }
45}
46
47impl<T, R> Buildable for FnProvider<T, R>
48where
49    R: Into<Option<T>>,
50    T: Clone + Send + Sync,
51{
52    fn get_dependencies(&self, _: &Project) -> ProjectResult<HashSet<TaskId>> {
53        Ok(HashSet::new())
54    }
55}
56
57impl<T, R> Debug for FnProvider<T, R>
58where
59    R: Into<Option<T>>,
60    T: Clone + Send + Sync,
61{
62    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
63        write!(f, "FunctionalProvider")
64    }
65}
66
67impl<T, R> Provider<T> for FnProvider<T, R>
68where
69    R: Into<Option<T>>,
70    T: Send + Sync + Clone,
71{
72    fn try_get(&self) -> Option<T> {
73        (self.func)().into()
74    }
75}
76
77impl<T, R> FnProvider<T, R>
78where
79    R: Into<Option<T>>,
80    T: Send + Sync + Clone,
81{
82    pub fn new<F>(func: F) -> Self
83    where
84        F: Fn() -> R + Send + Sync + 'static,
85    {
86        Self {
87            func: Arc::new(func),
88            _phantom: PhantomData,
89        }
90    }
91}
92
93/// Provides methods to map the output of a map to another
94#[derive(Clone)]
95pub struct Map<T, R, F, P>
96where
97    T: Send + Sync + Clone,
98    R: Send + Sync + Clone,
99    F: Fn(T) -> R + Send + Sync,
100    P: Provider<T>,
101{
102    provider: P,
103    transform: F,
104    _data: PhantomData<(T, R)>,
105}
106
107impl<T, R, F, P> Buildable for Map<T, R, F, P>
108where
109    F: Fn(T) -> R + Send + Sync,
110    P: Provider<T>,
111    R: Clone + Send + Sync,
112    T: Clone + Send + Sync,
113{
114    fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
115        self.provider.get_dependencies(project)
116    }
117}
118
119impl<T, R, F, P> Debug for Map<T, R, F, P>
120where
121    F: Fn(T) -> R + Send + Sync,
122    P: Provider<T>,
123    R: Clone + Send + Sync,
124    T: Clone + Send + Sync,
125{
126    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
127        write!(f, "Map<{:?}>", self.provider)
128    }
129}
130
131impl<T, R, F, P> Provider<R> for Map<T, R, F, P>
132where
133    T: Send + Sync + Clone,
134    R: Send + Sync + Clone,
135    F: Fn(T) -> R + Send + Sync,
136    P: Provider<T>,
137{
138    fn missing_message(&self) -> String {
139        self.provider.missing_message()
140    }
141
142    fn try_get(&self) -> Option<R> {
143        self.provider.try_get().map(|v| (self.transform)(v))
144    }
145}
146
147impl<T, R, F, P> Map<T, R, F, P>
148where
149    T: Send + Sync + Clone,
150    R: Send + Sync + Clone,
151    F: Fn(T) -> R + Send + Sync,
152    P: Provider<T>,
153{
154    pub(super) fn new(provider: P, transform: F) -> Self {
155        Self {
156            provider,
157            transform,
158            _data: Default::default(),
159        }
160    }
161}
162
163/// Provides methods to map the output of a map to another
164#[derive(Clone)]
165pub struct FlatMap<T, R, PT, PR, F>
166where
167    T: Send + Sync + Clone,
168    R: Send + Sync + Clone,
169    PT: Provider<T>,
170    PR: Provider<R>,
171    F: Fn(T) -> PR + Send + Sync,
172{
173    provider: PT,
174    transform: F,
175    _data: PhantomData<(R, T, PR)>,
176}
177
178impl<T, R, PR, PT, F> FlatMap<T, R, PT, PR, F>
179where
180    T: Send + Sync + Clone,
181    R: Send + Sync + Clone,
182    PT: Provider<T>,
183    PR: Provider<R>,
184    F: Fn(T) -> PR + Send + Sync,
185{
186    pub(super) fn new(provider: PT, transform: F) -> Self {
187        Self {
188            provider,
189            transform,
190            _data: PhantomData,
191        }
192    }
193}
194
195impl<T, R, PT, PR, F> Buildable for FlatMap<T, R, PT, PR, F>
196where
197    F: Fn(T) -> PR + Send + Sync,
198    PR: Provider<R>,
199    PT: Provider<T>,
200    R: Clone + Send + Sync,
201    T: Clone + Send + Sync,
202{
203    fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
204        self.provider.get_dependencies(project)
205    }
206}
207
208impl<T, R, PT, PR, F> Debug for FlatMap<T, R, PT, PR, F>
209where
210    F: Fn(T) -> PR + Send + Sync,
211    PR: Provider<R>,
212    PT: Provider<T>,
213    R: Clone + Send + Sync,
214    T: Clone + Send + Sync,
215{
216    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
217        write!(f, "FlatMap<{:?}>", self.provider)
218    }
219}
220
221impl<T, R, PT, PR, F> Provider<R> for FlatMap<T, R, PT, PR, F>
222where
223    T: Send + Sync + Clone,
224    R: Send + Sync + Clone,
225    PT: Provider<T>,
226    PR: Provider<R>,
227    F: Fn(T) -> PR + Send + Sync,
228{
229    fn missing_message(&self) -> String {
230        self.provider.missing_message()
231    }
232
233    fn get(&self) -> R {
234        let start = self
235            .provider
236            .try_get()
237            .unwrap_or_else(|| panic!("{}", self.provider.missing_message()));
238        let transformed = (self.transform)(start);
239        transformed
240            .try_get()
241            .unwrap_or_else(|| panic!("{}", transformed.missing_message()))
242    }
243
244    fn try_get(&self) -> Option<R> {
245        self.provider
246            .try_get()
247            .and_then(|gotten| (self.transform)(gotten).try_get())
248    }
249}
250
251#[derive(Clone)]
252pub struct Zip<T, B, R, F>
253where
254    T: Send + Sync + Clone,
255    B: Send + Sync + Clone,
256    R: Send + Sync + Clone,
257    F: Fn(T, B) -> R + Send + Sync,
258{
259    left: Arc<dyn Provider<T>>,
260    right: Arc<dyn Provider<B>>,
261    transform: F,
262}
263
264impl<T, B, R, F> Zip<T, B, R, F>
265where
266    T: Send + Sync + Clone,
267    B: Send + Sync + Clone,
268    R: Send + Sync + Clone,
269    F: Fn(T, B) -> R + Send + Sync,
270{
271    pub fn new<PL, PR>(left: PL, right: PR, zip_func: F) -> Self
272    where
273        PL: IntoProvider<T>,
274        <PL as IntoProvider<T>>::Provider: 'static,
275        PR: IntoProvider<B>,
276        <PR as IntoProvider<B>>::Provider: 'static,
277    {
278        Self {
279            left: Arc::new(left.into_provider()),
280            right: Arc::new(right.into_provider()),
281            transform: zip_func,
282        }
283    }
284}
285
286impl<T, B, R, F> Buildable for Zip<T, B, R, F>
287where
288    B: Clone + Send + Sync,
289    F: Fn(T, B) -> R + Send + Sync,
290    R: Clone + Send + Sync,
291    T: Clone + Send + Sync,
292{
293    fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
294        self.left.get_dependencies(project)
295    }
296}
297
298impl<T, B, R, F> Debug for Zip<T, B, R, F>
299where
300    B: Clone + Send + Sync,
301    F: Fn(T, B) -> R + Send + Sync,
302    R: Clone + Send + Sync,
303    T: Clone + Send + Sync,
304{
305    fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
306        todo!()
307    }
308}
309
310impl<T, B, R, F> Provider<R> for Zip<T, B, R, F>
311where
312    T: Send + Sync + Clone,
313    B: Send + Sync + Clone,
314    R: Send + Sync + Clone,
315    F: Fn(T, B) -> R + Send + Sync,
316{
317    fn missing_message(&self) -> String {
318        format!(
319            "{} or {}",
320            self.left.missing_message(),
321            self.right.missing_message()
322        )
323    }
324
325    fn try_get(&self) -> Option<R> {
326        let left = self.left.try_get();
327        let right = self.right.try_get();
328
329        left.zip(right).map(|(l, r)| (self.transform)(l, r))
330    }
331}
332
333impl<T: Send + Sync + Clone + Debug, F: Send + FnOnce() -> T> Buildable for Lazy<T, F> {
334    fn get_dependencies(&self, _project: &Project) -> ProjectResult<HashSet<TaskId>> {
335        Ok(HashSet::new())
336    }
337}
338
339impl<T: Send + Sync + Clone + Debug> Buildable for Option<T> {
340    fn get_dependencies(&self, _project: &Project) -> ProjectResult<HashSet<TaskId>> {
341        Ok(HashSet::new())
342    }
343}
344
345impl<T: Send + Sync + Clone + Debug> Provider<T> for Option<T> {
346    fn try_get(&self) -> Option<T> {
347        self.clone()
348    }
349}
350
351impl<T: Send + Sync + Clone + Debug, E: Send + Sync + Debug> Buildable for Result<T, E> {
352    fn get_dependencies(&self, _project: &Project) -> ProjectResult<HashSet<TaskId>> {
353        Ok(HashSet::new())
354    }
355}
356
357impl<T: Send + Sync + Clone + Debug, E: Send + Sync + Debug> Provider<T> for Result<T, E> {
358    fn try_get(&self) -> Option<T> {
359        self.as_ref().ok().cloned()
360    }
361}
362
363impl<T: Send + Sync + Clone + Debug, F: Send + FnOnce() -> T> Provider<T> for Lazy<T, F> {
364    fn try_get(&self) -> Option<T> {
365        Some(Lazy::force(self).clone())
366    }
367}
368
369/// Used to flatten providers
370pub type Flatten<T, B, P> = FlatMap<T, B, P, T, fn(T) -> T>;