1use std::collections::HashSet;
5use std::error::Error;
6use std::io::Write;
7use std::path::{Path, PathBuf};
8use std::{fs, io};
9
10fn find_headers<P: AsRef<Path>>(dir: P) -> Result<Vec<PathBuf>, io::Error> {
11 fn find_headers_inner<P: AsRef<Path>>(dir: P, headers: &mut Vec<PathBuf>) -> io::Result<()> {
12 for entry in fs::read_dir(dir)? {
13 let entry = entry?;
14 let metadata = entry.metadata()?;
15
16 let path = entry.path();
17 if metadata.file_type().is_dir() {
18 find_headers_inner(path, headers)?;
19 } else {
20 if path.extension().map(|ext| ext == "h").unwrap_or(false) {
21 headers.push(path);
22 }
23 }
24 }
25
26 Ok(())
27 }
28
29 let mut headers = Vec::new();
30 find_headers_inner(dir, &mut headers)?;
31
32 Ok(headers)
33}
34
35fn parse_iid(tokens: &[String]) -> Option<String> {
36 if let Some(first) = tokens.first() {
37 if first == "DECLARE_CLASS_IID" {
38 return Some(format!(
39 "pub const {}_iid: TUID = uid({}, {}, {}, {});",
40 tokens[2], tokens[4], tokens[6], tokens[8], tokens[10]
41 ));
42 }
43 }
44
45 None
46}
47
48pub fn generate(
50 sdk_dir: &Path,
51 target: Option<&str>,
52 mut sink: impl Write,
53) -> Result<(), Box<dyn Error>> {
54 let pluginterfaces_path = sdk_dir.join("pluginterfaces");
55 let headers = find_headers(&pluginterfaces_path)?;
56
57 let skip_headers = HashSet::from([
58 Path::new("pluginterfaces/base/funknownimpl.h"),
59 Path::new("pluginterfaces/base/ustring.h"),
60 Path::new("pluginterfaces/test/itest.h"),
61 Path::new("pluginterfaces/vst/ivsttestplugprovider.h"),
62 ]);
63
64 let mut source = String::new();
65 for header in &headers {
66 let relative = header.strip_prefix(sdk_dir).unwrap();
67 if skip_headers.contains(relative) {
68 continue;
69 }
70
71 let name = relative.to_str().unwrap();
72
73 use std::fmt::Write;
74 writeln!(source, "#include \"{}\"", name)?;
75 }
76
77 writeln!(sink, "{}", include_str!("support.rs"))?;
78
79 let mut generator = com_scrape::Generator::default()
80 .skip_types(&[
81 "Adopt",
82 "ConstStringTable",
83 "FUID",
84 "FReleaser",
85 "LARGE_INT",
86 ])
87 .skip_interface_trait("FUnknown")
88 .constant_parser(parse_iid)
89 .iid_generator(|name| format!("tuid_as_guid({name}_iid)"))
90 .query_interface_fn("FUnknown_query_interface")
91 .add_ref_fn("FUnknown_add_ref")
92 .release_fn("FUnknown_release")
93 .include_path(sdk_dir);
94
95 if let Some(target) = target {
96 generator = generator.target(target);
97 }
98
99 generator.generate(source, &mut sink)?;
100
101 Ok(())
102}