1use std::borrow::Cow;
2use std::collections::{HashMap, HashSet};
3use std::env;
4use std::error::Error;
5use std::io::Write;
6use std::path::{Path, PathBuf};
7
8use crate::clang::*;
9use crate::parse::*;
10use crate::print::*;
11
12const HOST_TARGET: &'static str = include_str!(concat!(env!("OUT_DIR"), "/host-target.txt"));
13
14fn rust_to_clang_target(rust_target: &str) -> String {
17 if rust_target.starts_with("aarch64-apple-") {
18 return "arm64-apple-".to_owned() + &rust_target["aarch64-apple-".len()..];
19 }
20
21 rust_target.to_owned()
22}
23
24pub struct Generator {
26 pub(crate) include_paths: Vec<PathBuf>,
27 pub(crate) target: Option<String>,
28 pub(crate) skip_types: HashSet<String>,
29 pub(crate) skip_interface_traits: HashSet<String>,
30 pub(crate) override_typedef_types: HashMap<String, String>,
31 pub(crate) override_constant_types: HashMap<String, String>,
32 pub(crate) override_constant_values: HashMap<String, String>,
33 pub(crate) constant_parser: Option<Box<dyn Fn(&[&str]) -> Option<String>>>,
34 pub(crate) iid_generator: Option<Box<dyn Fn(&str) -> String>>,
35 pub(crate) query_interface_fn: Option<String>,
36 pub(crate) add_ref_fn: Option<String>,
37 pub(crate) release_fn: Option<String>,
38}
39
40impl Default for Generator {
41 fn default() -> Generator {
42 Generator {
43 include_paths: Vec::new(),
44 target: None,
45 skip_types: HashSet::new(),
46 skip_interface_traits: HashSet::new(),
47 override_typedef_types: HashMap::new(),
48 override_constant_types: HashMap::new(),
49 override_constant_values: HashMap::new(),
50 constant_parser: None,
51 iid_generator: None,
52 query_interface_fn: None,
53 add_ref_fn: None,
54 release_fn: None,
55 }
56 }
57}
58
59impl Generator {
60 pub fn include_path<T: AsRef<Path>>(mut self, path: T) -> Self {
62 self.include_paths.push(path.as_ref().to_path_buf());
63 self
64 }
65
66 pub fn target<T: AsRef<str>>(mut self, target: T) -> Self {
68 self.target = Some(target.as_ref().to_string());
69 self
70 }
71
72 pub fn skip_type<T: AsRef<str>>(mut self, type_: T) -> Self {
74 self.skip_types.insert(type_.as_ref().to_string());
75 self
76 }
77
78 pub fn skip_types<S: AsRef<str>, T: AsRef<[S]>>(mut self, types: T) -> Self {
80 self.skip_types
81 .extend(types.as_ref().iter().map(|s| s.as_ref().to_string()));
82 self
83 }
84
85 pub fn skip_interface_trait<T: AsRef<str>>(mut self, interface: T) -> Self {
87 self.skip_interface_traits
88 .insert(interface.as_ref().to_string());
89 self
90 }
91
92 pub fn skip_interface_traits<'a, T: AsRef<[&'a str]>>(mut self, interfaces: T) -> Self {
94 self.skip_interface_traits
95 .extend(interfaces.as_ref().iter().map(|s| s.to_string()));
96 self
97 }
98
99 pub fn override_typedef_type<T: AsRef<str>, U: AsRef<str>>(
101 mut self,
102 typedef: T,
103 type_: U,
104 ) -> Self {
105 self.override_typedef_types
106 .insert(typedef.as_ref().to_string(), type_.as_ref().to_string());
107 self
108 }
109
110 pub fn override_typedef_types<T, U, I>(mut self, typedefs: I) -> Self
113 where
114 T: AsRef<str>,
115 U: AsRef<str>,
116 I: AsRef<[(T, U)]>,
117 {
118 self.override_typedef_types.extend(
119 typedefs
120 .as_ref()
121 .into_iter()
122 .map(|(k, v)| (k.as_ref().to_string(), v.as_ref().to_string())),
123 );
124 self
125 }
126
127 pub fn override_constant_type<T: AsRef<str>, U: AsRef<str>>(
129 mut self,
130 constant: T,
131 type_: U,
132 ) -> Self {
133 self.override_constant_types
134 .insert(constant.as_ref().to_string(), type_.as_ref().to_string());
135 self
136 }
137
138 pub fn override_constant_types<T, U, I>(mut self, constants: I) -> Self
141 where
142 T: AsRef<str>,
143 U: AsRef<str>,
144 I: AsRef<[(T, U)]>,
145 {
146 self.override_constant_types.extend(
147 constants
148 .as_ref()
149 .into_iter()
150 .map(|(k, v)| (k.as_ref().to_string(), v.as_ref().to_string())),
151 );
152 self
153 }
154
155 pub fn override_constant_value<T: AsRef<str>, U: AsRef<str>>(
157 mut self,
158 constant: T,
159 value: U,
160 ) -> Self {
161 self.override_constant_values
162 .insert(constant.as_ref().to_string(), value.as_ref().to_string());
163 self
164 }
165
166 pub fn override_constant_values<T, U, I>(mut self, constants: I) -> Self
169 where
170 T: AsRef<str>,
171 U: AsRef<str>,
172 I: AsRef<[(T, U)]>,
173 {
174 self.override_constant_values.extend(
175 constants
176 .as_ref()
177 .into_iter()
178 .map(|(k, v)| (k.as_ref().to_string(), v.as_ref().to_string())),
179 );
180 self
181 }
182
183 pub fn constant_parser<F>(mut self, f: F) -> Self
189 where
190 F: Fn(&[&str]) -> Option<String> + 'static,
191 {
192 self.constant_parser = Some(Box::new(f));
193 self
194 }
195
196 pub fn iid_generator<F>(mut self, f: F) -> Self
199 where
200 F: Fn(&str) -> String + 'static,
201 {
202 self.iid_generator = Some(Box::new(f));
203 self
204 }
205
206 pub fn query_interface_fn<T: AsRef<str>>(mut self, f: T) -> Self {
212 self.query_interface_fn = Some(f.as_ref().to_string());
213 self
214 }
215
216 pub fn add_ref_fn<T: AsRef<str>>(mut self, f: T) -> Self {
222 self.add_ref_fn = Some(f.as_ref().to_string());
223 self
224 }
225
226 pub fn release_fn<T: AsRef<str>>(mut self, f: T) -> Self {
232 self.release_fn = Some(f.as_ref().to_string());
233 self
234 }
235
236 pub fn generate<T: AsRef<str>, W: Write>(
238 &self,
239 source: T,
240 sink: W,
241 ) -> Result<(), Box<dyn Error>> {
242 if !clang_sys::is_loaded() {
243 clang_sys::load()?;
244 }
245
246 let rust_target = if let Some(target) = &self.target {
247 Cow::from(target)
248 } else if let Ok(target) = env::var("TARGET") {
249 Cow::from(target)
250 } else {
251 Cow::from(HOST_TARGET)
252 };
253 let clang_target = rust_to_clang_target(&rust_target);
254
255 let unit = TranslationUnit::new(source.as_ref(), &self.include_paths, Some(&clang_target))?;
256
257 let namespace = Namespace::parse(&unit.cursor(), &self)?;
258
259 let mut printer = RustPrinter::new(sink, &self);
260 printer.print_namespace(&namespace)?;
261
262 Ok(())
263 }
264}