assemble_core/lazy_evaluation/
prop.rs

1use 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/// A property that contains a value. Once a property is created, only types that
30/// use the correct type are used.
31#[derive(Clone)]
32pub struct AnyProp {
33    id: Id,
34    inner: Arc<dyn Any + Send + Sync>,
35    ty_id: TypeId,
36}
37
38impl AnyProp {
39    /// Creates a new, empty property
40    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    /// Creates a new property with this value set
50    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    /// Sets
60    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
96/// A typed prop
97pub 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    /// The identifier of the property
225    pub fn id(&self) -> &Id {
226        &self.id
227    }
228}
229
230impl<P: AsRef<Path> + Send + Sync + Clone> Prop<P> {
231    /// Attempt to open the file using given open_options
232    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    /// Attempt to read a file
238    pub fn read(&self) -> ProjectResult<File> {
239        self.open(OpenOptions::new().read(true))
240    }
241
242    /// Attempt to read a file
243    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/// A vec prop is a special property that uses a list
325#[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    /// A vec prop will never return an empty vec
381    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    /// create a new vec prop with a given id
400    pub fn new(id: Id) -> Self {
401        Self {
402            id,
403            prop: Arc::new(RwLock::new(vec![])),
404        }
405    }
406
407    /// Resets this property to contain only the values from the provider
408    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    /// Push a value to the vector
423    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    /// Push all value to the vector
434    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    /// Push a value to the vector
450    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    /// Push a value to the vector
459    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    /// Clears the contents of the vector
469    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}