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/syntax/atom.rs b/syntax/atom.rs
index eeea831..c68b3fe 100644
--- a/syntax/atom.rs
+++ b/syntax/atom.rs
@@ -42,6 +42,43 @@
_ => None,
}
}
+
+ pub fn to_cxx(&self) -> &'static str {
+ use self::Atom::*;
+ match self {
+ Bool => "bool",
+ U8 => "uint8_t",
+ U16 => "uint16_t",
+ U32 => "uint32_t",
+ U64 => "uint64_t",
+ Usize => "size_t",
+ I8 => "int8_t",
+ I16 => "int16_t",
+ I32 => "int32_t",
+ I64 => "int64_t",
+ Isize => "::rust::isize",
+ F32 => "float",
+ F64 => "double",
+ CxxString => "::std::string",
+ RustString => "::rust::String",
+ }
+ }
+
+ pub fn is_valid_vector_target(&self) -> bool {
+ use self::Atom::*;
+ *self == U8
+ || *self == U16
+ || *self == U32
+ || *self == U64
+ || *self == Usize
+ || *self == I8
+ || *self == I16
+ || *self == I32
+ || *self == I64
+ || *self == Isize
+ || *self == F32
+ || *self == F64
+ }
}
impl PartialEq<Atom> for Ident {
diff --git a/syntax/check.rs b/syntax/check.rs
index 5e8cc09..387f9a6 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -29,7 +29,9 @@
match ty {
Type::Ident(ident) => check_type_ident(cx, ident),
Type::RustBox(ptr) => check_type_box(cx, ptr),
+ Type::RustVec(ptr) => check_type_vec(cx, ptr),
Type::UniquePtr(ptr) => check_type_unique_ptr(cx, ptr),
+ Type::Vector(ptr) => check_type_vector(cx, ptr),
Type::Ref(ty) => check_type_ref(cx, ty),
Type::Slice(ty) => check_type_slice(cx, ty),
_ => {}
@@ -87,6 +89,21 @@
cx.error(ptr, "unsupported target type of Box");
}
+fn check_type_vec(cx: &mut Check, ptr: &Ty1) {
+ // Vec can contain either user-defined type or u8
+ if let Type::Ident(ident) = &ptr.inner {
+ if Atom::from(ident).map(|a| a.is_valid_vector_target()) == Some(true) {
+ return;
+ } else if cx.types.cxx.contains(ident) {
+ cx.error(ptr, error::VEC_CXX_TYPE.msg);
+ } else {
+ return;
+ }
+ }
+
+ cx.error(ptr, "unsupported target type of Vec");
+}
+
fn check_type_unique_ptr(cx: &mut Check, ptr: &Ty1) {
if let Type::Ident(ident) = &ptr.inner {
if cx.types.rust.contains(ident) {
@@ -97,11 +114,31 @@
None | Some(CxxString) => return,
_ => {}
}
+ } else if let Type::Vector(_) = &ptr.inner {
+ return;
}
cx.error(ptr, "unsupported unique_ptr target type");
}
+fn check_type_vector(cx: &mut Check, ptr: &Ty1) {
+ if let Type::Ident(ident) = &ptr.inner {
+ if cx.types.rust.contains(ident) {
+ cx.error(ptr, "vector of a Rust type is not supported yet");
+ }
+
+ match Atom::from(ident) {
+ None => return,
+ Some(atom) => {
+ if atom.is_valid_vector_target() {
+ return;
+ }
+ }
+ }
+ }
+ cx.error(ptr, "unsupported vector target type");
+}
+
fn check_type_ref(cx: &mut Check, ty: &Ref) {
if ty.lifetime.is_some() {
cx.error(ty, "references with explicit lifetimes are not supported");
@@ -310,9 +347,11 @@
}
}
Type::RustBox(_) => "Box".to_owned(),
+ Type::RustVec(_) => "Vec".to_owned(),
Type::UniquePtr(_) => "unique_ptr".to_owned(),
Type::Ref(_) => "reference".to_owned(),
Type::Str(_) => "&str".to_owned(),
+ Type::Vector(_) => "vector".to_owned(),
Type::Slice(_) => "slice".to_owned(),
Type::SliceRefU8(_) => "&[u8]".to_owned(),
Type::Fn(_) => "function pointer".to_owned(),
diff --git a/syntax/error.rs b/syntax/error.rs
index f52d651..103a54f 100644
--- a/syntax/error.rs
+++ b/syntax/error.rs
@@ -15,6 +15,7 @@
pub static ERRORS: &[Error] = &[
BOX_CXX_TYPE,
+ VEC_CXX_TYPE,
CXXBRIDGE_RESERVED,
CXX_STRING_BY_VALUE,
CXX_TYPE_BY_VALUE,
@@ -29,6 +30,12 @@
note: Some("hint: use UniquePtr<>"),
};
+pub static VEC_CXX_TYPE: Error = Error {
+ msg: "Vec of a C++ type is not supported yet",
+ label: None,
+ note: Some("hint: use UniquePtr<>"),
+};
+
pub static CXXBRIDGE_RESERVED: Error = Error {
msg: "identifiers starting with cxxbridge are reserved",
label: Some("reserved identifier"),
diff --git a/syntax/impls.rs b/syntax/impls.rs
index a2ce05b..8e94f06 100644
--- a/syntax/impls.rs
+++ b/syntax/impls.rs
@@ -26,6 +26,8 @@
Type::UniquePtr(t) => t.hash(state),
Type::Ref(t) => t.hash(state),
Type::Str(t) => t.hash(state),
+ Type::RustVec(t) => t.hash(state),
+ Type::Vector(t) => t.hash(state),
Type::Fn(t) => t.hash(state),
Type::Slice(t) => t.hash(state),
Type::SliceRefU8(t) => t.hash(state),
@@ -44,6 +46,8 @@
(Type::UniquePtr(lhs), Type::UniquePtr(rhs)) => lhs == rhs,
(Type::Ref(lhs), Type::Ref(rhs)) => lhs == rhs,
(Type::Str(lhs), Type::Str(rhs)) => lhs == rhs,
+ (Type::RustVec(lhs), Type::RustVec(rhs)) => lhs == rhs,
+ (Type::Vector(lhs), Type::Vector(rhs)) => lhs == rhs,
(Type::Fn(lhs), Type::Fn(rhs)) => lhs == rhs,
(Type::Slice(lhs), Type::Slice(rhs)) => lhs == rhs,
(Type::SliceRefU8(lhs), Type::SliceRefU8(rhs)) => lhs == rhs,
diff --git a/syntax/mangled.rs b/syntax/mangled.rs
new file mode 100644
index 0000000..56e8b73
--- /dev/null
+++ b/syntax/mangled.rs
@@ -0,0 +1,30 @@
+use crate::syntax::{Atom, Type};
+
+pub trait ToMangled {
+ fn to_mangled(&self, namespace: &Vec<String>) -> String;
+}
+
+impl ToMangled for Type {
+ fn to_mangled(&self, namespace: &Vec<String>) -> String {
+ match self {
+ Type::Ident(ident) => {
+ let mut instance = 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 namespace {
+ instance += name;
+ instance += "$";
+ }
+ }
+ instance += &ident.to_string();
+ instance
+ }
+ Type::RustBox(ptr) => format!("rust_box${}", ptr.inner.to_mangled(namespace)),
+ Type::RustVec(ptr) => format!("rust_vec${}", ptr.inner.to_mangled(namespace)),
+ Type::UniquePtr(ptr) => format!("std$unique_ptr${}", ptr.inner.to_mangled(namespace)),
+ Type::Vector(ptr) => format!("std$vector${}", ptr.inner.to_mangled(namespace)),
+ _ => unimplemented!(),
+ }
+ }
+}
diff --git a/syntax/mod.rs b/syntax/mod.rs
index ab5cecc..4e0b908 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -8,11 +8,13 @@
pub mod ident;
mod impls;
pub mod mangle;
+pub mod mangled;
pub mod namespace;
mod parse;
pub mod set;
pub mod symbol;
mod tokens;
+pub mod typename;
pub mod types;
use self::parse::kw;
@@ -86,9 +88,11 @@
pub enum Type {
Ident(Ident),
RustBox(Box<Ty1>),
+ RustVec(Box<Ty1>),
UniquePtr(Box<Ty1>),
Ref(Box<Ref>),
Str(Box<Ref>),
+ Vector(Box<Ty1>),
Fn(Box<Signature>),
Void(Span),
Slice(Box<Slice>),
diff --git a/syntax/namespace.rs b/syntax/namespace.rs
index d26bb9e..a4e972b 100644
--- a/syntax/namespace.rs
+++ b/syntax/namespace.rs
@@ -11,7 +11,7 @@
#[derive(Clone)]
pub struct Namespace {
- segments: Vec<String>,
+ pub segments: Vec<String>,
}
impl Namespace {
diff --git a/syntax/parse.rs b/syntax/parse.rs
index 7d92b1b..f5c598d 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -300,6 +300,16 @@
rangle: generic.gt_token,
})));
}
+ } else if ident == "Vector" && generic.args.len() == 1 {
+ if let GenericArgument::Type(arg) = &generic.args[0] {
+ let inner = parse_type(arg)?;
+ return Ok(Type::Vector(Box::new(Ty1 {
+ name: ident,
+ langle: generic.lt_token,
+ inner,
+ rangle: generic.gt_token,
+ })));
+ }
} else if ident == "Box" && generic.args.len() == 1 {
if let GenericArgument::Type(arg) = &generic.args[0] {
let inner = parse_type(arg)?;
@@ -310,6 +320,16 @@
rangle: generic.gt_token,
})));
}
+ } else if ident == "Vec" && generic.args.len() == 1 {
+ if let GenericArgument::Type(arg) = &generic.args[0] {
+ let inner = parse_type(arg)?;
+ return Ok(Type::RustVec(Box::new(Ty1 {
+ name: ident,
+ langle: generic.lt_token,
+ inner,
+ rangle: generic.gt_token,
+ })));
+ }
}
}
PathArguments::Parenthesized(_) => {}
diff --git a/syntax/tokens.rs b/syntax/tokens.rs
index 26bb3d1..3d67a0a 100644
--- a/syntax/tokens.rs
+++ b/syntax/tokens.rs
@@ -14,7 +14,9 @@
}
ident.to_tokens(tokens);
}
- Type::RustBox(ty) | Type::UniquePtr(ty) => ty.to_tokens(tokens),
+ Type::RustBox(ty) | Type::UniquePtr(ty) | Type::Vector(ty) | Type::RustVec(ty) => {
+ ty.to_tokens(tokens)
+ }
Type::Ref(r) | Type::Str(r) | Type::SliceRefU8(r) => r.to_tokens(tokens),
Type::Slice(s) => s.to_tokens(tokens),
Type::Fn(f) => f.to_tokens(tokens),
@@ -33,7 +35,8 @@
impl ToTokens for Ty1 {
fn to_tokens(&self, tokens: &mut TokenStream) {
- if self.name == "UniquePtr" {
+ // Do not add cxx namespace to Vector since we're defining it in the user crate
+ if self.name == "UniquePtr" || self.name == "RustVec" {
let span = self.name.span();
tokens.extend(quote_spanned!(span=> ::cxx::));
}
diff --git a/syntax/typename.rs b/syntax/typename.rs
new file mode 100644
index 0000000..883e1fb
--- /dev/null
+++ b/syntax/typename.rs
@@ -0,0 +1,36 @@
+use crate::syntax::{Atom, Type};
+
+pub trait ToTypename {
+ fn to_typename(&self, namespace: &Vec<String>) -> String;
+}
+
+impl ToTypename for Type {
+ fn to_typename(&self, namespace: &Vec<String>) -> String {
+ match self {
+ Type::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 namespace {
+ inner += name;
+ inner += "::";
+ }
+ }
+ if let Some(ti) = Atom::from(ident) {
+ inner += ti.to_cxx();
+ } else {
+ inner += &ident.to_string();
+ };
+ inner
+ }
+ Type::RustBox(ptr) => format!("rust_box<{}>", ptr.inner.to_typename(namespace)),
+ Type::RustVec(ptr) => format!("rust_vec<{}>", ptr.inner.to_typename(namespace)),
+ Type::UniquePtr(ptr) => {
+ format!("std::unique_ptr<{}>", ptr.inner.to_typename(namespace))
+ }
+ Type::Vector(ptr) => format!("std::vector<{}>", ptr.inner.to_typename(namespace)),
+ _ => unimplemented!(),
+ }
+ }
+}
diff --git a/syntax/types.rs b/syntax/types.rs
index 6f3af09..7bce154 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -24,7 +24,9 @@
all.insert(ty);
match ty {
Type::Ident(_) | Type::Str(_) | Type::Void(_) | Type::SliceRefU8(_) => {}
- Type::RustBox(ty) | Type::UniquePtr(ty) => visit(all, &ty.inner),
+ Type::RustBox(ty) | Type::UniquePtr(ty) | Type::Vector(ty) | Type::RustVec(ty) => {
+ visit(all, &ty.inner)
+ }
Type::Ref(r) => visit(all, &r.inner),
Type::Slice(s) => visit(all, &s.inner),
Type::Fn(f) => {