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);
+}