diff options
Diffstat (limited to 'src/makefile/inference_rules.rs')
-rw-r--r-- | src/makefile/inference_rules.rs | 97 |
1 files changed, 91 insertions, 6 deletions
diff --git a/src/makefile/inference_rules.rs b/src/makefile/inference_rules.rs index 8d4f3b6..d7db1e6 100644 --- a/src/makefile/inference_rules.rs +++ b/src/makefile/inference_rules.rs @@ -1,18 +1,18 @@ -use std::fmt; +use std::collections::HashMap; +use std::{fmt, mem}; +use super::pattern::r#match; +use super::{CommandLine, ItemSource, MacroSet}; use eyre::{eyre, OptionExt, Result}; use regex::Captures; -use super::command_line::CommandLine; -use super::pattern::r#match; -use super::ItemSource; - -#[derive(PartialEq, Eq, Clone, Debug)] +#[derive(Clone, Debug)] pub struct InferenceRule { pub source: ItemSource, pub products: Vec<String>, pub prerequisites: Vec<String>, pub commands: Vec<CommandLine>, + pub macros: MacroSet, } impl InferenceRule { @@ -22,12 +22,14 @@ impl InferenceRule { s1: String, s2: String, commands: Vec<CommandLine>, + macros: MacroSet, ) -> Self { Self { source, products: vec![format!("%{}", s1)], prerequisites: vec![format!("%{}", s2)], commands, + macros, } } @@ -58,6 +60,30 @@ impl InferenceRule { .iter() .map(move |p| p.replace('%', percent_expansion))) } + + fn extend(&mut self, other: Self) { + assert_eq!(&self.products, &other.products); + match (self.commands.is_empty(), other.commands.is_empty()) { + (false, false) => { + // both rules have commands, so replace this entirely + *self = other; + } + (true, false) => { + // this rule doesn't have commands, but the other one does, + // so it's the real one + let mut other = other; + mem::swap(self, &mut other); + self.extend(other); + } + (false, true) | (true, true) => { + // this rule might have commands, but the other one doesn't, + // so append non-command stuff + // TODO decide something smart about sources + self.prerequisites.extend(other.prerequisites); + self.macros.extend(other.macros); + } + } + } } impl fmt::Display for InferenceRule { @@ -75,6 +101,63 @@ impl fmt::Display for InferenceRule { } } +#[derive(Clone, Default)] +pub struct InferenceRuleSet { + /// Maps from products to a map from prerequisites to rules. + data: HashMap<Vec<String>, HashMap<Vec<String>, InferenceRule>>, +} + +impl InferenceRuleSet { + pub fn get(&self, products: &[String], prerequisites: &[String]) -> Option<&InferenceRule> { + self.data.get(products).and_then(|x| x.get(prerequisites)) + } + + fn get_mut( + &mut self, + products: &[String], + prerequisites: &[String], + ) -> Option<&mut InferenceRule> { + self.data + .get_mut(products) + .and_then(|x| x.get_mut(prerequisites)) + } + + pub fn put(&mut self, rule: InferenceRule) { + if let Some(existing_rule) = self.get_mut(&rule.products, &rule.prerequisites) { + existing_rule.extend(rule); + } else { + self.data + .entry(rule.products.clone()) + .or_default() + .insert(rule.prerequisites.clone(), rule); + } + } + + pub fn len(&self) -> usize { + self.data.len() + } + + pub fn extend(&mut self, other: Self) { + for other in other.data.into_values().flat_map(HashMap::into_values) { + self.put(other); + } + } + + pub fn iter(&self) -> impl Iterator<Item = &InferenceRule> { + self.data.values().flat_map(HashMap::values) + } +} + +impl From<Vec<InferenceRule>> for InferenceRuleSet { + fn from(value: Vec<InferenceRule>) -> Self { + let mut result = Self::default(); + for rule in value { + result.put(rule); + } + result + } +} + #[cfg(test)] mod test { use super::*; @@ -88,6 +171,7 @@ mod test { ".o".to_owned(), ".c".to_owned(), vec![], + MacroSet::new(), ); assert!(rule.matches("foo.o")?); assert!(rule.matches("dir/foo.o")?); @@ -107,6 +191,7 @@ mod test { "goneall.gpg".to_owned(), ], commands: vec![], + macros: MacroSet::new(), }; assert!(rule.matches("licenseListPublisher-2.2.1.jar-valid")?); Ok(()) |