bindgen/
deps.rs

1/// Generating build depfiles from parsed bindings.
2use std::{collections::BTreeSet, path::PathBuf};
3
4#[derive(Clone, Debug)]
5pub(crate) struct DepfileSpec {
6    pub output_module: String,
7    pub depfile_path: PathBuf,
8}
9
10impl DepfileSpec {
11    pub fn write(&self, deps: &BTreeSet<Box<str>>) -> std::io::Result<()> {
12        std::fs::write(&self.depfile_path, self.to_string(deps))
13    }
14
15    fn to_string(&self, deps: &BTreeSet<Box<str>>) -> String {
16        // Transforms a string by escaping spaces and backslashes.
17        let escape = |s: &str| s.replace('\\', "\\\\").replace(' ', "\\ ");
18
19        let mut buf = format!("{}:", escape(&self.output_module));
20        for file in deps {
21            buf = format!("{buf} {}", escape(file));
22        }
23        buf
24    }
25}
26
27#[cfg(test)]
28mod tests {
29    use super::*;
30
31    #[test]
32    fn escaping_depfile() {
33        let spec = DepfileSpec {
34            output_module: "Mod Name".to_owned(),
35            depfile_path: PathBuf::new(),
36        };
37
38        let deps: BTreeSet<_> = vec![
39            r"/absolute/path".into(),
40            r"C:\win\absolute\path".into(),
41            r"../relative/path".into(),
42            r"..\win\relative\path".into(),
43            r"../path/with spaces/in/it".into(),
44            r"..\win\path\with spaces\in\it".into(),
45            r"path\with/mixed\separators".into(),
46        ]
47        .into_iter()
48        .collect();
49        assert_eq!(
50            spec.to_string(&deps),
51            "Mod\\ Name: \
52            ../path/with\\ spaces/in/it \
53            ../relative/path \
54            ..\\\\win\\\\path\\\\with\\ spaces\\\\in\\\\it \
55            ..\\\\win\\\\relative\\\\path \
56            /absolute/path \
57            C:\\\\win\\\\absolute\\\\path \
58            path\\\\with/mixed\\\\separators"
59        );
60    }
61}