use indoc::indoc;
use log::info;
use once_cell::sync::OnceCell;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use quote::ToTokens;
use quote::TokenStreamExt;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::panic::RefUnwindSafe;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use syn::{Item, Token};
use tempfile::{tempdir, TempDir};
use test_env_log::test;
const KEEP_TEMPDIRS: bool = false;
fn get_builder() -> &'static Mutex<LinkableTryBuilder> {
static INSTANCE: OnceCell<Mutex<LinkableTryBuilder>> = OnceCell::new();
INSTANCE.get_or_init(|| Mutex::new(LinkableTryBuilder::new()))
}
struct LinkableTryBuilder {
temp_dir: TempDir,
}
impl LinkableTryBuilder {
fn new() -> Self {
LinkableTryBuilder {
temp_dir: tempdir().unwrap(),
}
}
fn move_items_into_temp_dir<P1: AsRef<Path>>(&self, src_path: &P1, pattern: &str) {
for item in std::fs::read_dir(src_path).unwrap() {
let item = item.unwrap();
if item.file_name().into_string().unwrap().contains(pattern) {
let dest = self.temp_dir.path().join(item.file_name());
if dest.exists() {
std::fs::remove_file(&dest).unwrap();
}
std::fs::rename(item.path(), dest).unwrap();
}
}
}
fn build<P1: AsRef<Path>, P2: AsRef<Path>, P3: AsRef<Path> + RefUnwindSafe>(
&self,
library_path: &P1,
library_name: &str,
header_path: &P2,
header_names: &[&str],
rs_path: &P3,
generated_rs_files: Vec<PathBuf>,
) -> std::thread::Result<()> {
self.move_items_into_temp_dir(library_path, library_name);
for header_name in header_names {
self.move_items_into_temp_dir(header_path, header_name);
}
for generated_rs in generated_rs_files {
self.move_items_into_temp_dir(
&generated_rs.parent().unwrap().to_path_buf(),
&generated_rs.file_name().unwrap().to_str().unwrap(),
);
}
let temp_path = self.temp_dir.path().to_str().unwrap();
std::env::set_var("RUSTFLAGS", format!("-L {}", temp_path));
std::env::set_var("AUTOCXX_RS", temp_path);
std::panic::catch_unwind(|| {
let test_cases = trybuild::TestCases::new();
test_cases.pass(rs_path)
})
}
}
fn write_to_file(tdir: &TempDir, filename: &str, content: &str) -> PathBuf {
let path = tdir.path().join(filename);
let mut f = File::create(&path).unwrap();
f.write_all(content.as_bytes()).unwrap();
path
}
fn run_test(
cxx_code: &str,
header_code: &str,
rust_code: TokenStream,
generate: &[&str],
generate_pods: &[&str],
) {
do_run_test(
cxx_code,
header_code,
rust_code,
generate,
generate_pods,
None,
&[],
None,
)
.unwrap()
}
type RustCodeChecker = Box<dyn FnOnce(syn::File) -> Result<(), TestError>>;
#[allow(clippy::too_many_arguments)] fn run_test_ex(
cxx_code: &str,
header_code: &str,
rust_code: TokenStream,
generate: &[&str],
generate_pods: &[&str],
extra_directives: Option<TokenStream>,
extra_clang_args: &[&str],
rust_code_checker: Option<RustCodeChecker>,
) {
do_run_test(
cxx_code,
header_code,
rust_code,
generate,
generate_pods,
extra_directives,
extra_clang_args,
rust_code_checker,
)
.unwrap()
}
fn run_test_expect_fail(
cxx_code: &str,
header_code: &str,
rust_code: TokenStream,
generate: &[&str],
generate_pods: &[&str],
) {
do_run_test(
cxx_code,
header_code,
rust_code,
generate,
generate_pods,
None,
&[],
None,
)
.expect_err("Unexpected success");
}
#[derive(Debug)]
enum TestError {
AutoCxx(crate::BuilderError),
CppBuild(cc::Error),
RsBuild,
NoRs,
RsFileOpen(std::io::Error),
RsFileRead(std::io::Error),
RsFileParse(syn::Error),
RsCodeExaminationFail,
}
#[allow(clippy::too_many_arguments)] fn do_run_test(
cxx_code: &str,
header_code: &str,
rust_code: TokenStream,
generate: &[&str],
generate_pods: &[&str],
extra_directives: Option<TokenStream>,
extra_clang_args: &[&str],
rust_code_checker: Option<RustCodeChecker>,
) -> Result<(), TestError> {
let generate = generate.iter().map(|s| {
quote! {
generate!(#s)
}
});
let generate_pods = generate_pods.iter().map(|s| {
quote! {
generate_pod!(#s)
}
});
let hexathorpe = Token);
let unexpanded_rust = |hdr: &str| {
quote! {
use autocxx::include_cpp;
include_cpp!(
#hexathorpe include #hdr
safety!(unsafe_ffi)
#(#generate)*
#(#generate_pods)*
#extra_directives
);
fn main() {
#rust_code
}
}
};
do_run_test_manual(
cxx_code,
header_code,
unexpanded_rust,
extra_clang_args,
rust_code_checker,
)
}
fn do_run_test_manual<F>(
cxx_code: &str,
header_code: &str,
rust_code_generator: F,
extra_clang_args: &[&str],
rust_code_checker: Option<RustCodeChecker>,
) -> Result<(), TestError>
where
F: FnOnce(&'static str) -> TokenStream,
{
const HEADER_NAME: &str = "input.h";
let mut rust_code = rust_code_generator(HEADER_NAME);
let tdir = tempdir().unwrap();
write_to_file(
&tdir,
HEADER_NAME,
&format!("#pragma once\n{}", header_code),
);
write_to_file(&tdir, "cxx.h", crate::HEADER);
rust_code.append_all(quote! {
#[link(name="autocxx-demo")]
extern {}
});
info!("Unexpanded Rust: {}", rust_code);
let write_rust_to_file = |ts: &TokenStream| -> PathBuf {
let rs_code = format!("{}", ts);
write_to_file(&tdir, "input.rs", &rs_code)
};
let target_dir = tdir.path().join("target");
std::fs::create_dir(&target_dir).unwrap();
let rs_path = write_rust_to_file(&rust_code);
info!("Path is {:?}", tdir.path());
let build_results = crate::builder::build_to_custom_directory(
&rs_path,
&[tdir.path()],
&extra_clang_args,
Some(target_dir.clone()),
None,
)
.map_err(TestError::AutoCxx)?;
let mut b = build_results.0;
let generated_rs_files = build_results.1;
if let Some(rust_code_checker) = rust_code_checker {
let mut file = File::open(generated_rs_files.get(0).ok_or(TestError::NoRs)?)
.map_err(TestError::RsFileOpen)?;
let mut content = String::new();
file.read_to_string(&mut content)
.map_err(TestError::RsFileRead)?;
let ast = syn::parse_file(&content).map_err(TestError::RsFileParse)?;
rust_code_checker(ast)?;
}
let target = rust_info::get().target_triple.unwrap();
if !cxx_code.is_empty() {
let cxx_code = format!("#include \"{}\"\n{}", "input.h", cxx_code);
let cxx_path = write_to_file(&tdir, "input.cxx", &cxx_code);
b.file(cxx_path);
}
let mut b = b
.out_dir(&target_dir)
.host(&target)
.target(&target)
.opt_level(1)
.flag("-std=c++14");
for f in extra_clang_args {
b = b.flag(f);
}
b.include(tdir.path())
.try_compile("autocxx-demo")
.map_err(TestError::CppBuild)?;
let r = get_builder().lock().unwrap().build(
&target_dir,
"autocxx-demo",
&tdir.path(),
&["input.h", "cxx.h"],
&rs_path,
generated_rs_files,
);
if r.is_err() {
return Err(TestError::RsBuild); }
if KEEP_TEMPDIRS {
println!("Tempdir: {:?}", tdir.into_path().to_str());
}
Ok(())
}
#[test]
fn test_return_void() {
let cxx = indoc! {"
void do_nothing() {
}
"};
let hdr = indoc! {"
void do_nothing();
"};
let rs = quote! {
ffi::do_nothing();
};
run_test(cxx, hdr, rs, &["do_nothing"], &[]);
}
#[test]
fn test_two_funcs() {
let cxx = indoc! {"
void do_nothing1() {
}
void do_nothing2() {
}
"};
let hdr = indoc! {"
void do_nothing1();
void do_nothing2();
"};
let rs = quote! {
ffi::do_nothing1();
ffi::do_nothing2();
};
run_test(cxx, hdr, rs, &["do_nothing1", "do_nothing2"], &[]);
}
#[test]
fn test_two_funcs_with_definition() {
let cxx = indoc! {"
void do_nothing1() {
}
void do_nothing2() {
}
"};
let hdr = indoc! {"
struct Bob {
int a;
};
void do_nothing1();
void do_nothing2();
"};
let rs = quote! {
ffi::do_nothing1();
ffi::do_nothing2();
};
println!("Here");
info!("Here2");
run_test(cxx, hdr, rs, &["do_nothing1", "do_nothing2"], &[]);
}
#[test]
fn test_return_i32() {
let cxx = indoc! {"
uint32_t give_int() {
return 5;
}
"};
let hdr = indoc! {"
#include <cstdint>
uint32_t give_int();
"};
let rs = quote! {
assert_eq!(ffi::give_int(), 5);
};
run_test(cxx, hdr, rs, &["give_int"], &[]);
}
#[test]
fn test_take_i32() {
let cxx = indoc! {"
uint32_t take_int(uint32_t a) {
return a + 3;
}
"};
let hdr = indoc! {"
#include <cstdint>
uint32_t take_int(uint32_t a);
"};
let rs = quote! {
assert_eq!(ffi::take_int(3), 6);
};
run_test(cxx, hdr, rs, &["take_int"], &[]);
}
#[test]
#[ignore] fn test_give_up_int() {
let cxx = indoc! {"
std::unique_ptr<uint32_t> give_up() {
return std::make_unique<uint32_t>(12);
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
std::unique_ptr<uint32_t> give_up();
"};
let rs = quote! {
assert_eq!(ffi::give_up().as_ref().unwrap(), 12);
};
run_test(cxx, hdr, rs, &["give_up"], &[]);
}
#[test]
#[ignore] fn test_give_up_ctype() {
let cxx = indoc! {"
std::unique_ptr<int> give_up() {
return std::make_unique<int>(12);
}
"};
let hdr = indoc! {"
#include <memory>
std::unique_ptr<int> give_up();
"};
let rs = quote! {
assert_eq!(ffi::give_up().as_ref().unwrap(), autocxx::c_int(12));
};
run_test(cxx, hdr, rs, &["give_up"], &[]);
}
#[test]
fn test_give_string_up() {
let cxx = indoc! {"
std::unique_ptr<std::string> give_str_up() {
return std::make_unique<std::string>(\"Bob\");
}
"};
let hdr = indoc! {"
#include <memory>
#include <string>
std::unique_ptr<std::string> give_str_up();
"};
let rs = quote! {
assert_eq!(ffi::give_str_up().as_ref().unwrap().to_str().unwrap(), "Bob");
};
run_test(cxx, hdr, rs, &["give_str_up"], &[]);
}
#[test]
fn test_give_string_plain() {
let cxx = indoc! {"
std::string give_str() {
return std::string(\"Bob\");
}
"};
let hdr = indoc! {"
#include <string>
std::string give_str();
"};
let rs = quote! {
assert_eq!(ffi::give_str().as_ref().unwrap(), "Bob");
};
run_test(cxx, hdr, rs, &["give_str"], &[]);
}
#[test]
fn test_cycle_string_up() {
let cxx = indoc! {"
std::unique_ptr<std::string> give_str_up() {
return std::make_unique<std::string>(\"Bob\");
}
uint32_t take_str_up(std::unique_ptr<std::string> a) {
return a->length();
}
"};
let hdr = indoc! {"
#include <memory>
#include <string>
#include <cstdint>
std::unique_ptr<std::string> give_str_up();
uint32_t take_str_up(std::unique_ptr<std::string> a);
"};
let rs = quote! {
let s = ffi::give_str_up();
assert_eq!(ffi::take_str_up(s), 3);
};
run_test(cxx, hdr, rs, &["give_str_up", "take_str_up"], &[]);
}
#[test]
fn test_cycle_string() {
let cxx = indoc! {"
std::string give_str() {
return std::string(\"Bob\");
}
uint32_t take_str(std::string a) {
return a.length();
}
"};
let hdr = indoc! {"
#include <string>
#include <cstdint>
std::string give_str();
uint32_t take_str(std::string a);
"};
let rs = quote! {
let s = ffi::give_str();
assert_eq!(ffi::take_str(s), 3);
};
let generate = &["give_str", "take_str"];
run_test(cxx, hdr, rs, generate, &[]);
}
#[test]
fn test_cycle_string_by_ref() {
let cxx = indoc! {"
std::unique_ptr<std::string> give_str() {
return std::make_unique<std::string>(\"Bob\");
}
uint32_t take_str(const std::string& a) {
return a.length();
}
"};
let hdr = indoc! {"
#include <string>
#include <memory>
#include <cstdint>
std::unique_ptr<std::string> give_str();
uint32_t take_str(const std::string& a);
"};
let rs = quote! {
let s = ffi::give_str();
assert_eq!(ffi::take_str(s.as_ref().unwrap()), 3);
};
let generate = &["give_str", "take_str"];
run_test(cxx, hdr, rs, generate, &[]);
}
#[test]
fn test_cycle_string_by_mut_ref() {
let cxx = indoc! {"
std::unique_ptr<std::string> give_str() {
return std::make_unique<std::string>(\"Bob\");
}
uint32_t take_str(std::string& a) {
return a.length();
}
"};
let hdr = indoc! {"
#include <string>
#include <memory>
#include <cstdint>
std::unique_ptr<std::string> give_str();
uint32_t take_str(std::string& a);
"};
let rs = quote! {
let mut s = ffi::give_str();
assert_eq!(ffi::take_str(s.as_mut().unwrap()), 3);
};
let generate = &["give_str", "take_str"];
run_test(cxx, hdr, rs, generate, &[]);
}
#[test]
fn test_give_pod_by_value() {
let cxx = indoc! {"
Bob give_bob() {
Bob a;
a.a = 3;
a.b = 4;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
uint32_t b;
};
Bob give_bob();
"};
let rs = quote! {
assert_eq!(ffi::give_bob().b, 4);
};
run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
}
#[test]
fn test_give_pod_class_by_value() {
let cxx = indoc! {"
Bob give_bob() {
Bob a;
a.a = 3;
a.b = 4;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
class Bob {
public:
uint32_t a;
uint32_t b;
};
Bob give_bob();
"};
let rs = quote! {
assert_eq!(ffi::give_bob().b, 4);
};
run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
}
#[test]
fn test_give_pod_by_up() {
let cxx = indoc! {"
std::unique_ptr<Bob> give_bob() {
auto a = std::make_unique<Bob>();
a->a = 3;
a->b = 4;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
uint32_t b;
};
std::unique_ptr<Bob> give_bob();
"};
let rs = quote! {
assert_eq!(ffi::give_bob().as_ref().unwrap().b, 4);
};
run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
}
#[test]
fn test_take_pod_by_value() {
let cxx = indoc! {"
uint32_t take_bob(Bob a) {
return a.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
uint32_t b;
};
uint32_t take_bob(Bob a);
"};
let rs = quote! {
let a = ffi::Bob { a: 12, b: 13 };
assert_eq!(ffi::take_bob(a), 12);
};
run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
}
#[test]
fn test_take_pod_by_ref() {
let cxx = indoc! {"
uint32_t take_bob(const Bob& a) {
return a.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
uint32_t b;
};
uint32_t take_bob(const Bob& a);
"};
let rs = quote! {
let a = ffi::Bob { a: 12, b: 13 };
assert_eq!(ffi::take_bob(&a), 12);
};
run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
}
#[test]
fn test_take_pod_by_ref_and_ptr() {
let cxx = indoc! {"
uint32_t take_bob_ref(const Bob& a) {
return a.a;
}
uint32_t take_bob_ptr(const Bob* a) {
return a->a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
uint32_t b;
};
uint32_t take_bob_ref(const Bob& a);
uint32_t take_bob_ptr(const Bob* a);
"};
let rs = quote! {
let a = ffi::Bob { a: 12, b: 13 };
assert_eq!(ffi::take_bob_ref(&a), 12);
};
run_test(cxx, hdr, rs, &["take_bob_ref", "take_bob_ptr"], &["Bob"]);
}
#[test]
fn test_return_pod_by_ref_and_ptr() {
let hdr = indoc! {"
#include <cstdint>
struct B {
uint32_t a;
};
struct A {
B b;
};
inline const B& return_b_ref(const A& a) {
return a.b;
}
inline const B* return_b_ptr(const A& a) {
return &a.b;
}
"};
let rs = quote! {
let a = ffi::A { b: ffi::B { a: 3 } };
assert_eq!(ffi::return_b_ref(&a).a, 3);
let b_ptr = ffi::return_b_ptr(&a);
assert_eq!(unsafe { b_ptr.as_ref() }.unwrap().a, 3);
};
run_test("", hdr, rs, &["return_b_ref", "return_b_ptr"], &["A", "B"]);
}
#[test]
fn test_take_pod_by_mut_ref() {
let cxx = indoc! {"
uint32_t take_bob(Bob& a) {
a.b = 14;
return a.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
uint32_t b;
};
uint32_t take_bob(Bob& a);
"};
let rs = quote! {
let mut a = Box::pin(ffi::Bob { a: 12, b: 13 });
assert_eq!(ffi::take_bob(a.as_mut()), 12);
assert_eq!(a.b, 14);
};
run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
}
#[test]
fn test_take_nested_pod_by_value() {
let cxx = indoc! {"
uint32_t take_bob(Bob a) {
return a.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Phil {
uint32_t d;
};
struct Bob {
uint32_t a;
uint32_t b;
Phil c;
};
uint32_t take_bob(Bob a);
"};
let rs = quote! {
let a = ffi::Bob { a: 12, b: 13, c: ffi::Phil { d: 4 } };
assert_eq!(ffi::take_bob(a), 12);
};
run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
}
#[test]
fn test_take_nonpod_by_value() {
let cxx = indoc! {"
Bob::Bob(uint32_t a0, uint32_t b0)
: a(a0), b(b0) {}
uint32_t take_bob(Bob a) {
return a.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct Bob {
Bob(uint32_t a, uint32_t b);
uint32_t a;
uint32_t b;
std::string reason_why_this_is_nonpod;
};
uint32_t take_bob(Bob a);
"};
let rs = quote! {
let a = ffi::Bob::make_unique(12, 13);
assert_eq!(ffi::take_bob(a), 12);
};
run_test(cxx, hdr, rs, &["take_bob", "Bob"], &[]);
}
#[test]
fn test_take_nonpod_by_ref() {
let cxx = indoc! {"
uint32_t take_bob(const Bob& a) {
return a.a;
}
std::unique_ptr<Bob> make_bob(uint32_t a) {
auto b = std::make_unique<Bob>();
b->a = a;
return b;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
std::unique_ptr<Bob> make_bob(uint32_t a);
uint32_t take_bob(const Bob& a);
"};
let rs = quote! {
let a = ffi::make_bob(12);
assert_eq!(ffi::take_bob(&a), 12);
};
run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
}
#[test]
fn test_take_nonpod_by_ptr_simple() {
let cxx = indoc! {"
uint32_t take_bob(const Bob* a) {
return a->a;
}
std::unique_ptr<Bob> make_bob(uint32_t a) {
auto b = std::make_unique<Bob>();
b->a = a;
return b;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
std::unique_ptr<Bob> make_bob(uint32_t a);
uint32_t take_bob(const Bob* a);
"};
let rs = quote! {
let a = ffi::make_bob(12);
let a_ptr = a.into_raw();
assert_eq!(unsafe { ffi::take_bob(a_ptr) }, 12);
unsafe { cxx::UniquePtr::from_raw(a_ptr) }; };
run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
}
#[test]
fn test_take_nonpod_by_ptr_in_method() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
#include <cstdint>
class A {
public:
A() {};
uint32_t take_bob(const Bob* a) const {
return a->a;
}
std::unique_ptr<Bob> make_bob(uint32_t a) const {
auto b = std::make_unique<Bob>();
b->a = a;
return b;
}
uint16_t a;
};
"};
let rs = quote! {
let a = ffi::A::make_unique();
let b = a.as_ref().unwrap().make_bob(12);
let b_ptr = b.into_raw();
assert_eq!(unsafe { a.as_ref().unwrap().take_bob(b_ptr) }, 12);
unsafe { cxx::UniquePtr::from_raw(b_ptr) }; };
run_test("", hdr, rs, &["A", "Bob"], &[]);
}
#[test]
fn test_take_nonpod_by_ptr_in_wrapped_method() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct C {
C() {}
uint32_t a;
};
struct Bob {
uint32_t a;
};
class A {
public:
A() {};
uint32_t take_bob(const Bob* a, C) const {
return a->a;
}
std::unique_ptr<Bob> make_bob(uint32_t a) const {
auto b = std::make_unique<Bob>();
b->a = a;
return b;
}
uint16_t a;
};
"};
let rs = quote! {
let a = ffi::A::make_unique();
let c = ffi::C::make_unique();
let b = a.as_ref().unwrap().make_bob(12);
let b_ptr = b.into_raw();
assert_eq!(unsafe { a.as_ref().unwrap().take_bob(b_ptr, c) }, 12);
unsafe { cxx::UniquePtr::from_raw(b_ptr) }; };
run_test("", hdr, rs, &["A", "Bob", "C"], &[]);
}
#[test]
fn test_take_char_by_ptr_in_wrapped_method() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct C {
C() { test = \"hi\"; }
uint32_t a;
const char* test;
};
class A {
public:
A() {};
uint32_t take_char(const char* a, C) const {
return a[0];
}
const char* make_char(C extra) const {
return extra.test;
}
uint16_t a;
};
"};
let rs = quote! {
let a = ffi::A::make_unique();
let c1 = ffi::C::make_unique();
let c2 = ffi::C::make_unique();
let ch = a.as_ref().unwrap().make_char(c1);
assert_eq!(unsafe { ch.as_ref()}.unwrap(), &104i8);
assert_eq!(unsafe { a.as_ref().unwrap().take_char(ch, c2) }, 104);
};
run_test("", hdr, rs, &["A", "C"], &[]);
}
#[test]
fn test_take_nonpod_by_mut_ref() {
let cxx = indoc! {"
uint32_t take_bob(Bob& a) {
return a.a;
}
std::unique_ptr<Bob> make_bob(uint32_t a) {
auto b = std::make_unique<Bob>();
b->a = a;
return b;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
std::unique_ptr<Bob> make_bob(uint32_t a);
uint32_t take_bob(Bob& a);
"};
let rs = quote! {
let mut a = ffi::make_bob(12);
assert_eq!(ffi::take_bob(a.pin_mut()), 12);
};
run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
}
#[test]
fn test_return_nonpod_by_value() {
let cxx = indoc! {"
Bob::Bob(uint32_t a0, uint32_t b0)
: a(a0), b(b0) {}
Bob give_bob(uint32_t a) {
Bob c(a, 44);
return c;
}
uint32_t take_bob(std::unique_ptr<Bob> a) {
return a->a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
Bob(uint32_t a, uint32_t b);
uint32_t a;
uint32_t b;
};
Bob give_bob(uint32_t a);
uint32_t take_bob(std::unique_ptr<Bob> a);
"};
let rs = quote! {
let a = ffi::give_bob(13);
assert_eq!(ffi::take_bob(a), 13);
};
run_test(cxx, hdr, rs, &["take_bob", "give_bob", "Bob"], &[]);
}
#[test]
fn test_get_str_by_up() {
let cxx = indoc! {"
std::unique_ptr<std::string> get_str() {
return std::make_unique<std::string>(\"hello\");
}
"};
let hdr = indoc! {"
#include <string>
#include <memory>
std::unique_ptr<std::string> get_str();
"};
let rs = quote! {
assert_eq!(ffi::get_str().as_ref().unwrap(), "hello");
};
run_test(cxx, hdr, rs, &["get_str"], &[]);
}
#[test]
fn test_get_str_by_value() {
let cxx = indoc! {"
std::string get_str() {
return \"hello\";
}
"};
let hdr = indoc! {"
#include <string>
std::string get_str();
"};
let rs = quote! {
assert_eq!(ffi::get_str().as_ref().unwrap(), "hello");
};
run_test(cxx, hdr, rs, &["get_str"], &[]);
}
#[test]
fn test_cycle_nonpod_with_str_by_ref() {
let cxx = indoc! {"
uint32_t take_bob(const Bob& a) {
return a.a;
}
std::unique_ptr<Bob> make_bob() {
auto a = std::make_unique<Bob>();
a->a = 32;
a->b = \"hello\";
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
#include <memory>
struct Bob {
uint32_t a;
std::string b;
};
uint32_t take_bob(const Bob& a);
std::unique_ptr<Bob> make_bob();
"};
let rs = quote! {
let a = ffi::make_bob();
assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 32);
};
run_test(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
}
#[test]
fn test_make_up() {
let cxx = indoc! {"
Bob::Bob() : a(3) {
}
uint32_t take_bob(const Bob& a) {
return a.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
class Bob {
public:
Bob();
uint32_t a;
};
uint32_t take_bob(const Bob& a);
"};
let rs = quote! {
let a = ffi::Bob::make_unique(); assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 3);
};
run_test(cxx, hdr, rs, &["Bob", "take_bob"], &[]);
}
#[test]
fn test_make_up_with_args() {
let cxx = indoc! {"
Bob::Bob(uint32_t a0, uint32_t b0)
: a(a0), b(b0) {}
uint32_t take_bob(const Bob& a) {
return a.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
Bob(uint32_t a, uint32_t b);
uint32_t a;
uint32_t b;
};
uint32_t take_bob(const Bob& a);
"};
let rs = quote! {
let a = ffi::Bob::make_unique(12, 13);
assert_eq!(ffi::take_bob(a.as_ref().unwrap()), 12);
};
run_test(cxx, hdr, rs, &["take_bob", "Bob"], &[]);
}
#[test]
#[ignore] fn test_make_up_int() {
let cxx = indoc! {"
Bob::Bob(uint32_t a) : b(a) {
}
"};
let hdr = indoc! {"
#include <cstdint>
class Bob {
public:
Bob(uint32_t a);
uint32_t b;
};
"};
let rs = quote! {
let a = ffi::Bob::make_unique(3);
assert_eq!(a.as_ref().unwrap().b, 3);
};
run_test(cxx, hdr, rs, &["Bob"], &[]);
}
#[test]
fn test_enum_with_funcs() {
let cxx = indoc! {"
Bob give_bob() {
return Bob::BOB_VALUE_2;
}
"};
let hdr = indoc! {"
#include <cstdint>
enum Bob {
BOB_VALUE_1,
BOB_VALUE_2,
};
Bob give_bob();
"};
let rs = quote! {
let a = ffi::Bob::BOB_VALUE_2;
let b = ffi::give_bob();
assert!(a == b);
};
run_test(cxx, hdr, rs, &["Bob", "give_bob"], &[]);
}
#[test]
fn test_enum_no_funcs() {
let cxx = indoc! {"
"};
let hdr = indoc! {"
enum Bob {
BOB_VALUE_1,
BOB_VALUE_2,
};
"};
let rs = quote! {
let a = ffi::Bob::BOB_VALUE_1;
let b = ffi::Bob::BOB_VALUE_2;
assert!(a != b);
};
run_test(cxx, hdr, rs, &["Bob"], &[]);
}
#[test] fn test_take_pod_class_by_value() {
let cxx = indoc! {"
uint32_t take_bob(Bob a) {
return a.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
class Bob {
public:
uint32_t a;
uint32_t b;
};
uint32_t take_bob(Bob a);
"};
let rs = quote! {
let a = ffi::Bob { a: 12, b: 13 };
assert_eq!(ffi::take_bob(a), 12);
};
run_test(cxx, hdr, rs, &["take_bob"], &["Bob"]);
}
#[test]
fn test_pod_method() {
let cxx = indoc! {"
uint32_t Bob::get_bob() const {
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob() const;
};
"};
let rs = quote! {
let a = ffi::Bob { a: 12, b: 13 };
assert_eq!(a.get_bob(), 12);
};
run_test(cxx, hdr, rs, &[], &["Bob"]);
}
#[test]
fn test_pod_mut_method() {
let cxx = indoc! {"
uint32_t Bob::get_bob() {
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob();
};
"};
let rs = quote! {
let mut a = Box::pin(ffi::Bob { a: 12, b: 13 });
assert_eq!(a.as_mut().get_bob(), 12);
};
run_test(cxx, hdr, rs, &[], &["Bob"]);
}
#[test]
fn test_define_int() {
let cxx = indoc! {"
"};
let hdr = indoc! {"
#define BOB 3
"};
let rs = quote! {
assert_eq!(ffi::BOB, 3);
};
run_test(cxx, hdr, rs, &["BOB"], &[]);
}
#[test]
fn test_define_str() {
let cxx = indoc! {"
"};
let hdr = indoc! {"
#define BOB \"foo\"
"};
let rs = quote! {
assert_eq!(std::str::from_utf8(ffi::BOB).unwrap().trim_end_matches(char::from(0)), "foo");
};
run_test(cxx, hdr, rs, &["BOB"], &[]);
}
#[test]
fn test_i32_const() {
let cxx = indoc! {"
"};
let hdr = indoc! {"
#include <cstdint>
const uint32_t BOB = 3;
"};
let rs = quote! {
assert_eq!(ffi::BOB, 3);
};
run_test(cxx, hdr, rs, &["BOB"], &[]);
}
#[test]
fn test_negative_rs_nonsense() {
let cxx = indoc! {"
"};
let hdr = indoc! {"
#include <cstdint>
const uint32_t BOB = 3;
"};
let rs = quote! {
foo bar
};
run_test_expect_fail(cxx, hdr, rs, &["BOB"], &[]);
}
#[test]
fn test_negative_cpp_nonsense() {
let cxx = indoc! {"
"};
let hdr = indoc! {"
#include <cstdint>
const uint32_t BOB = CAT;
"};
let rs = quote! {
assert_eq!(ffi::BOB, 3);
};
run_test_expect_fail(cxx, hdr, rs, &["BOB"], &[]);
}
#[test]
fn test_negative_make_nonpod() {
let cxx = indoc! {"
uint32_t take_bob(const Bob& a) {
return a.a;
}
std::unique_ptr<Bob> make_bob(uint32_t a) {
auto b = std::make_unique<Bob>();
b->a = a;
return b;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
std::unique_ptr<Bob> make_bob(uint32_t a);
uint32_t take_bob(const Bob& a);
"};
let rs = quote! {
ffi::Bob {};
};
let rs2 = quote! {
ffi::Bob { a: 12 };
};
let rs3 = quote! {
ffi::Bob { do_not_attempt_to_allocate_nonpod_types: [] };
};
run_test_expect_fail(cxx, hdr, rs, &["take_bob", "Bob", "make_bob"], &[]);
run_test_expect_fail(cxx, hdr, rs2, &["take_bob", "Bob", "make_bob"], &[]);
run_test_expect_fail(cxx, hdr, rs3, &["take_bob", "Bob", "make_bob"], &[]);
}
#[test]
fn test_method_pass_pod_by_value() {
let cxx = indoc! {"
uint32_t Bob::get_bob(Anna) const {
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Anna {
uint32_t a;
};
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob(Anna a) const;
};
"};
let rs = quote! {
let a = ffi::Anna { a: 14 };
let b = ffi::Bob { a: 12, b: 13 };
assert_eq!(b.get_bob(a), 12);
};
run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
}
#[test]
fn test_inline_method() {
let hdr = indoc! {"
#include <cstdint>
struct Anna {
uint32_t a;
};
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob(Anna) const {
return a;
}
};
"};
let rs = quote! {
let a = ffi::Anna { a: 14 };
let b = ffi::Bob { a: 12, b: 13 };
assert_eq!(b.get_bob(a), 12);
};
run_test("", hdr, rs, &[], &["Bob", "Anna"]);
}
#[test]
fn test_method_pass_pod_by_reference() {
let cxx = indoc! {"
uint32_t Bob::get_bob(const Anna&) const {
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Anna {
uint32_t a;
};
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob(const Anna& a) const;
};
"};
let rs = quote! {
let a = ffi::Anna { a: 14 };
let b = ffi::Bob { a: 12, b: 13 };
assert_eq!(b.get_bob(&a), 12);
};
run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
}
#[test]
fn test_method_pass_pod_by_mut_reference() {
let cxx = indoc! {"
uint32_t Bob::get_bob(Anna&) const {
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Anna {
uint32_t a;
};
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob(Anna& a) const;
};
"};
let rs = quote! {
let mut a = Box::pin(ffi::Anna { a: 14 });
let b = ffi::Bob { a: 12, b: 13 };
assert_eq!(b.get_bob(a.as_mut()), 12);
};
run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
}
#[test]
fn test_method_pass_pod_by_up() {
let cxx = indoc! {"
uint32_t Bob::get_bob(std::unique_ptr<Anna>) const {
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Anna {
uint32_t a;
};
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob(std::unique_ptr<Anna> z) const;
};
"};
let rs = quote! {
let a = ffi::Anna { a: 14 };
let b = ffi::Bob { a: 12, b: 13 };
assert_eq!(b.get_bob(cxx::UniquePtr::new(a)), 12);
};
run_test(cxx, hdr, rs, &[], &["Bob", "Anna"]);
}
#[test]
fn test_method_pass_nonpod_by_value() {
let cxx = indoc! {"
uint32_t Bob::get_bob(Anna) const {
return a;
}
Anna give_anna() {
Anna a;
a.a = 10;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct Anna {
uint32_t a;
std::string b;
};
Anna give_anna();
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob(Anna a) const;
};
"};
let rs = quote! {
let a = ffi::give_anna();
let b = ffi::Bob { a: 12, b: 13 };
assert_eq!(b.get_bob(a), 12);
};
run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
}
#[test]
fn test_method_pass_nonpod_by_value_with_up() {
let cxx = indoc! {"
uint32_t Bob::get_bob(Anna, std::unique_ptr<Anna>) const {
return a;
}
Anna give_anna() {
Anna a;
a.a = 10;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
#include <memory>
struct Anna {
uint32_t a;
std::string b;
};
Anna give_anna();
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob(Anna a, std::unique_ptr<Anna>) const;
};
"};
let rs = quote! {
let a = ffi::give_anna();
let a2 = ffi::give_anna();
let b = ffi::Bob { a: 12, b: 13 };
assert_eq!(b.get_bob(a, a2), 12);
};
run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
}
#[test]
fn test_method_pass_nonpod_by_reference() {
let cxx = indoc! {"
uint32_t Bob::get_bob(const Anna&) const {
return a;
}
Anna give_anna() {
Anna a;
a.a = 10;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct Anna {
uint32_t a;
std::string b;
};
Anna give_anna();
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob(const Anna& a) const;
};
"};
let rs = quote! {
let a = ffi::give_anna();
let b = ffi::Bob { a: 12, b: 13 };
assert_eq!(b.get_bob(a.as_ref().unwrap()), 12);
};
run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
}
#[test]
fn test_method_pass_nonpod_by_mut_reference() {
let cxx = indoc! {"
uint32_t Bob::get_bob(Anna&) const {
return a;
}
Anna give_anna() {
Anna a;
a.a = 10;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct Anna {
uint32_t a;
std::string b;
};
Anna give_anna();
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob(Anna& a) const;
};
"};
let rs = quote! {
let mut a = ffi::give_anna();
let b = ffi::Bob { a: 12, b: 13 };
assert_eq!(b.get_bob(a.as_mut().unwrap()), 12);
};
run_test(cxx, hdr, rs, &["Anna", "give_anna"], &["Bob"]);
}
#[test]
fn test_method_pass_nonpod_by_up() {
let cxx = indoc! {"
uint32_t Bob::get_bob(std::unique_ptr<Anna>) const {
return a;
}
Anna give_anna() {
Anna a;
a.a = 10;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
#include <string>
struct Anna {
uint32_t a;
std::string b;
};
Anna give_anna();
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t get_bob(std::unique_ptr<Anna> z) const;
};
"};
let rs = quote! {
let a = ffi::give_anna();
let b = ffi::Bob { a: 12, b: 13 };
assert_eq!(b.get_bob(a), 12);
};
run_test(cxx, hdr, rs, &["give_anna"], &["Bob"]);
}
#[test]
fn test_method_return_nonpod_by_value() {
let cxx = indoc! {"
Anna Bob::get_anna() const {
Anna a;
a.a = 12;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct Anna {
uint32_t a;
std::string b;
};
struct Bob {
public:
uint32_t a;
uint32_t b;
Anna get_anna() const;
};
"};
let rs = quote! {
let b = ffi::Bob { a: 12, b: 13 };
let a = b.get_anna();
assert!(!a.is_null());
};
run_test(cxx, hdr, rs, &["Anna"], &["Bob"]);
}
#[test]
fn test_pass_string_by_value() {
let cxx = indoc! {"
uint32_t measure_string(std::string z) {
return z.length();
}
std::unique_ptr<std::string> get_msg() {
return std::make_unique<std::string>(\"hello\");
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
#include <memory>
uint32_t measure_string(std::string a);
std::unique_ptr<std::string> get_msg();
"};
let rs = quote! {
let a = ffi::get_msg();
let c = ffi::measure_string(a);
assert_eq!(c, 5);
};
run_test(cxx, hdr, rs, &["measure_string", "get_msg"], &[]);
}
#[test]
fn test_return_string_by_value() {
let cxx = indoc! {"
std::string get_msg() {
return \"hello\";
}
"};
let hdr = indoc! {"
#include <string>
std::string get_msg();
"};
let rs = quote! {
let a = ffi::get_msg();
assert!(a.as_ref().unwrap() == "hello");
};
run_test(cxx, hdr, rs, &["get_msg"], &[]);
}
#[test]
fn test_method_pass_string_by_value() {
let cxx = indoc! {"
uint32_t Bob::measure_string(std::string z) const {
return z.length();
}
std::unique_ptr<std::string> get_msg() {
return std::make_unique<std::string>(\"hello\");
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
#include <memory>
struct Bob {
public:
uint32_t a;
uint32_t b;
uint32_t measure_string(std::string a) const;
};
std::unique_ptr<std::string> get_msg();
"};
let rs = quote! {
let a = ffi::get_msg();
let b = ffi::Bob { a: 12, b: 13 };
let c = b.measure_string(a);
assert_eq!(c, 5);
};
run_test(cxx, hdr, rs, &["Bob", "get_msg"], &["Bob"]);
}
#[test]
fn test_method_return_string_by_value() {
let cxx = indoc! {"
std::string Bob::get_msg() const {
return \"hello\";
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct Bob {
public:
uint32_t a;
uint32_t b;
std::string get_msg() const;
};
"};
let rs = quote! {
let b = ffi::Bob { a: 12, b: 13 };
let a = b.get_msg();
assert!(a.as_ref().unwrap() == "hello");
};
run_test(cxx, hdr, rs, &[], &["Bob"]);
}
#[test]
fn test_pass_rust_string_by_ref() {
let cxx = indoc! {"
uint32_t measure_string(const rust::String& z) {
return std::string(z).length();
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <cxx.h>
uint32_t measure_string(const rust::String& z);
"};
let rs = quote! {
let c = ffi::measure_string(&"hello".to_string());
assert_eq!(c, 5);
};
run_test(cxx, hdr, rs, &["measure_string"], &[]);
}
#[test]
fn test_pass_rust_string_by_value() {
let cxx = indoc! {"
uint32_t measure_string(rust::String z) {
return std::string(z).length();
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <cxx.h>
uint32_t measure_string(rust::String z);
"};
let rs = quote! {
let c = ffi::measure_string("hello".into());
assert_eq!(c, 5);
};
run_test(cxx, hdr, rs, &["measure_string"], &[]);
}
#[test]
fn test_pass_rust_str() {
let cxx = indoc! {"
uint32_t measure_string(rust::Str z) {
return std::string(z).length();
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <cxx.h>
uint32_t measure_string(rust::Str z);
"};
let rs = quote! {
let c = ffi::measure_string("hello");
assert_eq!(c, 5);
};
run_test(cxx, hdr, rs, &["measure_string"], &[]);
}
#[test]
fn test_multiple_classes_with_methods() {
let hdr = indoc! {"
#include <cstdint>
struct TrivialStruct {
uint32_t val = 0;
uint32_t get() const;
uint32_t inc();
};
TrivialStruct make_trivial_struct();
class TrivialClass {
public:
uint32_t get() const;
uint32_t inc();
private:
uint32_t val_ = 1;
};
TrivialClass make_trivial_class();
struct OpaqueStruct {
// ~OpaqueStruct();
uint32_t val = 2;
uint32_t get() const;
uint32_t inc();
};
OpaqueStruct make_opaque_struct();
class OpaqueClass {
public:
// ~OpaqueClass();
uint32_t get() const;
uint32_t inc();
private:
uint32_t val_ = 3;
};
OpaqueClass make_opaque_class();
"};
let cxx = indoc! {"
TrivialStruct make_trivial_struct() { return {}; }
TrivialClass make_trivial_class() { return {}; }
OpaqueStruct make_opaque_struct() { return {}; }
OpaqueClass make_opaque_class() { return {}; }
uint32_t TrivialStruct::get() const { return val;}
uint32_t TrivialClass::get() const { return val_; }
uint32_t OpaqueStruct::get() const { return val;}
uint32_t OpaqueClass::get() const { return val_; }
uint32_t TrivialStruct::inc() { return ++val; }
uint32_t TrivialClass::inc() { return ++val_; }
uint32_t OpaqueStruct::inc() { return ++val; }
uint32_t OpaqueClass::inc() { return ++val_; }
"};
let rs = quote! {
use ffi::*;
let mut ts = Box::pin(make_trivial_struct());
assert_eq!(ts.get(), 0);
assert_eq!(ts.as_mut().inc(), 1);
assert_eq!(ts.as_mut().inc(), 2);
let mut tc = Box::pin(make_trivial_class());
assert_eq!(tc.get(), 1);
assert_eq!(tc.as_mut().inc(), 2);
assert_eq!(tc.as_mut().inc(), 3);
let mut os= make_opaque_struct();
assert_eq!(os.get(), 2);
assert_eq!(os.pin_mut().inc(), 3);
assert_eq!(os.pin_mut().inc(), 4);
let mut oc = make_opaque_class();
assert_eq!(oc.get(), 3);
assert_eq!(oc.pin_mut().inc(), 4);
assert_eq!(oc.pin_mut().inc(), 5);
};
run_test(
cxx,
hdr,
rs,
&[
"make_trivial_struct",
"make_trivial_class",
"make_opaque_struct",
"make_opaque_class",
"OpaqueStruct",
"OpaqueClass",
],
&["TrivialStruct", "TrivialClass"],
);
}
#[test]
fn test_ns_return_struct() {
let cxx = indoc! {"
A::B::Bob give_bob() {
A::B::Bob a;
a.a = 3;
a.b = 4;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
namespace A {
namespace B {
struct Bob {
uint32_t a;
uint32_t b;
};
}
}
A::B::Bob give_bob();
"};
let rs = quote! {
assert_eq!(ffi::give_bob().b, 4);
};
run_test(cxx, hdr, rs, &["give_bob"], &["A::B::Bob"]);
}
#[test]
fn test_ns_take_struct() {
let cxx = indoc! {"
uint32_t take_bob(A::B::Bob a) {
return a.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
namespace A {
namespace B {
struct Bob {
uint32_t a;
uint32_t b;
};
}
}
uint32_t take_bob(A::B::Bob a);
"};
let rs = quote! {
let a = ffi::A::B::Bob { a: 12, b: 13 };
assert_eq!(ffi::take_bob(a), 12);
};
run_test(cxx, hdr, rs, &["take_bob"], &["A::B::Bob"]);
}
#[test]
fn test_ns_func() {
let cxx = indoc! {"
using namespace C;
A::B::Bob C::give_bob() {
A::B::Bob a;
a.a = 3;
a.b = 4;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
namespace A {
namespace B {
struct Bob {
uint32_t a;
uint32_t b;
};
}
}
namespace C {
::A::B::Bob give_bob();
}
"};
let rs = quote! {
assert_eq!(ffi::C::give_bob().b, 4);
};
run_test(cxx, hdr, rs, &["C::give_bob"], &["A::B::Bob"]);
}
#[test]
fn test_overload_constructors() {
let cxx = indoc! {"
Bob::Bob() {}
Bob::Bob(uint32_t _a) :a(_a) {}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
Bob();
Bob(uint32_t a);
uint32_t a;
uint32_t b;
};
"};
let rs = quote! {
ffi::Bob::make_unique();
ffi::Bob::make_unique1(32);
};
run_test(cxx, hdr, rs, &["Bob"], &[]);
}
#[test]
fn test_overload_functions() {
let cxx = indoc! {"
void daft(uint32_t) {}
void daft(uint8_t) {}
void daft(std::string) {}
void daft(Fred) {}
void daft(Norma) {}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct Fred {
uint32_t a;
};
struct Norma {
Norma() {}
uint32_t a;
};
void daft(uint32_t);
void daft(uint8_t);
void daft(std::string);
void daft(Fred);
void daft(Norma);
"};
let rs = quote! {
use ffi::ToCppString;
ffi::daft(32);
ffi::daft1(8);
ffi::daft2("hello".into_cpp());
let b = ffi::Fred { a: 3 };
ffi::daft3(b);
let c = ffi::Norma::make_unique();
ffi::daft4(c);
};
run_test(
cxx,
hdr,
rs,
&["Norma", "daft", "daft1", "daft2", "daft3", "daft4"],
&["Fred"],
);
}
#[test]
#[ignore] fn test_overload_numeric_functions() {
let cxx = indoc! {"
void daft1(uint32_t) {}
void daft2(uint8_t) {}
void daft(std::string) {}
void daft(Fred) {}
void daft(Norma) {}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct Fred {
uint32_t a;
};
struct Norma {
uint32_t a;
};
void daft1(uint32_t a);
void daft2(uint8_t a);
void daft(std::string a);
void daft(Fred a);
void daft(Norma a);
"};
let rs = quote! {
use ffi::ToCppString;
ffi::daft(32);
ffi::daft1(8);
ffi::daft2("hello".into_cpp());
let b = ffi::Fred { a: 3 };
ffi::daft3(b);
let c = ffi::Norma::make_unique();
ffi::daft4(c);
};
run_test(
cxx,
hdr,
rs,
&["Norma", "daft", "daft1", "daft2", "daft3", "daft4"],
&["Fred"],
);
}
#[test]
fn test_overload_methods() {
let cxx = indoc! {"
void Bob::daft(uint32_t) const {}
void Bob::daft(uint8_t) const {}
void Bob::daft(std::string) const {}
void Bob::daft(Fred) const {}
void Bob::daft(Norma) const {}
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct Fred {
uint32_t a;
};
struct Norma {
Norma() {}
uint32_t a;
};
struct Bob {
uint32_t a;
void daft(uint32_t) const;
void daft(uint8_t) const;
void daft(std::string) const;
void daft(Fred) const;
void daft(Norma) const;
};
"};
let rs = quote! {
use ffi::ToCppString;
let a = ffi::Bob { a: 12 };
a.daft(32);
a.daft1(8);
a.daft2("hello".into_cpp());
let b = ffi::Fred { a: 3 };
a.daft3(b);
let c = ffi::Norma::make_unique();
a.daft4(c);
};
run_test(cxx, hdr, rs, &["Norma"], &["Fred", "Bob"]);
}
#[test]
fn test_ns_constructor() {
let cxx = indoc! {"
A::Bob::Bob() {}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
Bob();
uint32_t a;
uint32_t b;
};
}
"};
let rs = quote! {
ffi::A::Bob::make_unique();
};
run_test(cxx, hdr, rs, &["A::Bob"], &[]);
}
#[test]
fn test_ns_up_direct() {
let cxx = indoc! {"
std::unique_ptr<A::Bob> A::get_bob() {
A::Bob b;
b.a = 2;
b.b = 3;
return std::make_unique<A::Bob>(b);
}
uint32_t give_bob(A::Bob bob) {
return bob.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
uint32_t a;
uint32_t b;
};
std::unique_ptr<Bob> get_bob();
}
uint32_t give_bob(A::Bob bob);
"};
let rs = quote! {
assert_eq!(ffi::give_bob(ffi::A::get_bob()), 2);
};
run_test(cxx, hdr, rs, &["give_bob", "A::get_bob"], &[]);
}
#[test]
fn test_ns_up_wrappers() {
let cxx = indoc! {"
A::Bob get_bob() {
A::Bob b;
b.a = 2;
b.b = 3;
return b;
}
uint32_t give_bob(A::Bob bob) {
return bob.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
namespace A {
struct Bob {
uint32_t a;
uint32_t b;
};
}
A::Bob get_bob();
uint32_t give_bob(A::Bob bob);
"};
let rs = quote! {
assert_eq!(ffi::give_bob(ffi::get_bob()), 2);
};
run_test(cxx, hdr, rs, &["give_bob", "get_bob"], &[]);
}
#[test]
fn test_ns_up_wrappers_in_up() {
let cxx = indoc! {"
A::Bob A::get_bob() {
A::Bob b;
b.a = 2;
b.b = 3;
return b;
}
uint32_t give_bob(A::Bob bob) {
return bob.a;
}
"};
let hdr = indoc! {"
#include <cstdint>
namespace A {
struct Bob {
uint32_t a;
uint32_t b;
};
Bob get_bob();
}
uint32_t give_bob(A::Bob bob);
"};
let rs = quote! {
assert_eq!(ffi::give_bob(ffi::A::get_bob()), 2);
};
run_test(cxx, hdr, rs, &["give_bob", "A::get_bob"], &[]);
}
#[test]
fn test_return_reference() {
let cxx = indoc! {"
const Bob& give_bob(const Bob& input_bob) {
return input_bob;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
uint32_t b;
};
const Bob& give_bob(const Bob& input_bob);
"};
let rs = quote! {
let b = ffi::Bob { a: 3, b: 4 };
assert_eq!(ffi::give_bob(&b).b, 4);
};
run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
}
#[test]
fn test_destructor() {
let hdr = indoc! {"
struct WithDtor {
~WithDtor();
};
WithDtor make_with_dtor();
"};
let cxx = indoc! {"
WithDtor::~WithDtor() {}
WithDtor make_with_dtor() {
return {};
}
"};
let rs = quote! {
use ffi::*;
let with_dtor: cxx::UniquePtr<WithDtor> = make_with_dtor();
drop(with_dtor);
};
run_test(cxx, hdr, rs, &["WithDtor", "make_with_dtor"], &[]);
}
#[test]
fn test_static_func() {
let hdr = indoc! {"
#include <cstdint>
struct WithStaticMethod {
static uint32_t call();
};
"};
let cxx = indoc! {"
uint32_t WithStaticMethod::call() {
return 42;
}
"};
let rs = quote! {
assert_eq!(ffi::WithStaticMethod::call(), 42);
};
run_test(cxx, hdr, rs, &["WithStaticMethod"], &[]);
}
#[test]
fn test_static_func_wrapper() {
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct A {
std::string a;
static A CreateA(std::string a, std::string) {
A c;
c.a = a;
return c;
}
};
"};
let rs = quote! {
use ffi::ToCppString;
ffi::A::CreateA("a".into_cpp(), "b".into_cpp());
};
run_test("", hdr, rs, &["A"], &[]);
}
#[test]
fn test_give_pod_typedef_by_value() {
let cxx = indoc! {"
Horace give_bob() {
Horace a;
a.a = 3;
a.b = 4;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
uint32_t b;
};
using Horace = Bob;
Horace give_bob();
"};
let rs = quote! {
assert_eq!(ffi::give_bob().b, 4);
};
run_test(cxx, hdr, rs, &["give_bob"], &["Bob"]);
}
#[ignore] #[test]
fn test_use_pod_typedef() {
let cxx = indoc! {"
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
uint32_t b;
};
using Horace = Bob;
"};
let rs = quote! {
let h = Horace { a: 3, b: 4 };
assert_eq!(h.b, 4);
};
run_test(cxx, hdr, rs, &[], &["Bob"]);
}
#[test]
fn test_typedef_to_ns() {
let hdr = indoc! {"
#include <cstdint>
namespace A {
template<typename T>
struct C {
T* t;
};
typedef C<char> B;
}
"};
let rs = quote! {};
run_test("", hdr, rs, &["A::B"], &[]);
}
#[ignore] #[test]
fn test_use_pod_typedef_with_allowpod() {
let cxx = indoc! {"
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
uint32_t b;
};
using Horace = Bob;
"};
let rs = quote! {
let h = Horace { a: 3, b: 4 };
assert_eq!(h.b, 4);
};
run_test(cxx, hdr, rs, &[], &["Horace"]);
}
#[test]
fn test_give_nonpod_typedef_by_value() {
let cxx = indoc! {"
Horace give_bob() {
Horace a;
a.a = 3;
a.b = 4;
return a;
}
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
uint32_t b;
};
using Horace = Bob;
Horace give_bob();
inline uint32_t take_horace(const Horace& horace) { return horace.b; }
"};
let rs = quote! {
assert_eq!(ffi::take_horace(ffi::give_bob().as_ref().unwrap()), 4);
};
run_test(cxx, hdr, rs, &["give_bob", "take_horace"], &[]);
}
#[test]
fn test_conflicting_static_functions() {
let cxx = indoc! {"
Bob Bob::create() { Bob a; return a; }
Fred Fred::create() { Fred b; return b; }
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
Bob() : a(0) {}
uint32_t a;
static Bob create();
};
struct Fred {
Fred() : b(0) {}
uint32_t b;
static Fred create();
};
"};
let rs = quote! {
ffi::Bob::create();
ffi::Fred::create();
};
run_test(cxx, hdr, rs, &[], &["Bob", "Fred"]);
}
#[test]
fn test_conflicting_ns_up_functions() {
let cxx = indoc! {"
uint32_t A::create(C) { return 3; }
uint32_t B::create(C) { return 4; }
"};
let hdr = indoc! {"
#include <cstdint>
struct C {
C() {}
uint32_t a;
};
namespace A {
uint32_t create(C c);
};
namespace B {
uint32_t create(C c);
};
"};
let rs = quote! {
let c = ffi::C::make_unique();
let c2 = ffi::C::make_unique();
assert_eq!(ffi::A::create(c), 3);
assert_eq!(ffi::B::create(c2), 4);
};
run_test(cxx, hdr, rs, &["A::create", "B::create", "C"], &[]);
}
#[test]
fn test_conflicting_methods() {
let cxx = indoc! {"
uint32_t Bob::get() const { return a; }
uint32_t Fred::get() const { return b; }
"};
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
uint32_t get() const;
};
struct Fred {
uint32_t b;
uint32_t get() const;
};
"};
let rs = quote! {
let a = ffi::Bob { a: 10 };
let b = ffi::Fred { b: 20 };
assert_eq!(a.get(), 10);
assert_eq!(b.get(), 20);
};
run_test(cxx, hdr, rs, &[], &["Bob", "Fred"]);
}
#[test]
fn test_conflicting_up_wrapper_methods_not_in_ns() {
let cxx = indoc! {"
Bob::Bob() : a(\"hello\") {}
Fred::Fred() : b(\"goodbye\") {}
std::string Bob::get() const { return a; }
std::string Fred::get() const { return b; }
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct Bob {
Bob();
std::string a;
std::string get() const;
};
struct Fred {
Fred();
std::string b;
std::string get() const;
};
"};
let rs = quote! {
let a = ffi::Bob::make_unique();
let b = ffi::Fred::make_unique();
assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello");
assert_eq!(b.get().as_ref().unwrap().to_str().unwrap(), "goodbye");
};
run_test(cxx, hdr, rs, &["Bob", "Fred"], &[]);
}
#[test]
fn test_conflicting_methods_in_ns() {
let cxx = indoc! {"
uint32_t A::Bob::get() const { return a; }
uint32_t B::Fred::get() const { return b; }
"};
let hdr = indoc! {"
#include <cstdint>
namespace A {
struct Bob {
uint32_t a;
uint32_t get() const;
};
}
namespace B {
struct Fred {
uint32_t b;
uint32_t get() const;
};
}
"};
let rs = quote! {
let a = ffi::A::Bob { a: 10 };
let b = ffi::B::Fred { b: 20 };
assert_eq!(a.get(), 10);
assert_eq!(b.get(), 20);
};
run_test(cxx, hdr, rs, &[], &["A::Bob", "B::Fred"]);
}
#[test]
fn test_conflicting_up_wrapper_methods_in_ns() {
let cxx = indoc! {"
A::Bob::Bob() : a(\"hello\") {}
B::Fred::Fred() : b(\"goodbye\") {}
std::string A::Bob::get() const { return a; }
std::string B::Fred::get() const { return b; }
"};
let hdr = indoc! {"
#include <cstdint>
#include <string>
namespace A {
struct Bob {
Bob();
std::string a;
std::string get() const;
};
}
namespace B {
struct Fred {
Fred();
std::string b;
std::string get() const;
};
}
"};
let rs = quote! {
let a = ffi::A::Bob::make_unique();
let b = ffi::B::Fred::make_unique();
assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello");
assert_eq!(b.get().as_ref().unwrap().to_str().unwrap(), "goodbye");
};
run_test(cxx, hdr, rs, &["A::Bob", "B::Fred"], &[]);
}
#[test]
fn test_ns_struct_pod_request() {
let hdr = indoc! {"
#include <cstdint>
namespace A {
struct Bob {
uint32_t a;
};
}
"};
let rs = quote! {
ffi::A::Bob { a: 12 };
};
run_test("", hdr, rs, &[], &["A::Bob"]);
}
#[test]
fn test_conflicting_ns_funcs() {
let cxx = indoc! {"
uint32_t A::get() { return 10; }
uint32_t B::get() { return 20; }
"};
let hdr = indoc! {"
#include <cstdint>
namespace A {
uint32_t get();
}
namespace B {
uint32_t get();
}
"};
let rs = quote! {
assert_eq!(ffi::A::get(), 10);
assert_eq!(ffi::B::get(), 20);
};
run_test(cxx, hdr, rs, &["A::get", "B::get"], &[]);
}
#[ignore]
#[test]
fn test_conflicting_ns_structs() {
let hdr = indoc! {"
#include <cstdint>
namespace A {
struct Bob {
uint32_t a;
};
}
namespace B {
struct Bob {
uint32_t a;
};
}
"};
let rs = quote! {
ffi::A::Bob { a: 12 };
ffi::B::Bob { b: 12 };
};
run_test("", hdr, rs, &[], &["A::Bob", "B::Bob"]);
}
#[test]
fn test_make_string() {
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
};
"};
let rs = quote! {
use ffi::ToCppString;
let a = "hello".into_cpp();
assert_eq!(a.to_str().unwrap(), "hello");
};
run_test("", hdr, rs, &["Bob"], &[]);
}
#[test]
fn test_string_constant() {
let hdr = indoc! {"
#include <cstdint>
const char* STRING = \"Foo\";
"};
let rs = quote! {
let a = std::str::from_utf8(ffi::STRING).unwrap().trim_end_matches(char::from(0));
assert_eq!(a, "Foo");
};
run_test("", hdr, rs, &["STRING"], &[]);
}
#[test]
fn test_pod_constant_harmless_inside_type() {
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
};
struct Anna {
uint32_t a;
const Bob BOB = Bob { 10 };
};
"};
let rs = quote! {};
run_test("", hdr, rs, &[], &["Anna"]);
}
#[test]
#[ignore] fn test_pod_constant() {
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
};
const Bob BOB = Bob { 10 };
"};
let rs = quote! {
let a = &ffi::BOB;
assert_eq!(a.a, 10);
};
run_test("", hdr, rs, &["BOB"], &["Bob"]);
}
#[test]
fn test_pod_static_harmless_inside_type() {
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
};
struct Anna {
uint32_t a;
static Bob BOB;
};
Bob Anna::BOB = Bob { 10 };
"};
let rs = quote! {};
run_test("", hdr, rs, &[], &["Anna"]);
}
#[test]
#[ignore] fn test_pod_static() {
let hdr = indoc! {"
#include <cstdint>
struct Bob {
uint32_t a;
};
static Bob BOB = Bob { 10 };
"};
let rs = quote! {
let a = &ffi::BOB;
assert_eq!(a.a, 10);
};
run_test("", hdr, rs, &["BOB"], &["Bob"]);
}
#[test]
#[ignore] fn test_non_pod_constant() {
let hdr = indoc! {"
#include <cstdint>
#include <string>
struct Bob {
std::string a;
std::string get() { return a };
};
const Bob BOB = Bob { \"hello\" };
"};
let rs = quote! {
let a = ffi::BOB;
assert_eq!(a.get().as_ref().unwrap().to_str().unwrap(), "hello");
};
run_test("", hdr, rs, &["BOB"], &[]);
}
#[test]
fn test_templated_typedef() {
let hdr = indoc! {"
#include <string>
#include <cstdint>
template <typename STRING_TYPE> class BasicStringPiece {
public:
const STRING_TYPE* ptr_;
size_t length_;
};
typedef BasicStringPiece<uint8_t> StringPiece;
struct Origin {
Origin() {}
StringPiece host;
};
"};
let rs = quote! {
ffi::Origin::make_unique();
};
run_test("", hdr, rs, &["Origin"], &[]);
}
#[test]
fn test_struct_templated_typedef() {
let hdr = indoc! {"
#include <string>
#include <cstdint>
struct Concrete {
uint8_t a;
};
template <typename STRING_TYPE> class BasicStringPiece {
public:
const STRING_TYPE* ptr_;
size_t length_;
};
typedef BasicStringPiece<Concrete> StringPiece;
struct Origin {
Origin() {}
StringPiece host;
};
"};
let rs = quote! {
ffi::Origin::make_unique();
};
run_test("", hdr, rs, &["Origin"], &[]);
}
#[test]
fn test_enum_typedef() {
let hdr = indoc! {"
enum ConstraintSolverParameters_TrailCompression : int {
ConstraintSolverParameters_TrailCompression_NO_COMPRESSION = 0,
ConstraintSolverParameters_TrailCompression_COMPRESS_WITH_ZLIB = 1,
ConstraintSolverParameters_TrailCompression_ConstraintSolverParameters_TrailCompression_INT_MIN_SENTINEL_DO_NOT_USE_ = -2147483648,
ConstraintSolverParameters_TrailCompression_ConstraintSolverParameters_TrailCompression_INT_MAX_SENTINEL_DO_NOT_USE_ = 2147483647
};
typedef ConstraintSolverParameters_TrailCompression TrailCompression;
"};
let rs = quote! {
let _ = ffi::TrailCompression::ConstraintSolverParameters_TrailCompression_NO_COMPRESSION;
};
run_test("", hdr, rs, &["TrailCompression"], &[]);
}
#[test]
#[ignore] fn test_conflicting_usings() {
let hdr = indoc! {"
#include <cstdint>
#include <cstddef>
typedef size_t diff;
struct A {
using diff = diff;
diff a;
};
struct B {
using diff = diff;
diff a;
};
"};
let rs = quote! {};
run_test("", hdr, rs, &[], &["A", "B"]);
}
#[test]
fn test_conflicting_usings_with_self_declaration1() {
let hdr = indoc! {"
#include <cstdint>
#include <cstddef>
struct common_params {
using difference_type = ptrdiff_t;
};
template <typename Params>
class btree_node {
public:
using difference_type = typename Params::difference_type;
Params params;
};
template <typename Tree>
class btree_container {
public:
using difference_type = typename Tree::difference_type;
void clear() {}
Tree b;
uint32_t a;
};
typedef btree_container<btree_node<common_params>> my_tree;
"};
let rs = quote! {};
run_test("", hdr, rs, &["my_tree"], &[]);
}
#[test]
#[ignore] fn test_string_templated_typedef() {
let hdr = indoc! {"
#include <string>
#include <cstdint>
template <typename STRING_TYPE> class BasicStringPiece {
public:
const STRING_TYPE* ptr_;
size_t length_;
};
typedef BasicStringPiece<std::string> StringPiece;
struct Origin {
Origin() {}
StringPiece host;
};
"};
let rs = quote! {
ffi::Origin::make_unique();
};
run_test("", hdr, rs, &["Origin"], &[]);
}
#[test]
fn test_associated_type_problem() {
let hdr = indoc! {"
namespace a {
template <typename> class b {};
} // namespace a
class bl {
a::b<bl> bm;
};
struct B {
int a;
};
"};
let rs = quote! {};
run_test("", hdr, rs, &["B"], &[]);
}
#[ignore] #[test]
fn test_associated_type_templated_typedef() {
let hdr = indoc! {"
#include <string>
#include <cstdint>
template <typename STRING_TYPE> class BasicStringPiece {
public:
typedef size_t size_type;
typedef typename STRING_TYPE::value_type value_type;
const value_type* ptr_;
size_type length_;
};
typedef BasicStringPiece<std::string> StringPiece;
struct Origin {
// void SetHost(StringPiece host);
StringPiece host;
};
"};
let rs = quote! {
ffi::Origin::make_unique();
};
run_test("", hdr, rs, &["Origin"], &[]);
}
#[test]
fn test_foreign_ns_func_arg_pod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
uint32_t a;
};
}
namespace B {
inline uint32_t daft(A::Bob a) { return a.a; }
}
"};
let rs = quote! {
let a = ffi::A::Bob { a: 12 };
assert_eq!(ffi::B::daft(a), 12);
};
run_test("", hdr, rs, &["B::daft"], &["A::Bob"]);
}
#[test]
fn test_foreign_ns_func_arg_nonpod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
uint32_t a;
Bob(uint32_t _a) :a(_a) {}
};
}
namespace B {
inline uint32_t daft(A::Bob a) { return a.a; }
}
"};
let rs = quote! {
let a = ffi::A::Bob::make_unique(12);
assert_eq!(ffi::B::daft(a), 12);
};
run_test("", hdr, rs, &["B::daft", "A::Bob"], &[]);
}
#[test]
fn test_foreign_ns_meth_arg_pod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
uint32_t a;
};
}
namespace B {
struct C {
uint32_t a;
uint32_t daft(A::Bob a) const { return a.a; }
};
}
"};
let rs = quote! {
let a = ffi::A::Bob { a: 12 };
let b = ffi::B::C { a: 12 };
assert_eq!(b.daft(a), 12);
};
run_test("", hdr, rs, &[], &["A::Bob", "B::C"]);
}
#[test]
fn test_foreign_ns_meth_arg_nonpod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
uint32_t a;
Bob(uint32_t _a) :a(_a) {}
};
}
namespace B {
struct C {
uint32_t a;
uint32_t daft(A::Bob a) const { return a.a; }
};
}
"};
let rs = quote! {
let a = ffi::A::Bob::make_unique(12);
let b = ffi::B::C { a: 12 };
assert_eq!(b.daft(a), 12);
};
run_test("", hdr, rs, &["A::Bob"], &["B::C"]);
}
#[test]
fn test_foreign_ns_cons_arg_pod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
uint32_t a;
};
}
namespace B {
struct C {
uint32_t a;
C(const A::Bob& input) : a(input.a) {}
};
}
"};
let rs = quote! {
let a = ffi::A::Bob { a: 12 };
let b = ffi::B::C::make_unique(&a);
assert_eq!(b.as_ref().unwrap().a, 12);
};
run_test("", hdr, rs, &[], &["B::C", "A::Bob"]);
}
#[test]
fn test_foreign_ns_cons_arg_nonpod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
Bob(uint32_t _a) :a(_a) {}
uint32_t a;
};
}
namespace B {
struct C {
uint32_t a;
C(const A::Bob& input) : a(input.a) {}
};
}
"};
let rs = quote! {
let a = ffi::A::Bob::make_unique(12);
let b = ffi::B::C::make_unique(&a);
assert_eq!(b.as_ref().unwrap().a, 12);
};
run_test("", hdr, rs, &["A::Bob"], &["B::C"]);
}
#[test]
fn test_foreign_ns_func_ret_pod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
uint32_t a;
};
}
namespace B {
inline A::Bob daft() { A::Bob bob; bob.a = 12; return bob; }
}
"};
let rs = quote! {
assert_eq!(ffi::B::daft().a, 12);
};
run_test("", hdr, rs, &["B::daft"], &["A::Bob"]);
}
#[test]
fn test_foreign_ns_func_ret_nonpod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
uint32_t a;
};
}
namespace B {
inline A::Bob daft() { A::Bob bob; bob.a = 12; return bob; }
}
"};
let rs = quote! {
ffi::B::daft().as_ref().unwrap();
};
run_test("", hdr, rs, &["B::daft", "A::Bob"], &[]);
}
#[test]
fn test_foreign_ns_meth_ret_pod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
uint32_t a;
};
}
namespace B {
struct C {
uint32_t a;
A::Bob daft() const { A::Bob bob; bob.a = 12; return bob; }
};
}
"};
let rs = quote! {
let b = ffi::B::C { a: 12 };
assert_eq!(b.daft().a, 12);
};
run_test("", hdr, rs, &[], &["A::Bob", "B::C"]);
}
#[test]
fn test_foreign_ns_meth_ret_nonpod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
namespace A {
struct Bob {
uint32_t a;
};
}
namespace B {
struct C {
uint32_t a;
A::Bob daft() const { A::Bob bob; bob.a = 12; return bob; }
};
}
"};
let rs = quote! {
let b = ffi::B::C { a: 14 };
b.daft().as_ref().unwrap();
};
run_test("", hdr, rs, &["A::Bob"], &["B::C"]);
}
#[test]
fn test_root_ns_func_arg_pod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
namespace B {
inline uint32_t daft(Bob a) { return a.a; }
}
"};
let rs = quote! {
let a = ffi::Bob { a: 12 };
assert_eq!(ffi::B::daft(a), 12);
};
run_test("", hdr, rs, &["B::daft"], &["Bob"]);
}
#[test]
fn test_root_ns_func_arg_nonpod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
Bob(uint32_t _a) :a(_a) {}
};
namespace B {
inline uint32_t daft(Bob a) { return a.a; }
}
"};
let rs = quote! {
let a = ffi::Bob::make_unique(12);
assert_eq!(ffi::B::daft(a), 12);
};
run_test("", hdr, rs, &["B::daft", "Bob"], &[]);
}
#[test]
fn test_root_ns_meth_arg_pod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
namespace B {
struct C {
uint32_t a;
uint32_t daft(Bob a) const { return a.a; }
};
}
"};
let rs = quote! {
let a = ffi::Bob { a: 12 };
let b = ffi::B::C { a: 12 };
assert_eq!(b.daft(a), 12);
};
run_test("", hdr, rs, &[], &["Bob", "B::C"]);
}
#[test]
fn test_root_ns_meth_arg_nonpod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
Bob(uint32_t _a) :a(_a) {}
};
namespace B {
struct C {
uint32_t a;
uint32_t daft(Bob a) const { return a.a; }
};
}
"};
let rs = quote! {
let a = ffi::Bob::make_unique(12);
let b = ffi::B::C { a: 12 };
assert_eq!(b.daft(a), 12);
};
run_test("", hdr, rs, &["Bob"], &["B::C"]);
}
#[test]
fn test_root_ns_cons_arg_pod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
namespace B {
struct C {
uint32_t a;
C(const Bob& input) : a(input.a) {}
};
}
"};
let rs = quote! {
let a = ffi::Bob { a: 12 };
let b = ffi::B::C::make_unique(&a);
assert_eq!(b.as_ref().unwrap().a, 12);
};
run_test("", hdr, rs, &[], &["B::C", "Bob"]);
}
#[test]
fn test_root_ns_cons_arg_nonpod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
Bob(uint32_t _a) :a(_a) {}
uint32_t a;
};
namespace B {
struct C {
uint32_t a;
C(const Bob& input) : a(input.a) {}
};
}
"};
let rs = quote! {
let a = ffi::Bob::make_unique(12);
let b = ffi::B::C::make_unique(&a);
assert_eq!(b.as_ref().unwrap().a, 12);
};
run_test("", hdr, rs, &["Bob"], &["B::C"]);
}
#[test]
fn test_root_ns_func_ret_pod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
namespace B {
inline Bob daft() { Bob bob; bob.a = 12; return bob; }
}
"};
let rs = quote! {
assert_eq!(ffi::B::daft().a, 12);
};
run_test("", hdr, rs, &["B::daft"], &["Bob"]);
}
#[test]
fn test_root_ns_func_ret_nonpod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
namespace B {
inline Bob daft() { Bob bob; bob.a = 12; return bob; }
}
"};
let rs = quote! {
ffi::B::daft().as_ref().unwrap();
};
run_test("", hdr, rs, &["B::daft", "Bob"], &[]);
}
#[test]
fn test_root_ns_meth_ret_pod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
namespace B {
struct C {
uint32_t a;
Bob daft() const { Bob bob; bob.a = 12; return bob; }
};
}
"};
let rs = quote! {
let b = ffi::B::C { a: 12 };
assert_eq!(b.daft().a, 12);
};
run_test("", hdr, rs, &[], &["Bob", "B::C"]);
}
#[test]
fn test_root_ns_meth_ret_nonpod() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct Bob {
uint32_t a;
};
namespace B {
struct C {
uint32_t a;
Bob daft() const { Bob bob; bob.a = 12; return bob; }
};
}
"};
let rs = quote! {
let b = ffi::B::C { a: 12 };
b.daft().as_ref().unwrap();
};
run_test("", hdr, rs, &["Bob"], &["B::C"]);
}
#[test]
fn test_forward_declaration() {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
struct A;
struct B {
B() {}
uint32_t a;
void daft(const A&) const {}
void daft2(std::unique_ptr<A>) const {}
static B daft3(const A&) { B b; return b; }
};
A* get_a();
void delete_a(A*);
"};
let cpp = indoc! {"
struct A {
uint32_t a;
};
A* get_a() {
return new A();
}
void delete_a(A* a) {
delete a;
}
"};
let rs = quote! {
let b = ffi::B::make_unique();
let a = ffi::get_a();
b.daft(unsafe { a.as_ref().unwrap() });
unsafe { ffi::delete_a(a) };
};
run_test(cpp, hdr, rs, &["B", "get_a", "delete_a"], &[]);
}
#[test]
fn test_ulong() {
let hdr = indoc! {"
inline unsigned long daft(unsigned long a) { return a; }
"};
let rs = quote! {
assert_eq!(ffi::daft(autocxx::c_ulong(34)), autocxx::c_ulong(34));
};
run_test("", hdr, rs, &["daft"], &[]);
}
#[test]
fn test_typedef_to_ulong() {
let hdr = indoc! {"
#include <cstddef>
inline size_t daft(size_t a) { return a; }
"};
let rs = quote! {
assert_eq!(ffi::daft(autocxx::c_ulong(34)), autocxx::c_ulong(34));
};
run_test("", hdr, rs, &["daft"], &[]);
}
#[test]
fn test_generate_typedef_to_ulong() {
let hdr = indoc! {"
#include <cstdint>
typedef uint32_t fish_t;
"};
let rs = quote! {
let _: ffi::fish_t;
};
run_test("", hdr, rs, &[], &["fish_t"]);
}
#[test]
fn test_ulong_method() {
let hdr = indoc! {"
class A {
public:
A() {};
unsigned long daft(unsigned long a) const { return a; }
};
"};
let rs = quote! {
let a = ffi::A::make_unique();
assert_eq!(a.as_ref().unwrap().daft(autocxx::c_ulong(34)), autocxx::c_ulong(34));
};
run_test("", hdr, rs, &["A"], &[]);
}
#[test]
fn test_ulong_wrapped_method() {
let hdr = indoc! {"
#include <cstdint>
struct B {
B() {};
uint32_t a;
};
class A {
public:
A() {};
unsigned long daft(unsigned long a, B) const { return a; }
};
"};
let rs = quote! {
let b = ffi::B::make_unique();
let a = ffi::A::make_unique();
assert_eq!(a.as_ref().unwrap().daft(autocxx::c_ulong(34), b), autocxx::c_ulong(34));
};
run_test("", hdr, rs, &["A", "B"], &[]);
}
#[test]
fn test_reserved_name() {
let hdr = indoc! {"
#include <cstdint>
inline uint32_t async(uint32_t a) { return a; }
"};
let rs = quote! {
assert_eq!(ffi::async_(34), 34);
};
run_test("", hdr, rs, &["async_"], &[]);
}
#[test]
fn test_nested_type() {
let hdr = indoc! {"
struct A {
A() {}
struct B {
B() {}
};
enum C {};
using D = int;
};
struct B {
B() {}
void method_on_top_level_type() const {}
};
void take_A_B(A::B);
void take_A_C(A::C);
void take_A_D(A::D);
"};
let rs = quote! {
let _ = ffi::A::make_unique();
let b = ffi::B::make_unique();
b.as_ref().unwrap().method_on_top_level_type();
};
run_test("", hdr, rs, &["A", "B", "take_A_B", "take_A_C"], &[]);
}
#[test]
fn test_nested_type_in_namespace() {
let hdr = indoc! {"
namespace N {
struct A {
A() {}
struct B {
B() {}
};
};
};
void take_A_B(N::A::B);
"};
let rs = quote! {};
run_test("", hdr, rs, &["take_A_B"], &[]);
}
#[test]
fn test_generic_type() {
let hdr = indoc! {"
#include <cstdint>
#include <string>
template<typename TY>
struct Container {
Container(TY a_) : a(a_) {}
TY a;
};
struct Secondary {
Secondary() {}
void take_a(const Container<char>) const {}
void take_b(const Container<uint16_t>) const {}
uint16_t take_c(std::string a) const { return 10 + a.size(); }
};
"};
let rs = quote! {
use ffi::ToCppString;
let item = ffi::Secondary::make_unique();
assert_eq!(item.take_c("hello".into_cpp()), 15)
};
run_test("", hdr, rs, &["Secondary"], &[]);
}
#[test]
fn test_cycle_generic_type() {
let hdr = indoc! {"
#include <cstdint>
template<typename TY>
struct Container {
Container(TY a_) : a(a_) {}
TY a;
};
inline Container<char> make_thingy() {
Container<char> a('a');
return a;
}
typedef Container<char> Concrete;
inline uint32_t take_thingy(Concrete a) {
return a.a;
}
"};
let rs = quote! {
assert_eq!(ffi::take_thingy(ffi::make_thingy()), 'a' as u32)
};
run_test("", hdr, rs, &["take_thingy", "make_thingy"], &[]);
}
#[test]
fn test_virtual_fns() {
let hdr = indoc! {"
#include <cstdint>
class A {
public:
A(uint32_t num) : b(num) {}
virtual uint32_t foo(uint32_t a) { return a+1; };
virtual ~A() {}
uint32_t b;
};
class B: public A {
public:
B() : A(3), c(4) {}
virtual uint32_t foo(uint32_t a) { return a+2; };
uint32_t c;
};
"};
let rs = quote! {
let mut a = ffi::A::make_unique(12);
assert_eq!(a.pin_mut().foo(2), 3);
let mut b = ffi::B::make_unique();
assert_eq!(b.pin_mut().foo(2), 4);
};
run_test("", hdr, rs, &["A", "B"], &[]);
}
#[test]
fn test_const_virtual_fns() {
let hdr = indoc! {"
#include <cstdint>
class A {
public:
A(uint32_t num) : b(num) {}
virtual uint32_t foo(uint32_t a) const { return a+1; };
virtual ~A() {}
uint32_t b;
};
class B: public A {
public:
B() : A(3), c(4) {}
virtual uint32_t foo(uint32_t a) const { return a+2; };
uint32_t c;
};
"};
let rs = quote! {
let a = ffi::A::make_unique(12);
assert_eq!(a.foo(2), 3);
let b = ffi::B::make_unique();
assert_eq!(b.foo(2), 4);
};
run_test("", hdr, rs, &["A", "B"], &[]);
}
#[test]
#[ignore] fn test_virtual_fns_inheritance() {
let hdr = indoc! {"
#include <cstdint>
class A {
public:
A(uint32_t num) : b(num) {}
virtual uint32_t foo(uint32_t a) { return a+1; };
virtual ~A() {}
uint32_t b;
};
class B: public A {
public:
B() : A(3), c(4) {}
uint32_t c;
};
"};
let rs = quote! {
let mut b = ffi::B::make_unique();
assert_eq!(b.pin_mut().foo(2), 3);
};
run_test("", hdr, rs, &["B"], &[]);
}
#[test]
fn test_vector_cycle_up() {
let hdr = indoc! {"
#include <cstdint>
#include <vector>
#include <memory>
struct A {
uint32_t a;
};
inline uint32_t take_vec(std::unique_ptr<std::vector<A>> many_as) {
return many_as->size();
}
inline std::unique_ptr<std::vector<A>> get_vec() {
auto items = std::make_unique<std::vector<A>>();
items->push_back(A { 3 });
items->push_back(A { 4 });
return items;
}
"};
let rs = quote! {
let v = ffi::get_vec();
assert_eq!(v.as_ref().unwrap().is_empty(), false);
assert_eq!(ffi::take_vec(v), 2);
};
run_test("", hdr, rs, &["take_vec", "get_vec"], &[]);
}
#[test]
fn test_vector_cycle_bare() {
let hdr = indoc! {"
#include <cstdint>
#include <vector>
struct A {
uint32_t a;
};
inline uint32_t take_vec(std::vector<A> many_as) {
return many_as.size();
}
inline std::vector<A> get_vec() {
std::vector<A> items;
items.push_back(A { 3 });
items.push_back(A { 4 });
return items;
}
"};
let rs = quote! {
assert_eq!(ffi::take_vec(ffi::get_vec()), 2);
};
run_test("", hdr, rs, &["take_vec", "get_vec"], &[]);
}
#[test]
fn test_typedef_to_std() {
let hdr = indoc! {"
#include <string>
typedef std::string my_string;
inline uint32_t take_str(my_string a) {
return a.size();
}
"};
let rs = quote! {
use ffi::ToCppString;
assert_eq!(ffi::take_str("hello".into_cpp()), 5);
};
run_test("", hdr, rs, &["take_str"], &[]);
}
#[test]
fn test_typedef_to_up_in_fn_call() {
let hdr = indoc! {"
#include <string>
#include <memory>
typedef std::unique_ptr<std::string> my_string;
inline uint32_t take_str(my_string a) {
return a->size();
}
"};
let rs = quote! {
use ffi::ToCppString;
assert_eq!(ffi::take_str("hello".into_cpp()), 5);
};
run_test("", hdr, rs, &["take_str"], &[]);
}
#[test]
fn test_typedef_in_pod_struct() {
let hdr = indoc! {"
#include <string>
typedef uint32_t my_int;
struct A {
my_int a;
};
inline uint32_t take_a(A a) {
return a.a;
}
"};
let rs = quote! {
let a = ffi::A {
a: 32,
};
assert_eq!(ffi::take_a(a), 32);
};
run_test("", hdr, rs, &["take_a"], &["A"]);
}
#[test]
fn test_typedef_to_std_in_struct() {
let hdr = indoc! {"
#include <string>
typedef std::string my_string;
struct A {
my_string a;
};
inline A make_a(std::string b) {
A bob;
bob.a = b;
return bob;
}
inline uint32_t take_a(A a) {
return a.a.size();
}
"};
let rs = quote! {
use ffi::ToCppString;
assert_eq!(ffi::take_a(ffi::make_a("hello".into_cpp())), 5);
};
run_test("", hdr, rs, &["make_a", "take_a"], &[]);
}
#[test]
fn test_typedef_to_up_in_struct() {
let hdr = indoc! {"
#include <string>
#include <memory>
typedef std::unique_ptr<std::string> my_string;
struct A {
my_string a;
};
inline A make_a(std::string b) {
A bob;
bob.a = std::make_unique<std::string>(b);
return bob;
}
inline uint32_t take_a(A a) {
return a.a->size();
}
"};
let rs = quote! {
use ffi::ToCppString;
assert_eq!(ffi::take_a(ffi::make_a("hello".into_cpp())), 5);
};
run_test("", hdr, rs, &["make_a", "take_a"], &[]);
}
#[test]
fn test_float() {
let hdr = indoc! {"
inline float daft(float a) { return a; }
"};
let rs = quote! {
assert_eq!(ffi::daft(34.0f32), 34.0f32);
};
run_test("", hdr, rs, &["daft"], &[]);
}
#[test]
fn test_double() {
let hdr = indoc! {"
inline double daft(double a) { return a; }
"};
let rs = quote! {
assert_eq!(ffi::daft(34.0f64), 34.0f64);
};
run_test("", hdr, rs, &["daft"], &[]);
}
#[test]
fn test_issues_217_222() {
let hdr = indoc! {"
#include <string>
#include <cstdint>
#include <cstddef>
template <typename STRING_TYPE> class BasicStringPiece {
public:
typedef size_t size_type;
typedef typename STRING_TYPE::traits_type traits_type;
typedef typename STRING_TYPE::value_type value_type;
typedef const value_type* pointer;
typedef const value_type& reference;
typedef const value_type& const_reference;
typedef ptrdiff_t difference_type;
typedef const value_type* const_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
static const size_type npos;
};
template<typename CHAR>
class Replacements {
public:
Replacements() {
}
void SetScheme(const CHAR*) {
}
uint16_t a;
};
struct Component {
uint16_t a;
};
template <typename STR>
class StringPieceReplacements : public Replacements<typename STR::value_type> {
private:
using CharT = typename STR::value_type;
using StringPieceT = BasicStringPiece<STR>;
using ParentT = Replacements<CharT>;
using SetterFun = void (ParentT::*)(const CharT*, const Component&);
void SetImpl(SetterFun, StringPieceT) {
}
public:
void SetSchemeStr(const CharT* str) { SetImpl(&ParentT::SetScheme, str); }
};
class GURL {
public:
typedef StringPieceReplacements<std::string> UrlReplacements;
GURL() {}
GURL ReplaceComponents(const Replacements<char>&) const {
return GURL();
}
uint16_t a;
};
"};
let rs = quote! {
ffi::GURL::make_unique();
};
run_test_ex(
"",
hdr,
rs,
&["GURL"],
&[],
Some(quote! { block!("StringPiece") block!("Replacements") }),
&[],
None,
);
}
#[test]
#[ignore] fn test_dependent_qualified_type() {
let hdr = indoc! {"
#include <stddef.h>
struct MyString {
typedef char value_type;
};
template<typename T> struct MyStringView {
typedef typename T::value_type view_value_type;
const view_value_type* start;
size_t length;
};
const char* HELLO = \"hello\";
inline MyStringView<MyString> make_string_view() {
MyStringView<MyString> r;
r.start = HELLO;
r.length = 2;
return r;
}
inline size_t take_string_view(const MyStringView<MyString>& bit) {
return bit.length;
}
"};
let rs = quote! {
let sv = ffi::make_string_view();
assert_eq!(ffi::take_string_view(sv.as_ref().unwrap()), 2);
};
run_test("", hdr, rs, &["take_string_view", "make_string_view"], &[]);
}
#[test]
fn test_simple_dependent_qualified_type() {
let hdr = indoc! {"
#include <stddef.h>
#include <stdint.h>
struct MyString {
typedef char value_type;
};
template<typename T> struct MyStringView {
typedef typename T::value_type view_value_type;
const view_value_type* start;
size_t length;
};
typedef MyStringView<MyString>::view_value_type MyChar;
inline MyChar make_char() {
return 'a';
}
inline uint32_t take_char(MyChar c) {
return static_cast<unsigned char>(c);
}
"};
let rs = quote! {
let c = ffi::make_char();
assert_eq!(ffi::take_char(c), 97);
};
run_test("", hdr, rs, &["make_char", "take_char"], &[]);
}
#[test]
fn test_ignore_dependent_qualified_type() {
let hdr = indoc! {"
#include <stddef.h>
struct MyString {
typedef char value_type;
};
template<typename T> struct MyStringView {
typedef typename T::value_type view_value_type;
const view_value_type* start;
size_t length;
};
MyStringView<MyString> make_string_view();
struct B {
B() {}
inline size_t take_string_view(const MyStringView<MyString> bit) {
return bit.length;
}
};
"};
let cpp = indoc! {"
const char* HELLO = \"hello\";
MyStringView<MyString> make_string_view() {
MyStringView<MyString> r;
r.start = HELLO;
r.length = 2;
return r;
}
"};
let rs = quote! {
ffi::B::make_unique();
};
run_test(cpp, hdr, rs, &["B"], &[]);
}
#[test]
fn test_ignore_dependent_qualified_type_reference() {
let hdr = indoc! {"
#include <stddef.h>
struct MyString {
typedef char value_type;
};
template<typename T> struct MyStringView {
typedef typename T::value_type view_value_type;
const view_value_type* start;
size_t length;
};
MyStringView<MyString> make_string_view();
struct B {
B() {}
inline size_t take_string_view(const MyStringView<MyString>& bit) {
return bit.length;
}
};
"};
let cpp = indoc! {"
const char* HELLO = \"hello\";
MyStringView<MyString> make_string_view() {
MyStringView<MyString> r;
r.start = HELLO;
r.length = 2;
return r;
}
"};
let rs = quote! {
ffi::B::make_unique();
};
run_test(cpp, hdr, rs, &["B"], &[]);
}
#[test]
fn test_specialization() {
let hdr = indoc! {"
#include <stddef.h>
#include <stdint.h>
#include <string>
#include <type_traits>
template <typename T, bool = std::is_trivially_destructible<T>::value>
struct OptionalStorageBase {
T value_;
};
template <typename T,
bool = std::is_trivially_copy_constructible<T>::value,
bool = std::is_trivially_move_constructible<T>::value>
struct OptionalStorage : OptionalStorageBase<T> {};
template <typename T>
struct OptionalStorage<T,
true /* trivially copy constructible */,
false /* trivially move constructible */>
: OptionalStorageBase<T> {
};
template <typename T>
struct OptionalStorage<T,
false /* trivially copy constructible */,
true /* trivially move constructible */>
: OptionalStorageBase<T> {
};
template <typename T>
struct OptionalStorage<T,
true /* trivially copy constructible */,
true /* trivially move constructible */>
: OptionalStorageBase<T> {
};
template <typename T>
class OptionalBase {
private:
OptionalStorage<T> storage_;
};
template <typename T>
class Optional : public OptionalBase<T> {
};
struct B {
B() {}
void take_optional(Optional<std::string>) {}
uint32_t a;
};
"};
let rs = quote! {
ffi::B::make_unique();
};
run_test("", hdr, rs, &["B"], &[]);
}
#[test]
fn test_private_constructor_make_unique() {
let hdr = indoc! {"
#include <stdint.h>
struct A {
private:
A() {};
public:
uint32_t a;
};
"};
let rs = quote! {};
run_test("", hdr, rs, &["A"], &[]);
}
#[test]
#[ignore] fn test_take_array() {
let hdr = indoc! {"
#include <cstdint>
uint32_t take_array(const uint32_t a[4]) {
return a[0] + a[2];
}
"};
let rs = quote! {
let c: [u32; 4usize] = [ 10, 20, 30, 40 ];
let c = c as *const [_];
assert_eq!(ffi::take_array(&c), 40);
};
run_test("", hdr, rs, &["take_array"], &[]);
}
#[test]
fn test_union_ignored() {
let hdr = indoc! {"
#include <cstdint>
union A {
uint32_t a;
float b;
};
struct B {
B() :a(1) {}
uint32_t take_union(A) const {
return 3;
}
uint32_t get_a() const { return 2; }
uint32_t a;
};
"};
let rs = quote! {
let b = ffi::B::make_unique();
assert_eq!(b.get_a(), 2);
};
run_test("", hdr, rs, &["B"], &[]);
}
#[test]
fn test_double_underscores_ignored() {
let hdr = indoc! {"
#include <cstdint>
struct __FOO {
uint32_t a;
};
struct B {
B() :a(1) {}
uint32_t take_foo(__FOO a) const {
return 3;
}
void do__something() const { }
uint32_t get_a() const { return 2; }
uint32_t a;
};
"};
let rs = quote! {
let b = ffi::B::make_unique();
assert_eq!(b.get_a(), 2);
};
run_test("", hdr, rs, &["B"], &[]);
}
#[test]
fn test_double_underscore_typedef_ignored() {
let hdr = indoc! {"
#include <cstdint>
typedef int __int32_t;
typedef __int32_t __darwin_pid_t;
typedef __darwin_pid_t pid_t;
struct B {
B() :a(1) {}
uint32_t take_foo(pid_t) const {
return 3;
}
uint32_t get_a() const { return 2; }
uint32_t a;
};
"};
let rs = quote! {
let b = ffi::B::make_unique();
assert_eq!(b.get_a(), 2);
};
run_test("", hdr, rs, &["B"], &[]);
}
#[test]
fn test_typedef_to_ptr_is_marked_unsafe() {
let hdr = indoc! {"
struct _xlocalefoo; /* forward reference */
typedef struct _xlocalefoo * locale_tfoo;
extern \"C\" {
locale_tfoo duplocalefoo(locale_tfoo);
}
"};
let rs = quote! {};
run_test("", hdr, rs, &["duplocalefoo"], &[]);
}
#[test]
fn test_issue_264() {
let hdr = indoc! {"
namespace a {
typedef int b;
inline namespace c {}
template <typename> class aa;
namespace c {
template <typename d, typename = d, typename = aa<d>> class e;
}
typedef e<char> f;
template <typename g, typename, template <typename> typename> struct h {
using i = g;
};
template <typename g, template <typename> class k> using j = h<g, void, k>;
template <typename g, template <typename> class k>
using m = typename j<g, k>::i;
template <typename> struct l { typedef b ab; };
template <typename p> class aa {
public:
typedef p n;
};
struct r {
template <typename p> using o = typename p::c;
};
template <typename ad> struct u : r {
typedef typename ad::n n;
using ae = m<n, o>;
template <typename af, typename> struct v { using i = typename l<f>::ab; };
using ab = typename v<ad, ae>::i;
};
} // namespace a
namespace q {
template <typename ad> struct w : a::u<ad> {};
} // namespace q
namespace a {
namespace c {
template <typename, typename, typename ad> class e {
typedef q::w<ad> s;
public:
typedef typename s::ab ab;
};
} // namespace c
} // namespace a
namespace ag {
namespace ah {
typedef a::f::ab t;
class ai {
t aj;
};
class al;
namespace am {
class an {
public:
void ao(ai);
};
} // namespace am
class ap {
public:
al aq();
};
class ar {
am::an as;
};
class al {
ar at;
};
struct au {
ap av;
};
} // namespace ah
} // namespace ag
namespace operations_research {
class aw {
ag::ah::au ax;
};
class Solver {
aw ay;
};
} // namespace operations_research
"};
let rs = quote! {};
run_test("", hdr, rs, &["operations_research::Solver"], &[]);
}
#[test]
fn test_unexpected_use() {
let hdr = indoc! {"
typedef int a;
namespace b {
namespace c {
enum d : a;
}
} // namespace b
namespace {
using d = b::c::d;
}
namespace content {
class RenderFrameHost {
public:
RenderFrameHost() {}
d e;
};
} // namespace content
"};
let rs = quote! {
let _ = ffi::content::RenderFrameHost::make_unique();
};
run_test("", hdr, rs, &["content::RenderFrameHost"], &[]);
}
#[test]
fn test_get_pure_virtual() {
let hdr = indoc! {"
#include <cstdint>
class A {
public:
virtual uint32_t get_val() const = 0;
};
class B : public A {
public:
virtual uint32_t get_val() const { return 3; }
};
const B b;
inline const A* get_a() { return &b; };
"};
let rs = quote! {
let a = ffi::get_a();
let a_ref = unsafe { a.as_ref() }.unwrap();
assert_eq!(a_ref.get_val(), 3);
};
run_test("", hdr, rs, &["A", "get_a"], &[]);
}
#[test]
fn test_abstract_class_no_make_unique() {
let hdr = indoc! {"
class A {
public:
A();
virtual void foo() const = 0;
};
"};
let rs = quote! {};
run_test("", hdr, rs, &["A"], &[]);
}
#[test]
fn test_derived_abstract_class_no_make_unique() {
let hdr = indoc! {"
class A {
public:
A();
virtual void foo() const = 0;
};
class B : public A {
public:
B();
};
"};
let rs = quote! {};
run_test("", hdr, rs, &["A", "B"], &[]);
}
#[test]
fn test_recursive_derived_abstract_class_no_make_unique() {
let hdr = indoc! {"
class A {
public:
A() {};
virtual void foo() const = 0;
};
class B : public A {
public:
B() {};
};
class C : public B {
public:
C() {};
};
"};
let rs = quote! {};
run_test("", hdr, rs, &["A", "B", "C"], &[]);
}
#[test]
fn test_derived_abstract_class_with_no_allowlisting_no_make_unique() {
let hdr = indoc! {"
class A {
public:
A();
virtual void foo() const = 0;
};
class B : public A {
public:
B();
};
"};
let rs = quote! {};
run_test("", hdr, rs, &["B"], &[]);
}
#[test]
fn test_vector_of_pointers() {
let hdr = indoc! {"
#include <vector>
namespace operations_research {
class a;
class Solver {
public:
struct b c(std::vector<a *>);
};
class a {};
} // namespace operations_research
"};
let rs = quote! {};
run_test("", hdr, rs, &["operations_research::Solver"], &[]);
}
#[test]
fn test_pointer_to_pointer() {
let hdr = indoc! {"
namespace operations_research {
class a;
class Solver {
public:
struct b c(a **);
};
class a {};
} // namespace operations_research
"};
let rs = quote! {};
run_test("", hdr, rs, &["operations_research::Solver"], &[]);
}
#[test]
fn test_defines_effective() {
let hdr = indoc! {"
#include <cstdint>
#ifdef FOO
inline uint32_t a() { return 4; }
#endif
"};
let rs = quote! {
ffi::a();
};
run_test_ex("", hdr, rs, &["a"], &[], None, &["-DFOO"], None);
}
#[test]
#[ignore] fn test_function_pointer_template() {
let hdr = indoc! {"
typedef int a;
namespace std {
template <typename> class b;
}
typedef a c;
namespace operations_research {
class d;
class Solver {
public:
typedef std::b<c()> IndexEvaluator3;
d e(IndexEvaluator3);
};
class d {};
} // namespace operations_research
"};
let rs = quote! {};
run_test("", hdr, rs, &["operations_research::Solver"], &[]);
}
#[test]
fn test_cvoid() {
let hdr = indoc! {"
#include <memory>
#include <cstdint>
inline void* a() {
return static_cast<void*>(new int(3));
}
inline uint32_t b(void* p) {
int* p_int = static_cast<int*>(p);
auto val = *p_int;
delete p_int;
return val;
}
"};
let rs = quote! {
let ptr = ffi::a();
let res = unsafe { ffi::b(ptr) };
assert_eq!(res, 3);
};
run_test("", hdr, rs, &["a", "b"], &[]);
}
#[test]
fn test_c_schar() {
let hdr = indoc! {"
inline signed char a() {
return 8;
}
"};
let rs = quote! {
assert_eq!(ffi::a(), 8);
};
run_test("", hdr, rs, &["a"], &[]);
}
#[test]
fn test_c_uchar() {
let hdr = indoc! {"
inline unsigned char a() {
return 8;
}
"};
let rs = quote! {
assert_eq!(ffi::a(), 8);
};
run_test("", hdr, rs, &["a"], &[]);
}
#[test]
fn test_c_ulonglong() {
let hdr = indoc! {"
inline unsigned long long a() {
return 8;
}
"};
let rs = quote! {
assert_eq!(ffi::a(), autocxx::c_ulonglong(8));
};
run_test("", hdr, rs, &["a"], &[]);
}
#[test]
fn test_string_transparent_function() {
let hdr = indoc! {"
#include <string>
#include <cstdint>
inline uint32_t take_string(std::string a) { return a.size(); }
"};
let rs = quote! {
assert_eq!(ffi::take_string("hello"), 5);
};
run_test("", hdr, rs, &["take_string"], &[]);
}
#[test]
fn test_string_transparent_method() {
let hdr = indoc! {"
#include <string>
#include <cstdint>
struct A {
A() {}
inline uint32_t take_string(std::string a) const { return a.size(); }
};
"};
let rs = quote! {
let a = ffi::A::make_unique();
assert_eq!(a.take_string("hello"), 5);
};
run_test("", hdr, rs, &["A"], &[]);
}
#[test]
fn test_string_transparent_static_method() {
let hdr = indoc! {"
#include <string>
#include <cstdint>
struct A {
A() {}
static inline uint32_t take_string(std::string a) { return a.size(); }
};
"};
let rs = quote! {
assert_eq!(ffi::A::take_string("hello"), 5);
};
run_test("", hdr, rs, &["A"], &[]);
}
#[test]
#[ignore] fn test_issue_490() {
let hdr = indoc! {"
typedef int a;
typedef long unsigned size_t;
namespace std {
namespace {
using ::size_t;
template <class b, b c> struct g { static const b value = c; };
template <bool d> using e = g<bool, d>;
typedef e<true> true_type;
template <size_t, size_t> struct ag {};
template <class b> typename b ::h move();
template <class> class allocator;
template <class> class vector;
} // namespace
} // namespace std
void *operator new(size_t, void *);
namespace std {
namespace {
template <class> struct iterator;
template <class b, class> struct ay { using h = b *; };
template <class b> struct bj { b bk; };
template <class bm, class> class bn : bj<bm> {};
template <class b, class i = b> class unique_ptr {
typedef i bp;
typedef typename ay<b, bp>::h bh;
bn<bh, bp> bq;
public:
unique_ptr();
unique_ptr(bh);
bh get() const;
bh release();
};
template <class = void> struct bt;
} // namespace
} // namespace std
typedef a bv;
namespace absl {
template <typename ce> class cj {
public:
using bh = ce *;
using iterator = bh;
};
namespace j {
template <class ce> struct cp {
using k = ce;
using cq = std::bt<>;
};
template <class ce> using cr = typename cp<ce>::k;
template <class ce> using cs = typename cp<ce>::cq;
template <class, class, class, class> class ct {
public:
class iterator {};
class cu {
cu(iterator);
iterator cv;
};
};
template <typename> struct cw;
} // namespace j
template <class ce, class k = j::cr<ce>, class cq = j::cs<ce>,
class cx = std::allocator<ce>>
class cy : public j::ct<j::cw<ce>, k, cq, cx> {};
} // namespace absl
namespace cz {
template <typename da> class db { std::ag<sizeof(a), alignof(da)> c; };
} // namespace cz
namespace spanner {
class l;
class ColumnList {
public:
typedef absl::cj<l>::iterator iterator;
iterator begin();
};
class dd {
union {
cz::db<absl::cy<bv>::cu> e;
};
};
class Row {
public:
bool f(dd);
};
} // namespace spanner
"};
let rs = quote! {};
run_test("", hdr, rs, &["spanner::Row", "spanner::ColumnList"], &[]);
}
#[test]
#[ignore] fn test_immovable_object() {
let hdr = indoc! {"
class A {
public:
A();
A(A&&) = delete;
};
class B{
public:
B();
B(const B&) = delete;
};
"};
let rs = quote! {};
run_test("", hdr, rs, &["A", "B"], &[]);
}
#[test]
fn test_type_called_type() {
let hdr = indoc! {"
namespace a {
template<int _Len>
struct b
{
union type
{
unsigned char __data[_Len];
struct foo {
int a;
};
};
};
}
inline void take_type(a::b<4>::type) {}
"};
let rs = quote! {};
run_test("", hdr, rs, &["take_type"], &[]);
}
#[test]
fn test_bridge_conflict_ty() {
let hdr = indoc! {"
namespace a {
struct Key { int a; };
}
namespace b {
struct Key { int a; };
}
"};
let rs = quote! {};
run_test("", hdr, rs, &["a::Key", "b::Key"], &[]);
}
#[test]
fn test_bridge_conflict_ty_fn() {
let hdr = indoc! {"
namespace a {
struct Key { int a; };
}
namespace b {
inline void Key() {}
}
"};
let rs = quote! {};
run_test("", hdr, rs, &["a::Key", "b::Key"], &[]);
}
#[test]
fn test_issue_506() {
let hdr = indoc! {"
namespace std {
template <class, class> class am;
typedef am<char, char> an;
} // namespace std
namespace be {
class bf {
virtual std::an bg() = 0;
};
class bh : bf {};
} // namespace be
namespace spanner {
class Database;
class Row {
public:
Row(be::bh *);
};
} // namespace spanner
"};
let rs = quote! {};
run_test("", hdr, rs, &["spanner::Database", "spanner::Row"], &[]);
}
fn find_ffi_items(f: syn::File) -> Result<Vec<Item>, TestError> {
Ok(f.items
.into_iter()
.filter_map(|i| match i {
Item::Mod(itm) => Some(itm),
_ => None,
})
.next()
.ok_or(TestError::RsCodeExaminationFail)?
.content
.ok_or(TestError::RsCodeExaminationFail)?
.1)
}
fn make_error_finder(error_symbol: &str) -> Box<dyn FnOnce(syn::File) -> Result<(), TestError>> {
let error_symbol = error_symbol.to_string();
Box::new(move |f| {
let ffi_items = find_ffi_items(f)?;
let error_item = ffi_items
.into_iter()
.filter_map(|i| match i {
Item::Struct(its) if its.ident == error_symbol => Some(its),
_ => None,
})
.next()
.ok_or(TestError::RsCodeExaminationFail)?;
error_item
.attrs
.into_iter()
.find(|a| a.path.get_ident().filter(|p| *p == "doc").is_some())
.ok_or(TestError::RsCodeExaminationFail)?;
Ok(())
})
}
#[test]
fn test_error_generated_for_static_data() {
let hdr = indoc! {"
#include <cstdint>
struct A {
A() {}
uint32_t a;
};
static A FOO = A();
"};
let rs = quote! {};
run_test_ex(
"",
hdr,
rs,
&["FOO"],
&[],
None,
&[],
Some(make_error_finder("FOO")),
);
}
#[test]
fn test_error_generated_for_array_dependent_function() {
let hdr = indoc! {"
#include <cstdint>
#include <functional>
inline void take_func(std::function<bool(const uint32_t number)>) {
}
"};
let rs = quote! {};
run_test_ex(
"",
hdr,
rs,
&["take_func"],
&[],
None,
&[],
Some(make_error_finder("take_func")),
);
}
#[test]
fn test_error_generated_for_array_dependent_method() {
let hdr = indoc! {"
#include <cstdint>
#include <functional>
struct A {
void take_func(std::function<bool(const uint32_t number)>) {
}
};
"};
let rs = quote! {};
run_test_ex(
"",
hdr,
rs,
&["A"],
&[],
None,
&[],
Some(make_string_finder(
["take_func", "couldn't be generated"].to_vec(),
)),
);
}
#[test]
fn test_keyword_function() {
let hdr = indoc! {"
inline void move(int a) {};
"};
let rs = quote! {};
run_test("", hdr, rs, &["move_"], &[]);
}
#[test]
fn test_keyword_method() {
let hdr = indoc! {"
struct A {
int a;
inline void move() {};
};
"};
let rs = quote! {};
run_test("", hdr, rs, &["A"], &[]);
}
fn make_string_finder(
error_texts: Vec<&str>,
) -> Box<dyn FnOnce(syn::File) -> Result<(), TestError> + '_> {
Box::new(|f| {
let mut ts = TokenStream::new();
f.to_tokens(&mut ts);
let toks = ts.to_string();
for msg in error_texts {
if !toks.contains(msg) {
return Err(TestError::RsCodeExaminationFail);
};
}
Ok(())
})
}
#[test]
fn test_doc_passthru() {
let hdr = indoc! {"
#include <cstdint>
/// Elephants!
struct A {
uint32_t a;
};
/// Giraffes!
struct B {
uint32_t a;
};
/// Rhinos!
inline uint32_t get_a() { return 3; }
"};
let rs = quote! {};
run_test_ex(
"",
hdr,
rs,
&["A", "get_a"],
&["B"],
None,
&[],
Some(make_string_finder(
["Giraffes", "Elephants", "Rhinos"].to_vec(),
)),
);
}
#[test]
fn test_closure() {
let hdr = indoc! {"
#include <functional>
#include <cstdint>
inline bool take_closure(std::function<bool(const uint32_t number)> fn) {
return fn(5);
}
inline uint32_t get_a() {
return 3;
}
"};
let rs = quote! {
assert_eq!(ffi::get_a(), 3);
};
run_test("", hdr, rs, &["get_a"], &[]);
}
#[test]
fn test_blocklist_not_overly_broad() {
let hdr = indoc! {"
inline void rust_func() { }
inline void std_func() { }
"};
let rs = quote! {
ffi::rust_func();
ffi::std_func();
};
run_test("", hdr, rs, &["rust_func", "std_func"], &[]);
}
#[test]
fn test_stringview() {
let hdr = indoc! {"
#include <string_view>
#include <string>
void take_string_view(std::string_view) {}
std::string_view return_string_view(std::string a) { return std::string_view(a); }
"};
let rs = quote! {};
run_test_ex(
"",
hdr,
rs,
&["take_string_view", "return_string_view"],
&[],
None,
&["-std=c++17"],
None,
);
}
#[test]
fn test_include_cpp_alone() {
let hdr = indoc! {"
#include <cstdint>
inline uint32_t give_int() {
return 5;
}
"};
let rs = |hdr| {
let hexathorpe = Token);
quote! {
use autocxx::include_cpp;
include_cpp! {
#hexathorpe include #hdr
safety!(unsafe_ffi)
generate!("give_int")
}
fn main() {
assert_eq!(ffi::give_int(), 5);
}
}
};
do_run_test_manual("", hdr, rs, &[], None).unwrap();
}
#[test]
fn test_include_cpp_in_path() {
let hdr = indoc! {"
#include <cstdint>
inline uint32_t give_int() {
return 5;
}
"};
let rs = |hdr| {
let hexathorpe = Token);
quote! {
autocxx::include_cpp! {
#hexathorpe include #hdr
safety!(unsafe_ffi)
generate!("give_int")
}
fn main() {
assert_eq!(ffi::give_int(), 5);
}
}
};
do_run_test_manual("", hdr, rs, &[], None).unwrap();
}
#[test]
fn test_cint_vector() {
let hdr = indoc! {"
#include <vector>
#include <cstdint>
inline std::vector<int32_t> give_vec() {
return std::vector<int32_t> {1,2};
}
"};
let rs = quote! {
assert_eq!(ffi::give_vec().as_ref().unwrap().as_slice(), &[1,2]);
};
run_test("", hdr, rs, &["give_vec"], &[]);
}
#[test]
#[ignore] fn test_int_vector() {
let hdr = indoc! {"
#include <vector>
std::vector<int> give_vec() {
return std::vector<int> {1,2};
}
"};
let rs = quote! {
assert_eq!(ffi::give_vec().as_ref().unwrap().as_slice(), &[autocxx::c_int(1),autocxx::c_int(2)]);
};
run_test("", hdr, rs, &["give_vec"], &[]);
}
#[test]
fn test_deleted_function() {
let hdr = indoc! {"
class A {
public:
void foo() = delete;
};
"};
let rs = quote! {};
run_test("", hdr, rs, &["A"], &[]);
}
#[test]
fn test_ignore_move_constructor() {
let hdr = indoc! {"
class A {
public:
A(A&&);
};
"};
let rs = quote! {};
run_test("", hdr, rs, &["A"], &[]);
}
#[test]
fn test_overloaded_ignored_function() {
let hdr = indoc! {"
struct Blocked {};
class A {
public:
void take_blocked(Blocked);
void take_blocked(Blocked, int);
};
"};
let rs = quote! {};
run_test_ex(
"",
hdr,
rs,
&["A"],
&[],
Some(quote! { block!("Blocked") }),
&[],
None,
);
}
#[test]
fn test_namespaced_constant() {
let hdr = indoc! {"
namespace A {
const int kConstant = 3;
}
"};
let rs = quote! {
assert_eq!(ffi::A::kConstant, 3);
};
run_test("", hdr, rs, &["A::kConstant"], &[]);
}
#[test]
fn test_mbstate() {
let hdr = indoc! {"
struct foo_mbstate_t {
int a;
};
inline void bar(foo_mbstate_t) {}
"};
let rs = quote! {};
run_test("", hdr, rs, &["bar"], &[]);
}
#[test]
fn test_issue_470_492() {
let hdr = indoc! {"
namespace std {
template <bool, typename _Iftrue, typename _Iffalse> struct a;
}
template <typename> struct b;
template <typename d> struct c {
typedef std::a<b<d>::c, int, int> e;
};
"};
let rs = quote! {};
run_test_ex(
"",
hdr,
rs,
&[],
&[],
Some(quote! {
generate_all!()
}),
&[],
None,
);
}
#[test]
fn test_no_impl() {
let hdr = indoc! {"
struct A {
int a;
};
"};
let rs = quote! {};
run_test_ex(
"",
hdr,
rs,
&["A"],
&[],
Some(quote! {
exclude_impls!()
exclude_utilities!()
}),
&[],
None,
);
}
#[test]
fn test_generate_all() {
let hdr = indoc! {"
#include <cstdint>
inline uint32_t give_int() {
return 5;
}
"};
let rs = quote! {
assert_eq!(ffi::give_int(), 5);
};
run_test_ex(
"",
hdr,
rs,
&[],
&[],
Some(quote! {
generate_all!()
}),
&[],
None,
);
}
#[test]
fn test_std_thing() {
let hdr = indoc! {"
#include <cstdint>
namespace std {
struct A {
uint8_t a;
};
}
typedef char daft;
"};
let rs = quote! {};
run_test_ex(
"",
hdr,
rs,
&[],
&[],
Some(quote! {
generate_all!()
}),
&[],
None,
);
}
#[test]
fn test_two_mods() {
let hdr = indoc! {"
#include <cstdint>
struct A {
uint32_t a;
};
inline A give_a() {
A a;
a.a = 5;
return a;
}
inline uint32_t get_a(A a) {
return a.a;
}
struct B {
uint32_t a;
};
inline B give_b() {
B a;
a.a = 8;
return a;
}
inline uint32_t get_b(B a) {
return a.a;
}
"};
let rs = |hdr| {
let hexathorpe = Token);
quote! {
autocxx::include_cpp! {
#hexathorpe include #hdr
safety!(unsafe_ffi)
generate!("give_a")
generate!("get_a")
}
autocxx::include_cpp! {
#hexathorpe include #hdr
name!(ffi2)
generate!("give_b")
generate!("get_b")
}
fn main() {
let a = ffi::give_a();
assert_eq!(ffi::get_a(a), 5);
let b = unsafe { ffi2::give_b() };
assert_eq!(unsafe { ffi2::get_b(b) }, 8);
}
}
};
do_run_test_manual("", hdr, rs, &[], None).unwrap();
}
#[test]
fn test_manual_bridge() {
let hdr = indoc! {"
#include <cstdint>
inline uint32_t give_int() {
return 5;
}
inline uint32_t give_int2() {
return 5;
}
"};
let rs = |hdr| {
let hexathorpe = Token);
quote! {
autocxx::include_cpp! {
#hexathorpe include #hdr
safety!(unsafe_ffi)
generate!("give_int")
}
#[cxx::bridge]
mod ffi2 {
unsafe extern "C++" {
include!(#hdr);
fn give_int2() -> u32;
}
}
fn main() {
assert_eq!(ffi::give_int(), 5);
assert_eq!(ffi2::give_int2(), 5);
}
}
};
do_run_test_manual("", hdr, rs, &[], None).unwrap();
}
#[test]
fn test_issue486() {
let hdr = indoc! {"
namespace a {
namespace spanner {
class Key;
}
} // namespace a
namespace spanner {
class Key {
public:
bool b(a::spanner::Key &);
};
} // namespace spanner
"};
let rs = quote! {};
run_test("", hdr, rs, &["spanner::Key"], &[]);
}