1use std::any::Any;
2use std::collections::HashMap;
3use std::fmt;
4
5pub struct Target<'a> {
6 pub key: String,
7 pub dependencies: Vec<&'a Target<'a>>,
8 pub build_order: Vec<&'a Target<'a>>,
9 pub recipe: fn(Vec<&Box<Any>>) -> Box<Any>,
10}
11
12impl<'a> fmt::Debug for Target<'a> {
13 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
14 let deps = self.dependencies.iter().map(|d| d.key.clone()).collect::<Vec<String>>().join(", ");
15 let build_order = self.build_order.iter().map(|d| d.key.clone()).collect::<Vec<String>>().join(", ");
16 write!(f, "Target {{ key: {}, dependencies: {}, build_order: {} }}", self.key, deps, build_order)
17 }
18}
19
20impl<'a> Target<'a> {
21 fn build(&self, deps: &HashMap<String, Box<Any>>) -> Box<Any> {
22 let args: Vec<&Box<Any>> = self.dependencies.iter()
23 .map(|d| deps.get(&d.key).unwrap())
24 .collect();
25
26 (self.recipe)(args)
27 }
28
29 pub fn build_order(deps: Vec<&'a Target<'a>>) -> Vec<&'a Target<'a>> {
30 let mut all_deps : Vec<&Target> = Vec::new();
31 deps.iter().for_each(|dep| all_deps.extend(dep.build_order.clone()));
32 all_deps.extend(deps);
33
34 let mut i: usize = 0;
35 while i != all_deps.len() {
36 if all_deps[..i].contains(&all_deps[i]) {
37 all_deps.remove(i);
38 } else {
39 i += 1;
40 }
41 }
42
43 all_deps
44 }
45}
46
47impl<'a> PartialEq for Target<'a> {
48 fn eq(&self, other: &Target) -> bool {
49 self.key == other.key
50 }
51}
52
53pub struct Builder {
54 resolved: HashMap<String,Box<Any>>,
55}
56
57impl fmt::Debug for Builder {
58 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59 write!(f, "Builder {{ resolved: {} }}", self.resolved.keys().map(|d| d.clone()).collect::<Vec<String>>().join(", "))
60 }
61}
62
63impl Builder {
64 pub fn new(state: Box<Any>) -> Self {
65 let mut resolved : HashMap<String,Box<Any>> = HashMap::new();
67 resolved.insert(String::from("_state"), state);
68
69 Builder {
70 resolved,
71 }
72 }
73
74 pub fn build(&mut self, buildable: &Target) -> &Box<Any> {
75 if self.resolved.contains_key(&buildable.key) {
77 return self.resolved.get(&buildable.key).unwrap();
79 }
80
81 let mut deps: Vec<&&Target> = buildable.build_order.iter()
83 .filter(|dep| !self.resolved.contains_key(&dep.key))
84 .collect();
85
86 while deps.len() != 0 {
88 let target = deps.remove(0);
89 let built = target.build(&self.resolved);
90 assert_eq!(self.resolved.insert(target.key.clone(), built).is_none(), true);
91 }
92
93 let built = buildable.build(&self.resolved);
94 assert_eq!(self.resolved.insert(buildable.key.clone(), built).is_none(), true);
95
96 self.resolved.get(&buildable.key).unwrap()
97 }
98}
99
100#[macro_export]
101macro_rules! capture {
102 ($name:ident) => {
103 let $name = Target {
104 key: String::from("_state"),
105 dependencies: vec![],
106 build_order: vec![],
107 recipe: |_deps| Box::new(1),
108 };
109 };
110}
111
112#[macro_export]
113macro_rules! target {
114 (fn $name:ident ($($arg:ident : $argtype:ty),+) -> $ret:ty = $body:expr) => {
115 let $name = Target {
116 key: String::from(stringify!($name)),
117 dependencies: vec![$(&$arg),*],
118 build_order: Target::build_order(vec![$(&$arg),*]),
119 recipe: |mut deps| {
120 $(
121 let $arg = deps.remove(0).downcast_ref::<$argtype>().expect(stringify!($arg));
122 )*
123 Box::new($body)
124 },
125 };
126 };
127}
128
129#[macro_export]
130macro_rules! build {
131 ($target:ident : $type:ty, $builder:ident) => {
132 {
133 let built = $builder.build(&$target);
134 built.downcast_ref::<$type>().unwrap()
135 }
136 }
137}