1#![recursion_limit = "128"]
2extern crate cbindgen;
3extern crate core;
4#[macro_use]
5extern crate error_chain;
6extern crate fs_extra;
7extern crate heck;
8extern crate ndk_build;
9extern crate ndk_tool;
10extern crate proc_macro2;
11#[macro_use]
12extern crate quote;
13#[macro_use]
14extern crate rstgen;
15extern crate serde;
16#[macro_use]
17extern crate serde_derive;
18extern crate serde_json;
19extern crate syn;
20extern crate toml;
21extern crate zip;
22
23use std::fs;
24use std::path::PathBuf;
25
26use crate::android::config::Android;
27use crate::android::process::AndroidProcess;
28use crate::ast::AstResult;
29use crate::base::process::*;
30use crate::errors::*;
31use crate::ios::config::Ios;
32use crate::ios::process::IosProcess;
33use crate::jar::config::Jar;
34use crate::jar::process::JarProcess;
35use crate::mac::config::Mac;
36use crate::mac::process::MacProcess;
37
38mod android;
39mod ast;
40mod base;
41mod bridge;
42mod cargo;
43mod config;
44mod errors;
45mod ios;
46mod jar;
47mod java;
48mod mac;
49mod swift;
50mod test;
51mod unzip;
52#[macro_use]
53mod common;
54
55const GEN_DIR_NAME: &str = "_gen";
56const HEADER_NAME: &str = "header";
57const AST_DIR: &str = "ast";
58const IOS_PROJ: &str = "ios_artifact";
59const IOS_BRIDGE_PROJ: &str = "ios_bridge";
60const MAC_PROJ: &str = "mac_artifact";
61const MAC_BRIDGE_PROJ: &str = "mac_bridge";
62const ANDROID_BRIDGE_PROJ: &str = "android_bridge";
63const ANDROID_PROJ: &str = "android_artifact";
64const JAR_BRIDGE_PROJ: &str = "jar_bridge";
65const JAR_PROJ: &str = "jar_artifact";
66
67pub struct Bind {
68 prj_path: PathBuf,
69 ios_artifact_path: PathBuf,
70 ios_bridge_path: PathBuf,
71 mac_artifact_path: PathBuf,
72 mac_bridge_path: PathBuf,
73 android_bridge_path: PathBuf,
74 android_artifact_path: PathBuf,
75 jar_bridge_path: PathBuf,
76 jar_artifact_path: PathBuf,
77 header_path: PathBuf,
78 ast_path: PathBuf,
79 target: Target,
80 action: Action,
81}
82
83pub enum Target {
84 Android,
85 Ios,
86 Mac,
87 Jar,
88 All,
89}
90
91pub enum Action {
92 GenAst,
94 GenBridge,
96 GenArtifactCode,
98 GenCHeader,
100 BuildArtifact,
102 All,
104}
105
106impl Bind {
107 pub fn from(prj_path: String, target: Target, action: Action) -> Bind {
113 let root = PathBuf::from(&prj_path);
114
115 let ast_path = root.join(GEN_DIR_NAME).join(AST_DIR);
117
118 let header_path = root.join(GEN_DIR_NAME).join(HEADER_NAME);
120
121 let ios_artifact_path = root.join(GEN_DIR_NAME).join(IOS_PROJ);
123
124 let ios_bridge_path = root.join(GEN_DIR_NAME).join(IOS_BRIDGE_PROJ);
126
127 let mac_artifact_path = root.join(GEN_DIR_NAME).join(MAC_PROJ);
129
130 let mac_bridge_path = root.join(GEN_DIR_NAME).join(MAC_BRIDGE_PROJ);
132
133 let android_bridge_path = root.join(GEN_DIR_NAME).join(ANDROID_BRIDGE_PROJ);
135
136 let android_artifact_path = root.join(GEN_DIR_NAME).join(ANDROID_PROJ);
137
138 let jar_bridge_path = root.join(GEN_DIR_NAME).join(JAR_BRIDGE_PROJ);
140
141 let jar_artifact_path = root.join(GEN_DIR_NAME).join(JAR_PROJ);
142
143 Bind {
144 prj_path: root,
145 ios_artifact_path,
146 ios_bridge_path,
147 mac_artifact_path,
148 mac_bridge_path,
149 android_bridge_path,
150 android_artifact_path,
151 jar_bridge_path,
152 jar_artifact_path,
153 header_path,
154 ast_path,
155 target,
156 action,
157 }
158 }
159
160 pub fn gen_all(&self) -> Result<()> {
164 let config = config::parse(&self.prj_path);
165 println!("rsbind config in {:?} is {:?}", &self.prj_path, config);
166
167 let crate_name = self.parse_crate_name()?;
168
169 if let Action::GenAst = self.action {
170 self.parse_ast(crate_name)?;
171 return Ok(());
172 }
173
174 let ast = &self.get_ast_if_need(crate_name.clone())?;
175 match self.target {
176 Target::Ios => {
177 self.gen_for_ios(&crate_name, ast, config)?;
178 }
179 Target::Android => {
180 self.gen_for_android(&crate_name, ast, config)?;
181 }
182 Target::Mac => {
183 self.gen_for_mac(&crate_name, ast, config)?;
184 }
185 Target::Jar => {
186 self.gen_for_jar(&crate_name, ast, config)?;
187 }
188 Target::All => {
189 self.gen_for_ios(&crate_name, ast, config.clone())?;
190 self.gen_for_android(&crate_name, ast, config.clone())?;
191 self.gen_for_mac(&crate_name, ast, config.clone())?;
192 self.gen_for_jar(&crate_name, ast, config)?;
193 }
194 };
195 Ok(())
196 }
197
198 fn get_ast_if_need(&self, crate_name: String) -> Result<AstResult> {
199 match self.action {
200 Action::GenBridge | Action::GenArtifactCode | Action::All => self.parse_ast(crate_name),
201 _ => {
202 use std::collections::HashMap;
203 let ast_result = AstResult {
204 traits: HashMap::new(),
205 structs: HashMap::new(),
206 imps: vec![],
207 };
208 Ok(ast_result)
209 }
210 }
211 }
212
213 fn parse_ast(&self, crate_name: String) -> Result<AstResult> {
214 let prj_path = PathBuf::from(&self.prj_path);
215 if self.ast_path.exists() {
216 fs::remove_dir_all(&self.ast_path)?;
217 }
218 fs::create_dir_all(&self.ast_path)?;
219 ast::AstHandler::new(crate_name)
220 .parse(&prj_path)?
221 .flush(&self.ast_path)
222 }
223
224 fn gen_for_jar(
227 &self,
228 crate_name: &str,
229 ast_result: &AstResult,
230 config: Option<config::Config>,
231 ) -> Result<()> {
232 let jar = match config {
233 Some(ref config) => config.jar.clone(),
234 None => Some(Jar::default()),
235 };
236
237 let jar_process = JarProcess::new(
238 &self.prj_path,
239 &self.jar_artifact_path,
240 &self.jar_bridge_path,
241 crate_name,
242 ast_result,
243 jar,
244 );
245
246 match self.action {
247 Action::GenAst => (),
248 Action::GenBridge => jar_process.gen_bridge_src()?,
249 Action::GenArtifactCode => jar_process.gen_artifact_code()?,
250 Action::GenCHeader => {}
251 Action::BuildArtifact => {
252 jar_process.build_bridge_prj()?;
253 jar_process.copy_bridge_outputs()?;
254 jar_process.build_artifact_prj()?;
255 }
256 Action::All => {
257 jar_process.gen_bridge_src()?;
258 jar_process.gen_artifact_code()?;
259 jar_process.build_bridge_prj()?;
260 jar_process.copy_bridge_outputs()?;
261 jar_process.build_artifact_prj()?;
262 }
263 }
264
265 Ok(())
266 }
267
268 fn gen_for_mac(
271 &self,
272 crate_name: &str,
273 ast_result: &AstResult,
274 config: Option<config::Config>,
275 ) -> Result<()> {
276 let mac = match config {
277 Some(ref config) => config.mac.clone(),
278 None => Some(Mac::default()),
279 };
280
281 let mac_process = MacProcess::new(
282 &self.prj_path,
283 &self.mac_artifact_path,
284 &self.mac_bridge_path,
285 &self.header_path,
286 crate_name,
287 ast_result,
288 mac,
289 );
290
291 match self.action {
292 Action::GenAst => (),
293 Action::GenBridge => mac_process.gen_bridge_src()?,
294 Action::GenArtifactCode => mac_process.gen_artifact_code()?,
295 Action::GenCHeader => mac_process.gen_c_header()?,
296 Action::BuildArtifact => {
297 mac_process.build_bridge_prj()?;
298 mac_process.copy_bridge_outputs()?;
299 }
302 Action::All => {
303 mac_process.gen_bridge_src()?;
304 mac_process.gen_artifact_code()?;
305 mac_process.build_bridge_prj()?;
306 mac_process.copy_bridge_outputs()?;
307 }
310 }
311
312 Ok(())
313 }
314
315 fn gen_for_ios(
318 &self,
319 crate_name: &str,
320 ast_result: &AstResult,
321 config: Option<config::Config>,
322 ) -> Result<()> {
323 let ios = match config {
324 Some(ref config) => config.ios.clone(),
325 None => Some(Ios::default()),
326 };
327
328 let ios_process = IosProcess::new(
329 &self.prj_path,
330 &self.ios_artifact_path,
331 &self.ios_bridge_path,
332 &self.header_path,
333 crate_name,
334 ast_result,
335 ios,
336 );
337
338 match self.action {
339 Action::GenAst => (),
340 Action::GenBridge => ios_process.gen_bridge_src()?,
341 Action::GenArtifactCode => ios_process.gen_artifact_code()?,
342 Action::GenCHeader => ios_process.gen_c_header()?,
343 Action::BuildArtifact => {
344 ios_process.build_bridge_prj()?;
345 ios_process.copy_bridge_outputs()?;
346 }
349 Action::All => {
350 ios_process.gen_bridge_src()?;
351 ios_process.gen_artifact_code()?;
352 ios_process.build_bridge_prj()?;
353 ios_process.copy_bridge_outputs()?;
354 }
357 }
358
359 Ok(())
360 }
361
362 fn gen_for_android(
366 &self,
367 crate_name: &str,
368 ast_result: &AstResult,
369 config: Option<config::Config>,
370 ) -> Result<()> {
371 let android = match config {
372 Some(ref config) => config.android.clone(),
373 None => Some(Android::default()),
374 };
375
376 let android_process = AndroidProcess::new(
377 &self.prj_path,
378 &self.android_artifact_path,
379 &self.android_bridge_path,
380 crate_name,
381 ast_result,
382 android,
383 );
384
385 match self.action {
386 Action::GenAst => (),
387 Action::GenBridge => android_process.gen_bridge_src()?,
388 Action::GenArtifactCode => android_process.gen_artifact_code()?,
389 Action::GenCHeader => (),
390 Action::BuildArtifact => {
391 android_process.build_bridge_prj()?;
392 android_process.copy_bridge_outputs()?;
393 android_process.build_artifact_prj()?;
394 }
395 Action::All => {
396 android_process.gen_bridge_src()?;
397 android_process.gen_artifact_code()?;
398 android_process.build_bridge_prj()?;
399 android_process.copy_bridge_outputs()?;
400 android_process.build_artifact_prj()?;
401 }
402 };
403
404 Ok(())
405 }
406
407 fn parse_crate_name(&self) -> Result<String> {
411 let toml_path = PathBuf::from(&self.prj_path).join("Cargo.toml");
412 let manifest = cargo::manifest(toml_path.as_path())?;
413 println!("parse project name = {}", manifest.package.name);
414 Ok(manifest.package.name)
415 }
416}