assemble_core/lazy_evaluation/
prop.rs1use std::any::{Any, TypeId};
2use std::collections::HashSet;
3use std::fmt;
4use std::fmt::{Debug, Display, Formatter};
5use std::fs::{File, OpenOptions};
6
7use std::ops::Deref;
8use std::path::{Path, PathBuf};
9use std::sync::{Arc, PoisonError, RwLock};
10
11use serde::ser::Error as SerdeError;
12use serde::{Serialize, Serializer};
13
14use crate::identifier::Id;
15use crate::identifier::TaskId;
16use crate::lazy_evaluation::anonymous::AnonymousProvider;
17
18use crate::lazy_evaluation::Error::PropertyNotSet;
19use crate::lazy_evaluation::{IntoProvider, Provider, Wrapper};
20use crate::lazy_evaluation::{ProviderError, ProviderExt};
21use crate::prelude::ProjectResult;
22use crate::project::buildable::Buildable;
23
24use crate::error::PayloadError;
25use crate::{provider, Project};
26
27assert_impl_all!(AnyProp: Send, Sync, Clone, Debug);
28
29#[derive(Clone)]
32pub struct AnyProp {
33 id: Id,
34 inner: Arc<dyn Any + Send + Sync>,
35 ty_id: TypeId,
36}
37
38impl AnyProp {
39 pub fn new<T: 'static + Send + Sync + Clone>(id: Id) -> Self {
41 let ty_id = TypeId::of::<T>();
42 Self {
43 id: id.clone(),
44 inner: Arc::new(Prop::<T>::new(id)),
45 ty_id,
46 }
47 }
48
49 pub fn with<T: 'static + IntoProvider<R>, R: 'static + Send + Sync + Clone>(
51 id: Id,
52 value: T,
53 ) -> Self {
54 let mut output = Self::new::<R>(id);
55 output.set(value).unwrap();
56 output
57 }
58
59 pub fn set<T: 'static + IntoProvider<R>, R: 'static + Send + Sync + Clone>(
61 &mut self,
62 value: T,
63 ) -> Result<(), Error> {
64 let mut with_ty: Prop<R> = self.clone().into_ty()?;
65 with_ty.set_with(value)?;
66 Ok(())
67 }
68
69 pub fn into_ty<T: 'static + Send + Sync + Clone>(self) -> Result<Prop<T>, Error> {
70 Prop::try_from(self)
71 }
72
73 pub fn as_ty<T: 'static + Send + Sync + Clone>(&self) -> Result<Prop<T>, Error> {
74 Prop::try_from(self.clone())
75 }
76}
77
78impl Debug for AnyProp {
79 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
80 write!(f, "Property {}", self.id)
81 }
82}
83
84impl<T: Send + Sync + Clone> From<Prop<T>> for AnyProp {
85 fn from(prop: Prop<T>) -> Self {
86 let id = prop.id.clone();
87 let ty_id = TypeId::of::<T>();
88 AnyProp {
89 id,
90 inner: Arc::new(prop),
91 ty_id,
92 }
93 }
94}
95
96pub struct Prop<T: 'static + Send + Sync + Clone> {
98 id: Id,
99 ty_string: String,
100 inner: Arc<RwLock<PropInner<T>>>,
101}
102
103impl<T: 'static + Send + Sync + Clone> Default for Prop<T> {
104 fn default() -> Self {
105 Self::new(Id::default())
106 }
107}
108
109impl<T: 'static + Send + Sync + Clone + Debug> Debug for Prop<T> {
110 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
111 if f.alternate() {
112 match self.fallible_get() {
113 Ok(v) => {
114 write!(f, "{:#?}", v)
115 }
116 Err(_) => {
117 write!(f, "<no value>")
118 }
119 }
120 } else {
121 let id = self.id.clone();
122 let read = self.inner.read().unwrap();
123
124 match &*read {
125 PropInner::Unset => {
126 write!(f, "Prop {{ id: {:?} }}>", self.id)
127 }
128 PropInner::Provided(inner) => f
129 .debug_struct("Prop")
130 .field("id", &id)
131 .field("value", &inner)
132 .finish(),
133 }
134 }
135 }
136}
137
138impl<T: 'static + Send + Sync + Clone + Display> Display for Prop<T> {
139 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
140 match self.fallible_get() {
141 Ok(v) => {
142 write!(f, "{}", v)
143 }
144 Err(_) => {
145 write!(f, "<unset>")
146 }
147 }
148 }
149}
150
151impl<T: 'static + Send + Sync + Clone + Debug> Buildable for Prop<T> {
152 fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
153 let inner = self.inner.read().map_err(PayloadError::new)?;
154 match &*inner {
155 PropInner::Unset => Ok(HashSet::new()),
156 PropInner::Provided(p) => p.get_dependencies(project),
157 }
158 }
159}
160
161impl<T: 'static + Send + Sync + Clone + Debug> Provider<T> for Prop<T> {
162 fn missing_message(&self) -> String {
163 match &*self.inner.read().unwrap() {
164 PropInner::Unset => {
165 format!("{:?} has no value", self.id)
166 }
167 PropInner::Provided(p) => p.missing_message(),
168 }
169 }
170
171 fn try_get(&self) -> Option<T> {
172 Self::fallible_get(self).ok()
173 }
174}
175
176impl<T: 'static + Send + Sync + Clone> Prop<T> {
177 pub fn new(id: Id) -> Self {
178 Self {
179 id,
180 ty_string: std::any::type_name::<T>().to_string(),
181 inner: Arc::new(RwLock::new(PropInner::Unset)),
182 }
183 }
184
185 pub fn with_name<S: AsRef<str>>(id: S) -> Self {
186 Self {
187 id: Id::new(id).unwrap(),
188 ty_string: std::any::type_name::<T>().to_string(),
189 inner: Arc::new(RwLock::new(PropInner::Unset)),
190 }
191 }
192
193 pub fn with_value(value: T) -> Self {
194 let mut output = Self::new(Default::default());
195 output.set(value).unwrap();
196 output
197 }
198
199 pub fn set_with<P: IntoProvider<T>>(&mut self, val: P) -> Result<(), Error>
200 where
201 <P as IntoProvider<T>>::Provider: 'static,
202 {
203 let mut inner = self.inner.write()?;
204 let provider = val.into_provider();
205 inner.set(provider);
206 Ok(())
207 }
208
209 pub fn set<P>(&mut self, val: P) -> Result<(), Error>
210 where
211 P: Into<T>,
212 {
213 self.set_with(Wrapper(val.into()))
214 }
215
216 fn fallible_get(&self) -> Result<T, Error> {
217 let inner = self.inner.read()?;
218 match &*inner {
219 PropInner::Unset => Err(PropertyNotSet),
220 PropInner::Provided(provo) => provo.deref().try_get().ok_or(PropertyNotSet),
221 }
222 }
223
224 pub fn id(&self) -> &Id {
226 &self.id
227 }
228}
229
230impl<P: AsRef<Path> + Send + Sync + Clone> Prop<P> {
231 pub fn open(&self, open_options: &OpenOptions) -> ProjectResult<File> {
233 let path = self.fallible_get().map_err(PayloadError::new)?;
234 Ok(open_options.open(path).map_err(PayloadError::new)?)
235 }
236
237 pub fn read(&self) -> ProjectResult<File> {
239 self.open(OpenOptions::new().read(true))
240 }
241
242 pub fn create(&self) -> ProjectResult<File> {
244 self.open(OpenOptions::new().write(true).create(true))
245 }
246}
247
248impl<T: 'static + Send + Sync + Clone> TryFrom<AnyProp> for Prop<T> {
249 type Error = Error;
250
251 fn try_from(value: AnyProp) -> Result<Self, Self::Error> {
252 let ty_id = TypeId::of::<T>();
253 if value.ty_id != ty_id {
254 Err(Error::TypeMismatch {
255 expected: value.ty_id,
256 found: ty_id,
257 })
258 } else {
259 let cloned = value.inner.clone();
260 let downcast = cloned.downcast_ref::<Prop<T>>().unwrap();
261 let take = downcast.clone();
262 Ok(take)
263 }
264 }
265}
266
267impl<T: 'static + Send + Sync + Clone> Clone for Prop<T> {
268 fn clone(&self) -> Self {
269 Self {
270 id: self.id.clone(),
271 ty_string: self.ty_string.clone(),
272 inner: self.inner.clone(),
273 }
274 }
275}
276
277enum PropInner<T: Send + Sync + Clone> {
278 Unset,
279 Provided(Box<dyn Provider<T>>),
280}
281
282impl<T: Send + Sync + Clone> PropInner<T> {
283 fn new() -> Self {
284 Self::Unset
285 }
286
287 fn set<P: 'static + Provider<T>>(&mut self, value: P) -> Option<T> {
288 let get = self.get();
289 *self = PropInner::Provided(Box::new(value));
290 get
291 }
292
293 fn get(&self) -> Option<T> {
294 match self {
295 PropInner::Unset => None,
296 PropInner::Provided(provider) => provider.as_ref().try_get(),
297 }
298 }
299
300 fn take_inner(&mut self) -> Option<Box<dyn Provider<T>>> {
301 match std::mem::replace(self, Self::Unset) {
302 PropInner::Unset => None,
303 PropInner::Provided(p) => Some(p),
304 }
305 }
306}
307
308#[derive(Debug, thiserror::Error)]
309pub enum Error {
310 #[error("Property's lock was poisoned")]
311 LockPoisonError,
312 #[error("Type Mismatch (Expected = {:?}, Found = {:?})", expected, found)]
313 TypeMismatch { expected: TypeId, found: TypeId },
314 #[error("Property has no value set")]
315 PropertyNotSet,
316}
317
318impl<T> From<PoisonError<T>> for Error {
319 fn from(_: PoisonError<T>) -> Self {
320 Self::LockPoisonError
321 }
322}
323
324#[derive(Clone)]
326pub struct VecProp<T: Send + Sync + Clone> {
327 id: Id,
328 prop: Arc<RwLock<Vec<AnonymousProvider<Vec<T>>>>>,
329}
330
331assert_impl_all!(VecProp<PathBuf>: Provider<Vec<PathBuf>>);
332assert_impl_all!(VecProp<String>: Provider<Vec<String>>);
333
334impl<T: 'static + Send + Sync + Clone> Default for VecProp<T> {
335 fn default() -> Self {
336 Self::new(Id::default())
337 }
338}
339
340impl<T: 'static + Send + Sync + Clone> Buildable for VecProp<T> {
341 fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
342 self.prop
343 .read()
344 .map_err(PayloadError::new)?
345 .iter()
346 .map(|s| s.get_dependencies(project))
347 .collect::<ProjectResult<Vec<_>>>()
348 .map(|s| s.into_iter().flatten().collect())
349 }
350}
351
352impl<T: 'static + Send + Sync + Clone> Debug for VecProp<T> {
353 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
354 let inner = self.prop.read().map_err(|_| fmt::Error)?;
355 write!(f, "VecProp ")?;
356 let mut debug_vec = f.debug_list();
357 for prov in &*inner {
358 debug_vec.entry(prov);
359 }
360 debug_vec.finish()
361 }
362}
363
364impl<T: 'static + Send + Sync + Clone> Provider<Vec<T>> for VecProp<T> {
365 fn missing_message(&self) -> String {
366 let read = self.prop.read().expect("poisoned");
367 let first_missing = read
368 .iter()
369 .filter(|p| p.try_get().is_none())
370 .map(|prop| prop.missing_message())
371 .next();
372 match first_missing {
373 None => {
374 format!("{} missing unknown value", self.id)
375 }
376 Some(msg) => format!("{} vector missing value > {}", self.id, msg),
377 }
378 }
379
380 fn try_get(&self) -> Option<Vec<T>> {
382 let read = self.prop.read().expect("poisoned");
383 read.iter()
384 .map(|p| p.try_get())
385 .collect::<Option<Vec<Vec<T>>>>()
386 .map(|o| o.into_iter().flatten().collect())
387 }
388
389 fn fallible_get(&self) -> Result<Vec<T>, ProviderError> {
390 let read = self.prop.read().expect("poisoned");
391 read.iter()
392 .map(|p| p.fallible_get())
393 .collect::<Result<Vec<Vec<T>>, _>>()
394 .map(|v| v.into_iter().flatten().collect())
395 }
396}
397
398impl<T: 'static + Send + Sync + Clone> VecProp<T> {
399 pub fn new(id: Id) -> Self {
401 Self {
402 id,
403 prop: Arc::new(RwLock::new(vec![])),
404 }
405 }
406
407 pub fn from<I: IntoIterator<Item = T> + Clone + Send + Sync, P: IntoProvider<I>>(
409 &mut self,
410 values: P,
411 ) where
412 P::Provider: 'static,
413 I: 'static,
414 {
415 let mut write = self.prop.write().expect("poisoned");
416 write.clear();
417 let anonymous: AnonymousProvider<Vec<T>> =
418 AnonymousProvider::new(values.into_provider().map(|v| v.into_iter().collect()));
419 write.push(anonymous);
420 }
421
422 pub fn push_with<P>(&mut self, value: P)
424 where
425 P: IntoProvider<T>,
426 P::Provider: 'static,
427 {
428 let mut write = self.prop.write().expect("vec panicked");
429 let anonymous = AnonymousProvider::new(value.into_provider().map(|v| vec![v]));
430 write.push(anonymous);
431 }
432
433 pub fn push_all_with<P, I>(&mut self, value: P)
435 where
436 I: IntoIterator<Item = T> + Clone + Send + Sync + 'static,
437 P: IntoProvider<I>,
438 P::Provider: 'static,
439 {
440 let mut write = self.prop.write().expect("vec panicked");
441 let anonymous = AnonymousProvider::new(
442 value
443 .into_provider()
444 .map(|v| v.into_iter().collect::<Vec<_>>()),
445 );
446 write.push(anonymous);
447 }
448
449 pub fn push<V>(&mut self, value: V)
451 where
452 V: Into<T>,
453 {
454 let value = value.into();
455 self.push_with(provider!(move || value.clone()))
456 }
457
458 pub fn push_all<V, I: IntoIterator<Item = V>>(&mut self, value: I)
460 where
461 V: Into<T>,
462 {
463 for x in value {
464 self.push(x);
465 }
466 }
467
468 pub fn clear(&mut self) {
470 let mut write = self.prop.write().expect("vec panicked");
471 write.clear();
472 }
473}
474
475impl<P, T: 'static + Send + Sync + Clone> Extend<P> for VecProp<T>
476where
477 P: IntoProvider<T>,
478 P::Provider: 'static,
479{
480 fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
481 for p in iter {
482 self.push_with(p);
483 }
484 }
485}
486
487impl<T: 'static + Send + Sync + Clone> IntoIterator for VecProp<T> {
488 type Item = T;
489 type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
490
491 fn into_iter(self) -> Self::IntoIter {
492 self.get().into_iter()
493 }
494}
495
496impl<T: Serialize> Serialize for VecProp<T>
497where
498 T: 'static + Send + Sync + Clone,
499{
500 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
501 where
502 S: Serializer,
503 {
504 self.fallible_get()
505 .map_err(S::Error::custom)?
506 .serialize(serializer)
507 }
508}
509
510#[cfg(test)]
511mod tests {
512 use crate::identifier::Id;
513 use crate::lazy_evaluation::providers::Zip;
514 use crate::lazy_evaluation::{AnyProp, Prop, Provider};
515 use crate::lazy_evaluation::{ProviderExt, VecProp};
516 use crate::provider;
517
518 #[test]
519 fn create_property() {
520 let prop = AnyProp::new::<i32>("value".into());
521 let mut ty_prop = prop.into_ty::<i32>().unwrap();
522 let cloned = ty_prop.clone();
523 ty_prop.set_with(provider!(|| 15)).unwrap();
524 let gotten = ty_prop.get();
525 assert_eq!(gotten, 15i32);
526
527 let prop = ty_prop.map(|i| i * i);
528 let get = prop.get();
529 assert_eq!(get, 15i32 * 15);
530 assert_eq!(cloned.get(), 15i32);
531 }
532
533 #[test]
534 fn list_properties_from() {
535 let mut prop = VecProp::<i32>::default();
536 let other_prop = prop.clone();
537 prop.push_with(provider!(|| 1));
538 prop.extend([provider!(|| 2), provider!(|| 3)]);
539 assert_eq!(other_prop.get(), vec![1, 2, 3]);
540 }
541
542 #[test]
543 fn list_properties_join() {
544 let mut prop = VecProp::<i32>::default();
545 prop.from(Zip::new(
546 provider!(|| vec![1, 2]),
547 provider!(|| vec![3, 4]),
548 |left, right| left.into_iter().chain(right).collect::<Vec<_>>(),
549 ));
550 assert_eq!(prop.get(), vec![1, 2, 3, 4]);
551 }
552
553 #[test]
554 fn vec_prop_missing() {
555 let mut vec_prop = VecProp::<i32>::new(Id::from("test"));
556 let mut prop1 = Prop::new(Id::from("prop1"));
557 let mut prop2 = Prop::new(Id::from("prop2"));
558 vec_prop.push_with(prop1.clone());
559 vec_prop.push_with(prop2.clone());
560 vec_prop.push_all_with(provider!(|| vec![1, 2]));
561 assert_eq!(
562 vec_prop.missing_message(),
563 format!(":test vector missing value > {}", prop1.missing_message())
564 );
565 assert!(vec_prop.try_get().is_none());
566 prop1.set(0).unwrap();
567 assert_eq!(
568 vec_prop.missing_message(),
569 format!(":test vector missing value > {}", prop2.missing_message())
570 );
571 assert!(vec_prop.try_get().is_none());
572 prop2.set(0).unwrap();
573 assert_eq!(vec_prop.get(), vec![0, 0, 1, 2]);
574 }
575}