1use 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#[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
24pub 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#[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#[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
369pub type Flatten<T, B, P> = FlatMap<T, B, P, T, fn(T) -> T>;