Repository: dtolnay/cxx
Pull request #1262 (2023-08-25 17:45:00)

Add CxxVector::new for creating an empty vector
When constructing a CxxVector to pass to C++, you have to end up writing your own utility function that constructs a `UniquePtr<CxxVector<...>>` and add that to your projects cxx bridge. Creating an empty vector seems like a simple enough task to afford having an API for it on `CxxVector`.


Patch:
diff --git a/gen/src/write.rs b/gen/src/write.rs
index 2acb9043..32942ab9 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -1671,6 +1671,7 @@ fn write_unique_ptr_common(out: &mut OutFile, ty: UniquePtr) {
         "static_assert(alignof(::std::unique_ptr<{}>) == alignof(void *), \"\");",
         inner,
     );
+
     begin_function_definition(out);
     writeln!(
         out,
@@ -1679,6 +1680,7 @@ fn write_unique_ptr_common(out: &mut OutFile, ty: UniquePtr) {
     );
     writeln!(out, "  ::new (ptr) ::std::unique_ptr<{}>();", inner);
     writeln!(out, "}}");
+
     if can_construct_from_value {
         out.builtin.maybe_uninit = true;
         begin_function_definition(out);
@@ -1926,6 +1928,20 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) {
         writeln!(out, "}}");
     }
 
+    let ty = UniquePtr::CxxVector(element);
+
     out.include.memory = true;
-    write_unique_ptr_common(out, UniquePtr::CxxVector(element));
+    write_unique_ptr_common(out, ty);
+
+    let inner = ty.to_typename(out.types);
+    let instance = ty.to_mangled(out.types);
+
+    begin_function_definition(out);
+    writeln!(
+        out,
+        "{} *cxxbridge1$unique_ptr${}$new() noexcept {{",
+        inner, instance,
+    );
+    writeln!(out, "  return new {}();", inner);
+    writeln!(out, "}}");
 }
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 005d607f..9f605bd3 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -1622,6 +1622,7 @@ fn expand_cxx_vector(
         resolve.name.to_symbol(),
     );
     let link_unique_ptr_null = format!("{}null", unique_ptr_prefix);
+    let link_unique_ptr_new = format!("{}new", unique_ptr_prefix);
     let link_unique_ptr_raw = format!("{}raw", unique_ptr_prefix);
     let link_unique_ptr_get = format!("{}get", unique_ptr_prefix);
     let link_unique_ptr_release = format!("{}release", unique_ptr_prefix);
@@ -1699,6 +1700,13 @@ fn expand_cxx_vector(
                 unsafe { __unique_ptr_null(&mut repr) }
                 repr
             }
+            fn __unique_ptr_new() -> *mut ::cxx::CxxVector<Self> {
+                extern "C" {
+                    #[link_name = #link_unique_ptr_new]
+                    fn __unique_ptr_new #impl_generics() -> *mut ::cxx::CxxVector<#elem #ty_generics>;
+                }
+                unsafe { __unique_ptr_new() }
+            }
             unsafe fn __unique_ptr_raw(raw: *mut ::cxx::CxxVector<Self>) -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
                 extern "C" {
                     #[link_name = #link_unique_ptr_raw]
diff --git a/src/cxx.cc b/src/cxx.cc
index 70ebc0b1..8c361c08 100644
--- a/src/cxx.cc
+++ b/src/cxx.cc
@@ -605,6 +605,10 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *),
       std::unique_ptr<std::vector<CXX_TYPE>> *ptr) noexcept {                  \
     new (ptr) std::unique_ptr<std::vector<CXX_TYPE>>();                        \
   }                                                                            \
+  std::vector<CXX_TYPE>                                                        \
+      *cxxbridge1$unique_ptr$std$vector$##RUST_TYPE##$new() noexcept {         \
+    return new std::vector<CXX_TYPE>();                                        \
+  }                                                                            \
   void cxxbridge1$unique_ptr$std$vector$##RUST_TYPE##$raw(                     \
       std::unique_ptr<std::vector<CXX_TYPE>> *ptr,                             \
       std::vector<CXX_TYPE> *raw) noexcept {                                   \
diff --git a/src/cxx_vector.rs b/src/cxx_vector.rs
index abf9297a..9587a751 100644
--- a/src/cxx_vector.rs
+++ b/src/cxx_vector.rs
@@ -4,6 +4,7 @@
 use crate::extern_type::ExternType;
 use crate::kind::Trivial;
 use crate::string::CxxString;
+use crate::unique_ptr::UniquePtr;
 use core::ffi::c_void;
 use core::fmt::{self, Debug};
 use core::iter::FusedIterator;
@@ -36,6 +37,13 @@ impl<T> CxxVector<T>
 where
     T: VectorElement,
 {
+    /// Constructs a new heap allocated vector, wrapped by UniquePtr.
+    ///
+    /// The C++ vector is default constructed.
+    pub fn new() -> UniquePtr<Self> {
+        unsafe { UniquePtr::from_raw(T::__unique_ptr_new()) }
+    }
+
     /// Returns the number of elements in the vector.
     ///
     /// Matches the behavior of C++ [std::vector\<T\>::size][size].
@@ -356,6 +364,8 @@ pub unsafe trait VectorElement: Sized {
     #[doc(hidden)]
     fn __unique_ptr_null() -> MaybeUninit<*mut c_void>;
     #[doc(hidden)]
+    fn __unique_ptr_new() -> *mut CxxVector<Self>;
+    #[doc(hidden)]
     unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> MaybeUninit<*mut c_void>;
     #[doc(hidden)]
     unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<Self>;
@@ -428,6 +438,15 @@ macro_rules! impl_vector_element {
                 unsafe { __unique_ptr_null(&mut repr) }
                 repr
             }
+            fn __unique_ptr_new() -> *mut CxxVector<Self> {
+                extern "C" {
+                    attr! {
+                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$new")]
+                        fn __unique_ptr_new() -> *mut CxxVector<$ty>;
+                    }
+                }
+                unsafe { __unique_ptr_new() }
+            }
             unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> MaybeUninit<*mut c_void> {
                 extern "C" {
                     attr! {


Test patch:
diff --git a/tests/cxx_vector.rs b/tests/cxx_vector.rs
new file mode 100644
index 00000000..1f7a21b1
--- /dev/null
+++ b/tests/cxx_vector.rs
@@ -0,0 +1,8 @@
+use cxx::{CxxVector};
+
+#[test]
+fn test_cxx_vector_new() {
+    let vector = CxxVector::<i32>::new();
+    assert!(vector.is_empty());
+}
+