ninja_files_data2/build/
builder.rs

1use std::collections::{BTreeMap, BTreeSet};
2
3use camino::Utf8Path;
4
5use crate::{
6    Build, FileName, InvalidFileName, InvalidRuleId, InvalidVariable, InvalidVariableId, RuleId,
7    Variable, VariableId,
8};
9
10#[derive(Debug, Clone)]
11pub struct BuildBuilder {
12    rule: Option<RuleId>,
13    explicits: BTreeSet<FileName>,
14    implicits: BTreeSet<FileName>,
15    order: BTreeSet<FileName>,
16    dyndep: Option<FileName>,
17    shadow: BTreeMap<VariableId, Variable>,
18    errors: Vec<BuildBuilderError>,
19}
20
21#[derive(Debug, Clone)]
22pub enum BuildBuilderError {
23    InvalidRuleId(InvalidRuleId),
24    InvalidFileName(InvalidFileName),
25    InvalidVariable(InvalidVariable),
26    InvalidVariableId(InvalidVariableId),
27    DynDepAlreadyDefined {
28        previous: FileName,
29        dyndep: FileName,
30    },
31    VariableAlreadyDefined {
32        id: VariableId,
33        previous: Variable,
34        var: Variable,
35    },
36}
37
38impl BuildBuilder {
39    pub fn new<Id>(rule_id: Id) -> Self
40    where
41        Id: AsRef<str>,
42    {
43        let rule_id = RuleId::try_create(rule_id);
44        let mut errors = vec![];
45        if let Some(err) = rule_id.clone().err() {
46            errors.push(BuildBuilderError::InvalidRuleId(err));
47        }
48
49        let rule = rule_id.ok();
50        BuildBuilder {
51            rule,
52            errors,
53            explicits: BTreeSet::new(),
54            implicits: BTreeSet::new(),
55            order: BTreeSet::new(),
56            dyndep: None,
57            shadow: BTreeMap::new(),
58        }
59    }
60
61    pub fn build(&self) -> Result<Build, Vec<BuildBuilderError>> {
62        if !self.errors.is_empty() {
63            return Err(self.errors.clone());
64        }
65        //Bug if none at this point
66        let build = Build {
67            rule: self.rule.clone().unwrap(),
68            explicits: self.explicits.clone(),
69            implicits: self.implicits.clone(),
70            order: self.order.clone(),
71            dyndep: self.dyndep.clone(),
72            shadow: self.shadow.clone(),
73        };
74        Ok(build)
75    }
76
77    pub fn explicit<Dep>(mut self, dep: Dep) -> Self
78    where
79        Dep: AsRef<Utf8Path>,
80    {
81        let filename = FileName::try_create(dep);
82        match filename {
83            Ok(file) => {
84                self.explicits.insert(file);
85            }
86            Err(err) => self.errors.push(BuildBuilderError::InvalidFileName(err)),
87        }
88        self
89    }
90
91    pub fn implicit<Dep>(mut self, dep: Dep) -> Self
92    where
93        Dep: AsRef<Utf8Path>,
94    {
95        let filename = FileName::try_create(dep);
96        match filename {
97            Ok(file) => {
98                self.implicits.insert(file);
99            }
100            Err(err) => self.errors.push(BuildBuilderError::InvalidFileName(err)),
101        }
102        self
103    }
104
105    pub fn order<Dep>(mut self, dep: Dep) -> Self
106    where
107        Dep: AsRef<Utf8Path>,
108    {
109        let filename = FileName::try_create(dep);
110        match filename {
111            Ok(file) => {
112                self.order.insert(file);
113            }
114            Err(err) => self.errors.push(BuildBuilderError::InvalidFileName(err)),
115        }
116        self
117    }
118
119    pub fn dyndep<Dep>(mut self, dep: Dep) -> Self
120    where
121        Dep: AsRef<Utf8Path>,
122    {
123        let filename = FileName::try_create(dep);
124        match (filename, self.dyndep.clone()) {
125            (Ok(file), None) => self.dyndep = Some(file),
126            (Ok(dyndep), Some(previous)) => self
127                .errors
128                .push(BuildBuilderError::DynDepAlreadyDefined { previous, dyndep }),
129            (Err(err), _) => self.errors.push(BuildBuilderError::InvalidFileName(err)),
130        }
131        self
132    }
133
134    pub fn variable<Id, Var>(mut self, id: Id, var: Var) -> Self
135    where
136        Id: AsRef<str>,
137        Var: AsRef<str>,
138    {
139        let id = VariableId::try_create(id);
140        let var = Variable::try_create(var);
141        match (id, var) {
142            (Ok(id), Ok(var)) => match self.shadow.insert(id.clone(), var.clone()) {
143                Some(previous) if var == previous => (),
144                Some(previous) => self.errors.push(BuildBuilderError::VariableAlreadyDefined {
145                    id,
146                    previous,
147                    var,
148                }),
149                None => (),
150            },
151            (Ok(_), Err(v)) => self.errors.push(BuildBuilderError::InvalidVariable(v)),
152            (Err(i), Ok(_)) => self.errors.push(BuildBuilderError::InvalidVariableId(i)),
153            (Err(i), Err(v)) => {
154                self.errors.push(BuildBuilderError::InvalidVariable(v));
155                self.errors.push(BuildBuilderError::InvalidVariableId(i));
156            }
157        }
158        self
159    }
160}
161
162impl From<Build> for BuildBuilder {
163    fn from(
164        Build {
165            rule,
166            explicits,
167            implicits,
168            order,
169            dyndep,
170            shadow,
171        }: Build,
172    ) -> Self {
173        BuildBuilder {
174            rule: Some(rule),
175            explicits,
176            implicits,
177            order,
178            dyndep,
179            shadow,
180            errors: vec![],
181        }
182    }
183}