1#![deny(missing_docs)]
5
6mod abi;
7mod dart;
8mod js;
9mod parser;
10mod rust;
11
12use crate::abi::{
13 export, import, AbiFunction, AbiFuture, AbiIter, AbiObject, AbiStream, AbiType, FunctionType,
14 NumType, Return, Var,
15};
16use crate::dart::DartGenerator;
17use crate::js::{JsGenerator, TsGenerator, WasmMultiValueShim};
18use crate::parser::Interface;
19use crate::rust::RustGenerator;
20use anyhow::{Context, Result};
21use std::path::Path;
22use std::process::Command;
23
24pub use crate::abi::Abi;
25
26pub struct FfiGen {
28 iface: Interface,
29}
30
31impl FfiGen {
32 pub fn new<P: AsRef<Path>>(path: P) -> Result<Self> {
35 let s = std::fs::read_to_string(path)?;
36 let iface = Interface::parse(&s)?;
37 Ok(Self { iface })
38 }
39
40 pub fn generate_rust(&self, abi: Abi) -> Result<String> {
42 let rust = RustGenerator::new(abi);
43 let rust = rust.generate(self.iface.clone()).to_file_string()?;
44 Ok(rust)
45 }
46
47 pub fn wasm_multi_value_shim<P: AsRef<Path>>(&self, path: P) -> Result<()> {
49 WasmMultiValueShim::new().run(path, self.iface.clone())
50 }
51
52 pub fn generate_dart<P: AsRef<Path>>(
54 &self,
55 path: P,
56 library: &str,
57 cdylib: &str,
58 ) -> Result<()> {
59 let dart = DartGenerator::new(library.to_string(), cdylib.to_string());
60 let dart = dart.generate(self.iface.clone()).to_file_string()?;
61 std::fs::write(path.as_ref(), &dart)?;
62 let status = Command::new("dart")
63 .arg("format")
64 .arg(path.as_ref())
65 .status()
66 .context("dart not installed")?;
67 if !status.success() {
68 anyhow::bail!("dart format failed");
69 }
70 Ok(())
71 }
72
73 pub fn generate_js<P: AsRef<Path>>(&self, path: P) -> Result<()> {
75 let js = JsGenerator::default();
76 let js = js.generate(self.iface.clone()).to_file_string()?;
77 std::fs::write(path.as_ref(), &js)?;
78 let status = Command::new("prettier")
79 .arg("--write")
80 .arg(path.as_ref())
81 .status()
82 .context("prettier not installed")?;
83 if !status.success() {
84 anyhow::bail!("prettier failed");
85 }
86 Ok(())
87 }
88
89 pub fn generate_ts<P: AsRef<Path>>(&self, path: P) -> Result<()> {
91 let ts = TsGenerator::default();
92 let ts = ts.generate(self.iface.clone()).to_file_string()?;
93 std::fs::write(path.as_ref(), &ts)?;
94 let status = Command::new("prettier")
95 .arg("--write")
96 .arg(path.as_ref())
97 .status()
98 .context("prettier not installed")?;
99 if !status.success() {
100 anyhow::bail!("prettier failed");
101 }
102 Ok(())
103 }
104}
105
106#[cfg(feature = "test_runner")]
107#[doc(hidden)]
108pub mod test_runner {
109 pub use crate::dart::test_runner::compile_pass as compile_pass_dart;
110 pub use crate::js::test_runner::compile_pass as compile_pass_js;
111 pub use crate::js::test_runner::compile_pass_ts;
112 pub use crate::rust::test_runner::compile_pass as compile_pass_rust;
113
114 #[macro_export]
115 macro_rules! compile_pass {
116 ($ident:ident, $iface:expr, ($($api:tt)*), ($($rust:tt)*), ($($dart:tt)*), ($($js:tt)*), ($($ts:tt)*)) => {
117 mod $ident {
118 #[test]
119 fn rust() {
120 $crate::test_runner::compile_pass_rust($iface, genco::quote!($($api)*), genco::quote!($($rust)*)).unwrap();
121 }
122
123 #[test]
124 fn dart() {
125 $crate::test_runner::compile_pass_dart($iface, genco::quote!($($api)*), genco::quote!($($dart)*)).unwrap();
126 }
127
128 #[test]
129 fn js() {
130 $crate::test_runner::compile_pass_js($iface, genco::quote!($($api)*), genco::quote!($($js)*)).unwrap();
131 }
132
133 #[test]
134 fn ts() {
135 $crate::test_runner::compile_pass_ts($iface, genco::quote!($($ts)*)).unwrap();
136 }
137 }
138 }
139 }
140}