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/src/cxx.cc b/src/cxx.cc
index b64333c..916f525 100644
--- a/src/cxx.cc
+++ b/src/cxx.cc
@@ -3,6 +3,7 @@
#include <exception>
#include <iostream>
#include <memory>
+#include <vector>
#include <stdexcept>
template <typename Exception>
@@ -197,3 +198,50 @@
ptr->~unique_ptr();
}
} // extern "C"
+
+#define STD_VECTOR_OPS(RUST_TYPE, CXX_TYPE) \
+extern "C" { \
+size_t cxxbridge02$std$vector$##RUST_TYPE##$length(const std::vector<CXX_TYPE> &s) noexcept { \
+ return s.size(); \
+} \
+void cxxbridge02$std$vector$##RUST_TYPE##$push_back(std::vector<CXX_TYPE> &s, const CXX_TYPE &item) noexcept { \
+ s.push_back(item); \
+} \
+const CXX_TYPE *cxxbridge02$std$vector$##RUST_TYPE##$get_unchecked(const std::vector<CXX_TYPE> &s, size_t pos) noexcept { \
+ return &s[pos]; \
+} \
+static_assert(sizeof(::std::unique_ptr<std::vector<CXX_TYPE>>) == sizeof(void *), ""); \
+static_assert(alignof(::std::unique_ptr<std::vector<CXX_TYPE>>) == alignof(void *), ""); \
+void cxxbridge02$unique_ptr$std$vector$##RUST_TYPE##$null(::std::unique_ptr<std::vector<CXX_TYPE>> *ptr) noexcept { \
+ new (ptr) ::std::unique_ptr<std::vector<CXX_TYPE>>(); \
+} \
+void cxxbridge02$unique_ptr$std$vector$##RUST_TYPE##$new(::std::unique_ptr<std::vector<CXX_TYPE>> *ptr, std::vector<CXX_TYPE> *value) noexcept { \
+ new (ptr) ::std::unique_ptr<std::vector<CXX_TYPE>>(new std::vector<CXX_TYPE>(::std::move(*value))); \
+} \
+void cxxbridge02$unique_ptr$std$vector$##RUST_TYPE##$raw(::std::unique_ptr<std::vector<CXX_TYPE>> *ptr, std::vector<CXX_TYPE> *raw) noexcept { \
+ new (ptr) ::std::unique_ptr<std::vector<CXX_TYPE>>(raw); \
+} \
+const std::vector<CXX_TYPE> *cxxbridge02$unique_ptr$std$vector$##RUST_TYPE##$get(const ::std::unique_ptr<std::vector<CXX_TYPE>>& ptr) noexcept { \
+ return ptr.get(); \
+} \
+std::vector<CXX_TYPE> *cxxbridge02$unique_ptr$std$vector$##RUST_TYPE##$release(::std::unique_ptr<std::vector<CXX_TYPE>>& ptr) noexcept { \
+ return ptr.release(); \
+} \
+void cxxbridge02$unique_ptr$std$vector$##RUST_TYPE##$drop(::std::unique_ptr<std::vector<CXX_TYPE>> *ptr) noexcept { \
+ ptr->~unique_ptr(); \
+} \
+} // extern "C"
+
+STD_VECTOR_OPS(u8, uint8_t);
+STD_VECTOR_OPS(u16, uint16_t);
+STD_VECTOR_OPS(u32, uint32_t);
+STD_VECTOR_OPS(u64, uint64_t);
+STD_VECTOR_OPS(usize, size_t);
+STD_VECTOR_OPS(i8, int8_t);
+STD_VECTOR_OPS(i16, int16_t);
+STD_VECTOR_OPS(i32, int32_t);
+STD_VECTOR_OPS(i64, int64_t);
+STD_VECTOR_OPS(isize, rust::isize);
+STD_VECTOR_OPS(f32, float);
+STD_VECTOR_OPS(f64, double);
+
diff --git a/src/lib.rs b/src/lib.rs
index 74e103a..994c430 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -370,13 +370,18 @@
mod rust_sliceu8;
mod rust_str;
mod rust_string;
+mod rust_vec;
mod syntax;
mod unique_ptr;
mod unwind;
+mod vector;
pub use crate::cxx_string::CxxString;
pub use crate::exception::Exception;
+pub use crate::rust_vec::RustVec;
pub use crate::unique_ptr::UniquePtr;
+pub use crate::vector::RealVector;
+pub use crate::vector::VectorIntoIterator;
pub use cxxbridge_macro::bridge;
// Not public API.
@@ -390,6 +395,7 @@
pub use crate::rust_string::RustString;
pub use crate::unique_ptr::UniquePtrTarget;
pub use crate::unwind::catch_unwind;
+ pub use crate::vector::VectorTarget;
}
use crate::error::Result;
diff --git a/src/rust_vec.rs b/src/rust_vec.rs
new file mode 100644
index 0000000..a28570d
--- /dev/null
+++ b/src/rust_vec.rs
@@ -0,0 +1,39 @@
+use crate::vector::RealVector;
+use crate::vector::VectorTarget;
+
+#[repr(C)]
+pub struct RustVec<T: VectorTarget<T>> {
+ repr: Vec<T>,
+}
+
+impl<T: VectorTarget<T>> RustVec<T> {
+ pub fn from(v: Vec<T>) -> Self {
+ RustVec { repr: v }
+ }
+
+ pub fn from_ref(v: &Vec<T>) -> &Self {
+ unsafe { std::mem::transmute::<&Vec<T>, &RustVec<T>>(v) }
+ }
+
+ pub fn into_vec(self) -> Vec<T> {
+ self.repr
+ }
+
+ pub fn as_vec(&self) -> &Vec<T> {
+ &self.repr
+ }
+
+ pub fn as_mut_vec(&mut self) -> &mut Vec<T> {
+ &mut self.repr
+ }
+
+ pub fn len(&self) -> usize {
+ self.repr.len()
+ }
+
+ pub fn into_vector(&self, vec: &mut RealVector<T>) {
+ for item in &self.repr {
+ vec.push_back(item);
+ }
+ }
+}
diff --git a/src/vector.rs b/src/vector.rs
new file mode 100644
index 0000000..805bdbb
--- /dev/null
+++ b/src/vector.rs
@@ -0,0 +1,91 @@
+pub trait VectorTarget<T> {
+ fn get_unchecked(v: &RealVector<T>, pos: usize) -> &T
+ where
+ Self: Sized;
+ fn vector_length(v: &RealVector<T>) -> usize
+ where
+ Self: Sized;
+ fn push_back(v: &RealVector<T>, item: &T)
+ where
+ Self: Sized;
+}
+
+/// Binding to C++ `std::vector`.
+///
+/// # Invariants
+///
+/// As an invariant of this API and the static analysis of the cxx::bridge
+/// macro, in Rust code we can never obtain a `Vector` by value. C++'s vector
+/// requires a move constructor and may hold internal pointers, which is not
+/// compatible with Rust's move behavior. Instead in Rust code we will only ever
+/// look at a Vector through a reference or smart pointer, as in `&Vector`
+/// or `UniquePtr<Vector>`.
+#[repr(C)]
+pub struct RealVector<T> {
+ _private: [T; 0],
+}
+
+impl<T: VectorTarget<T>> RealVector<T> {
+ /// Returns the length of the vector in bytes.
+ pub fn size(&self) -> usize {
+ T::vector_length(self)
+ }
+
+ pub fn get_unchecked(&self, pos: usize) -> &T {
+ T::get_unchecked(self, pos)
+ }
+
+ /// Returns true if `self` has a length of zero bytes.
+ pub fn is_empty(&self) -> bool {
+ self.size() == 0
+ }
+
+ pub fn get(&self, pos: usize) -> Option<&T> {
+ if pos < self.size() {
+ Some(self.get_unchecked(pos))
+ } else {
+ None
+ }
+ }
+
+ pub fn push_back(&mut self, item: &T) {
+ T::push_back(self, item);
+ }
+}
+
+unsafe impl<T> Send for RealVector<T> where T: Send + VectorTarget<T> {}
+
+pub struct VectorIntoIterator<'a, T> {
+ v: &'a RealVector<T>,
+ index: usize,
+}
+
+impl<'a, T: VectorTarget<T>> IntoIterator for &'a RealVector<T> {
+ type Item = &'a T;
+ type IntoIter = VectorIntoIterator<'a, T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ VectorIntoIterator { v: self, index: 0 }
+ }
+}
+
+impl<'a, T: VectorTarget<T>> Iterator for VectorIntoIterator<'a, T> {
+ type Item = &'a T;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.index = self.index + 1;
+ self.v.get(self.index - 1)
+ }
+}
+
+cxxbridge_macro::vector_builtin!(u8);
+cxxbridge_macro::vector_builtin!(u16);
+cxxbridge_macro::vector_builtin!(u32);
+cxxbridge_macro::vector_builtin!(u64);
+cxxbridge_macro::vector_builtin!(usize);
+cxxbridge_macro::vector_builtin!(i8);
+cxxbridge_macro::vector_builtin!(i16);
+cxxbridge_macro::vector_builtin!(i32);
+cxxbridge_macro::vector_builtin!(i64);
+cxxbridge_macro::vector_builtin!(isize);
+cxxbridge_macro::vector_builtin!(f32);
+cxxbridge_macro::vector_builtin!(f64);