devbox_build/
res.rs

1use std::{fmt::Debug, ops::Add, time::SystemTime};
2
3//-- Resource --------------------------------------------------------------------------------------
4
5/// A resource represents anything that is input or output of a build step.
6///
7/// Typical resources are files and directories with build steps like copying, moving, linking or
8/// invoking external commands.
9///
10/// The main resource property is it's optional timestamp. Build steps should treat output resources
11/// without one as out of date and build it unconditionally. When input resource does not have it's
12/// timestamp it should be considered as changed and therefore rebuild the output the same way as
13/// when input is newer the output. Typical scenario for lack or timestamp is when output resources
14/// do not exists yet (clean builds)
15///
16pub trait Resource : Debug {
17
18    /// Name of the resource used for logging and error reporting
19    //fn name(&self) -> &str;
20
21    /// Return resource timestamp. Can be None for input resources that should be considered as
22    /// changed in every build run or output resources that do not exists yet.
23    fn timestamp(&self) -> Option<SystemTime>;
24
25    /// Build the resource form a given `src` resource as a side product of given function `by`
26    /// respecting resource timestamps meaning that function `by` will only be ran if the output
27    /// needs to be build.
28    ///
29    /// This method forces the `by` function to handle any errors on it's own and stop Cargo build
30    /// using a panic. To propagate the error, use [`mk_from_result()`](#method.mk_from_result)
31    ///
32    //TODO: test
33    fn mk_from<F, R, S>(&self, description: &str, src: S, by: F)
34        where R:Resource, S:AsResource<R>, F: FnOnce() -> ()
35    {
36        let src = src.as_res();
37        let target_time = self.timestamp();
38        if target_time == None || src.timestamp() > target_time {
39            println!("Building: {:?} from {:?}: {}", self, src, description);
40            by();
41        }
42    }
43
44    /// Same as [`mk_from()`](#method.mk_from) with error propagation
45    //TODO: test
46    fn mk_from_result<E, F, R, S>(&self, description: &str, src: S, by: F) -> Result<(), E>
47        where R:Resource, S:AsRef<R>, F: FnOnce() -> Result<(), E>
48    {
49        let src = src.as_ref();
50        let target_time = self.timestamp();
51        if target_time == None || src.timestamp() > target_time {
52            println!("Building: {:?} from {:?}: {}", self, src, description);
53            return by()
54        }
55
56        Ok(())
57    }
58}
59
60pub trait AsResource<R> {
61    fn as_res(&self) -> &R;
62}
63
64impl<R> AsResource<R> for R where R:Resource {
65    fn as_res(&self) -> &R {
66        &self
67    }
68}
69
70impl<R> AsResource<R> for &R where R:Resource {
71    fn as_res(&self) -> &R {
72        self
73    }
74}
75
76//--- Resource for Vec -----------------------------------------------------------------------------
77
78impl<R> Resource for Vec<R>
79    where R:Resource
80{
81    fn timestamp(&self) -> Option<SystemTime> {
82        timestamp(self.iter())
83    }
84}
85
86//TODO: test
87pub fn timestamp<T: AsResource<R>, R: Resource>(iter: impl Iterator<Item=T>) -> Option<SystemTime> {
88    iter.fold(None, |result, entry| {
89        let timestamp = entry.as_res().timestamp();
90        if timestamp > result {
91            return timestamp;
92        }
93        result
94    })
95}
96
97//-- Set -------------------------------------------------------------------------------------------
98
99/// Ordered list of owned resources
100///
101/// This is like Vec with '+' overloaded for easy adding of resources. Resources added by reference
102/// are cloned.
103///
104#[derive(Debug,Clone)]
105pub struct Set<T> {
106    items: Vec<T>
107}
108
109impl<R> Add<&R> for Set<R> where R: Clone {
110    type Output = Set<R>;
111
112    fn add(mut self, rhs: &R) -> Self::Output {
113        self.items.push(rhs.clone());
114        self
115    }
116}
117
118impl<R> Add<R> for Set<R> {
119    type Output = Set<R>;
120
121    fn add(mut self, rhs: R) -> Self::Output {
122        self.items.push(rhs);
123        self
124    }
125}
126
127impl<T> AsRef<Set<T>> for Set<T> {
128    fn as_ref(&self) -> &Set<T> {
129        self
130    }
131}
132
133impl<T> From<Vec<T>> for Set<T> {
134    fn from(val: Vec<T>) -> Self {
135        Set { items: val }
136    }
137}
138
139impl<T> IntoIterator for Set<T> {
140    type Item = T;
141    type IntoIter = std::vec::IntoIter<Self::Item>;
142
143    fn into_iter(self) -> Self::IntoIter {
144        self.items.into_iter()
145    }
146}
147
148impl<R> Resource for Set<R> where R:Resource {
149
150    fn timestamp(&self) -> Option<SystemTime> {
151        self.items.timestamp()
152    }
153}