aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/inference_rules.rs
blob: dfbb07c44f61175f214ce031aead461c2870e5be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use std::fmt;

use eyre::{eyre, Result};
use regex::Captures;

use super::command_line::CommandLine;
use super::pattern::r#match;

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct InferenceRule {
    pub products: Vec<String>,
    pub prerequisites: Vec<String>,
    pub commands: Vec<CommandLine>,
}

impl InferenceRule {
    /// s1 is the product, s2 is the prereq
    pub fn new_suffix(s1: String, s2: String, commands: Vec<CommandLine>) -> Self {
        Self {
            products: vec![format!("%.{}", s1)],
            prerequisites: vec![format!("%.{}", s2)],
            commands,
        }
    }

    fn first_match<'s, 't: 's>(&'s self, target_name: &'t str) -> Result<Option<Captures<'t>>> {
        self.products
            .iter()
            .map(|pattern| r#match(pattern, target_name))
            .try_fold(None, |x, y| y.map(|y| x.or(y)))
    }

    pub fn matches(&self, target_name: &str) -> Result<bool> {
        self.first_match(target_name).map(|x| x.is_some())
    }

    pub fn prereqs<'s>(
        &'s self,
        target_name: &'s str,
    ) -> Result<impl Iterator<Item = String> + 's> {
        let capture = self
            .first_match(target_name)?
            .ok_or_else(|| eyre!("asked non-matching inference rule for prerequisites"))?;
        let percent_expansion = capture.get(1).expect("should've matched the %").as_str();
        Ok(self
            .prerequisites
            .iter()
            .map(move |p| p.replace('%', percent_expansion)))
    }
}

impl fmt::Display for InferenceRule {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(
            f,
            "{}: {}",
            self.products.join(" "),
            self.prerequisites.join(" ")
        )?;
        for command in &self.commands {
            writeln!(f, "\t{}", command)?;
        }
        Ok(())
    }
}