C++ std::vector<T> and Rust std::vec::Vec<T> support
Add basic std::vector and std::vec::Vec support across FFI boundary.
diff --git a/gen/write.rs b/gen/write.rs
index a8e3fd4..a74833f 100644
--- a/gen/write.rs
+++ b/gen/write.rs
@@ -1,8 +1,10 @@
use crate::gen::out::OutFile;
use crate::gen::{include, Opt};
use crate::syntax::atom::Atom::{self, *};
+use crate::syntax::mangled::ToMangled;
use crate::syntax::namespace::Namespace;
use crate::syntax::symbol::Symbol;
+use crate::syntax::typename::ToTypename;
use crate::syntax::{mangle, Api, ExternFn, ExternType, Signature, Struct, Type, Types, Var};
use proc_macro2::Ident;
use std::collections::HashMap;
@@ -42,7 +44,7 @@
Api::Struct(strct) => write_struct_decl(out, &strct.ident),
Api::CxxType(ety) => write_struct_using(out, &ety.ident),
Api::RustType(ety) => write_struct_decl(out, &ety.ident),
- _ => {}
+ _ => (),
}
}
@@ -123,8 +125,9 @@
},
Type::RustBox(_) => out.include.type_traits = true,
Type::UniquePtr(_) => out.include.memory = true,
+ Type::Vector(_) => out.include.vector = true,
Type::SliceRefU8(_) => out.include.cstdint = true,
- _ => {}
+ _ => (),
}
}
}
@@ -134,14 +137,18 @@
let mut needs_rust_str = false;
let mut needs_rust_slice = false;
let mut needs_rust_box = false;
+ let mut needs_rust_vec = false;
let mut needs_rust_fn = false;
- let mut needs_rust_isize = false;
for ty in types {
match ty {
Type::RustBox(_) => {
out.include.type_traits = true;
needs_rust_box = true;
}
+ Type::RustVec(_) => {
+ out.include.type_traits = true;
+ needs_rust_vec = true;
+ }
Type::Str(_) => {
out.include.cstdint = true;
out.include.string = true;
@@ -153,10 +160,6 @@
Type::Slice(_) | Type::SliceRefU8(_) => {
needs_rust_slice = true;
}
- ty if ty == Isize => {
- out.include.base_tsd = true;
- needs_rust_isize = true;
- }
ty if ty == RustString => {
out.include.array = true;
out.include.cstdint = true;
@@ -213,9 +216,9 @@
|| needs_rust_str
|| needs_rust_slice
|| needs_rust_box
+ || needs_rust_vec
|| needs_rust_fn
|| needs_rust_error
- || needs_rust_isize
|| needs_unsafe_bitcopy
|| needs_manually_drop
|| needs_maybe_uninit
@@ -233,9 +236,9 @@
write_header_section(out, needs_rust_str, "CXXBRIDGE02_RUST_STR");
write_header_section(out, needs_rust_slice, "CXXBRIDGE02_RUST_SLICE");
write_header_section(out, needs_rust_box, "CXXBRIDGE02_RUST_BOX");
+ write_header_section(out, needs_rust_vec, "CXXBRIDGE02_RUST_VEC");
write_header_section(out, needs_rust_fn, "CXXBRIDGE02_RUST_FN");
write_header_section(out, needs_rust_error, "CXXBRIDGE02_RUST_ERROR");
- write_header_section(out, needs_rust_isize, "CXXBRIDGE02_RUST_ISIZE");
write_header_section(out, needs_unsafe_bitcopy, "CXXBRIDGE02_RUST_BITCOPY");
if needs_manually_drop {
@@ -469,6 +472,10 @@
match &efn.ret {
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
+ Some(Type::Vector(_)) => write!(
+ out,
+ " /* Use RVO to convert to r-value and move construct */"
+ ),
Some(Type::Str(_)) | Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, ")"),
_ => {}
}
@@ -779,7 +786,7 @@
fn write_extern_arg(out: &mut OutFile, arg: &Var, types: &Types) {
match &arg.ty {
- Type::RustBox(ty) | Type::UniquePtr(ty) => {
+ Type::RustBox(ty) | Type::UniquePtr(ty) | Type::Vector(ty) => {
write_type_space(out, &ty.inner);
write!(out, "*");
}
@@ -796,21 +803,7 @@
fn write_type(out: &mut OutFile, ty: &Type) {
match ty {
Type::Ident(ident) => match Atom::from(ident) {
- Some(Bool) => write!(out, "bool"),
- Some(U8) => write!(out, "uint8_t"),
- Some(U16) => write!(out, "uint16_t"),
- Some(U32) => write!(out, "uint32_t"),
- Some(U64) => write!(out, "uint64_t"),
- Some(Usize) => write!(out, "size_t"),
- Some(I8) => write!(out, "int8_t"),
- Some(I16) => write!(out, "int16_t"),
- Some(I32) => write!(out, "int32_t"),
- Some(I64) => write!(out, "int64_t"),
- Some(Isize) => write!(out, "::rust::isize"),
- Some(F32) => write!(out, "float"),
- Some(F64) => write!(out, "double"),
- Some(CxxString) => write!(out, "::std::string"),
- Some(RustString) => write!(out, "::rust::String"),
+ Some(a) => write!(out, "{}", a.to_cxx()),
None => write!(out, "{}", ident),
},
Type::RustBox(ty) => {
@@ -818,11 +811,21 @@
write_type(out, &ty.inner);
write!(out, ">");
}
+ Type::RustVec(ty) => {
+ write!(out, "::rust::Vec<");
+ write_type(out, &ty.inner);
+ write!(out, ">");
+ }
Type::UniquePtr(ptr) => {
write!(out, "::std::unique_ptr<");
write_type(out, &ptr.inner);
write!(out, ">");
}
+ Type::Vector(ty) => {
+ write!(out, "::std::vector<");
+ write_type(out, &ty.inner);
+ write!(out, ">");
+ }
Type::Ref(r) => {
if r.mutability.is_none() {
write!(out, "const ");
@@ -870,6 +873,8 @@
| Type::RustBox(_)
| Type::UniquePtr(_)
| Type::Str(_)
+ | Type::Vector(_)
+ | Type::RustVec(_)
| Type::SliceRefU8(_)
| Type::Fn(_) => write!(out, " "),
Type::Ref(_) => {}
@@ -882,6 +887,11 @@
Atom::from(ident).is_none()
}
+ fn allow_vector(ident: &Ident) -> bool {
+ // Note: built-in types such as u8 are already defined in cxx.cc
+ Atom::from(ident).is_none()
+ }
+
out.begin_block("extern \"C\"");
for ty in types {
if let Type::RustBox(ty) = ty {
@@ -889,11 +899,30 @@
out.next_section();
write_rust_box_extern(out, inner);
}
+ } else if let Type::RustVec(ty) = ty {
+ if let Type::Ident(_) = &ty.inner {
+ out.next_section();
+ write_rust_vec_extern(out, &ty.inner);
+ }
} else if let Type::UniquePtr(ptr) = ty {
if let Type::Ident(inner) = &ptr.inner {
if allow_unique_ptr(inner) {
out.next_section();
- write_unique_ptr(out, inner, types);
+ write_unique_ptr(out, &ptr.inner, types);
+ }
+ } else if let Type::Vector(ptr1) = &ptr.inner {
+ if let Type::Ident(inner) = &ptr1.inner {
+ if allow_vector(inner) {
+ out.next_section();
+ write_unique_ptr(out, &ptr.inner, types);
+ }
+ }
+ }
+ } else if let Type::Vector(ptr) = ty {
+ if let Type::Ident(inner) = &ptr.inner {
+ if allow_vector(inner) {
+ out.next_section();
+ write_vector(out, inner);
}
}
}
@@ -907,6 +936,10 @@
if let Type::Ident(inner) = &ty.inner {
write_rust_box_impl(out, inner);
}
+ } else if let Type::RustVec(ty) = ty {
+ if let Type::Ident(_) = &ty.inner {
+ write_rust_vec_impl(out, &ty.inner);
+ }
}
}
out.end_block("namespace cxxbridge02");
@@ -937,6 +970,31 @@
writeln!(out, "#endif // CXXBRIDGE02_RUST_BOX_{}", instance);
}
+fn write_rust_vec_extern(out: &mut OutFile, ty: &Type) {
+ let namespace = out.namespace.iter().cloned().collect::<Vec<String>>();
+ let inner = ty.to_typename(&namespace);
+ let instance = ty.to_mangled(&namespace);
+
+ writeln!(out, "#ifndef CXXBRIDGE02_RUST_VEC_{}", instance);
+ writeln!(out, "#define CXXBRIDGE02_RUST_VEC_{}", instance);
+ writeln!(
+ out,
+ "void cxxbridge02$rust_vec${}$drop(::rust::Vec<{}> *ptr) noexcept;",
+ instance, inner,
+ );
+ writeln!(
+ out,
+ "void cxxbridge02$rust_vec${}$vector_from(const ::rust::Vec<{}> *ptr, const std::vector<{}> &vector) noexcept;",
+ instance, inner, inner
+ );
+ writeln!(
+ out,
+ "size_t cxxbridge02$rust_vec${}$len(const ::rust::Vec<{}> *ptr) noexcept;",
+ instance, inner,
+ );
+ writeln!(out, "#endif // CXXBRIDGE02_RUST_VEC_{}", instance);
+}
+
fn write_rust_box_impl(out: &mut OutFile, ident: &Ident) {
let mut inner = String::new();
for name in &out.namespace {
@@ -957,16 +1015,44 @@
writeln!(out, "}}");
}
-fn write_unique_ptr(out: &mut OutFile, ident: &Ident, types: &Types) {
- out.include.utility = true;
+fn write_rust_vec_impl(out: &mut OutFile, ty: &Type) {
+ let namespace = out.namespace.iter().cloned().collect::<Vec<String>>();
+ let inner = ty.to_typename(&namespace);
+ let instance = ty.to_mangled(&namespace);
- let mut inner = String::new();
- for name in &out.namespace {
- inner += name;
- inner += "::";
- }
- inner += &ident.to_string();
- let instance = inner.replace("::", "$");
+ writeln!(out, "template <>");
+ writeln!(out, "void Vec<{}>::drop() noexcept {{", inner);
+ writeln!(
+ out,
+ " return cxxbridge02$rust_vec${}$drop(this);",
+ instance
+ );
+ writeln!(out, "}}");
+
+ writeln!(out, "template <>");
+ writeln!(out, "size_t Vec<{}>::size() const noexcept {{", inner);
+ writeln!(out, " return cxxbridge02$rust_vec${}$len(this);", instance);
+ writeln!(out, "}}");
+
+ writeln!(out, "template <>");
+ writeln!(
+ out,
+ "Vec<{}>::operator std::vector<{}>() const noexcept {{",
+ inner, inner
+ );
+ writeln!(
+ out,
+ " std::vector<{}> v; v.reserve(this->size()); cxxbridge02$rust_vec${}$vector_from(this, v); return v;",
+ inner, instance,
+ );
+ writeln!(out, "}}");
+}
+
+fn write_unique_ptr(out: &mut OutFile, ty: &Type, types: &Types) {
+ out.include.utility = true;
+ let namespace = out.namespace.iter().cloned().collect::<Vec<String>>();
+ let inner = ty.to_typename(&namespace);
+ let instance = ty.to_mangled(&namespace);
writeln!(out, "#ifndef CXXBRIDGE02_UNIQUE_PTR_{}", instance);
writeln!(out, "#define CXXBRIDGE02_UNIQUE_PTR_{}", instance);
@@ -987,18 +1073,21 @@
);
writeln!(out, " new (ptr) ::std::unique_ptr<{}>();", inner);
writeln!(out, "}}");
- if types.structs.contains_key(ident) {
- writeln!(
+ match ty {
+ Type::Ident(ident) if types.structs.contains_key(ident) => {
+ writeln!(
out,
"void cxxbridge02$unique_ptr${}$new(::std::unique_ptr<{}> *ptr, {} *value) noexcept {{",
instance, inner, inner,
);
- writeln!(
- out,
- " new (ptr) ::std::unique_ptr<{}>(new {}(::std::move(*value)));",
- inner, inner,
- );
- writeln!(out, "}}");
+ writeln!(
+ out,
+ " new (ptr) ::std::unique_ptr<{}>(new {}(::std::move(*value)));",
+ inner, inner,
+ );
+ writeln!(out, "}}");
+ }
+ _ => (),
}
writeln!(
out,
@@ -1030,3 +1119,50 @@
writeln!(out, "}}");
writeln!(out, "#endif // CXXBRIDGE02_UNIQUE_PTR_{}", instance);
}
+
+fn write_vector(out: &mut OutFile, ident: &Ident) {
+ let mut inner = String::new();
+ // Do not apply namespace to built-in type
+ let is_user_type = Atom::from(ident).is_none();
+ if is_user_type {
+ for name in &out.namespace {
+ inner += name;
+ inner += "::";
+ }
+ }
+ let mut instance = inner.clone();
+ if let Some(ti) = Atom::from(ident) {
+ inner += ti.to_cxx();
+ } else {
+ inner += &ident.to_string();
+ };
+ instance += &ident.to_string();
+ let instance = instance.replace("::", "$");
+
+ writeln!(out, "#ifndef CXXBRIDGE02_vector_{}", instance);
+ writeln!(out, "#define CXXBRIDGE02_vector_{}", instance);
+ writeln!(
+ out,
+ "size_t cxxbridge02$std$vector${}$length(const std::vector<{}> &s) noexcept {{",
+ instance, inner,
+ );
+ writeln!(out, " return s.size();");
+ writeln!(out, "}}");
+
+ writeln!(
+ out,
+ "void cxxbridge02$std$vector${}$push_back(std::vector<{}> &s, const {} &item) noexcept {{",
+ instance, inner, inner
+ );
+ writeln!(out, " s.push_back(item);");
+ writeln!(out, "}}");
+
+ writeln!(
+ out,
+ "const {} *cxxbridge02$std$vector${}$get_unchecked(const std::vector<{}> &s, size_t pos) noexcept {{",
+ inner, instance, inner,
+ );
+ writeln!(out, " return &s[pos];");
+ writeln!(out, "}}");
+ writeln!(out, "#endif // CXXBRIDGE02_vector_{}", instance);
+}