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/Cargo.toml b/Cargo.toml
index f497482..95cd87d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,6 +17,7 @@
 [dependencies]
 anyhow = "1.0"
 cc = "1.0.49"
+codespan = "0.7"
 codespan-reporting = "0.9"
 cxxbridge-macro = { version = "=0.2.10", path = "macro" }
 link-cplusplus = "1.0"
diff --git a/demo-cxx/demo.cc b/demo-cxx/demo.cc
index cd447ea..387c56a 100644
--- a/demo-cxx/demo.cc
+++ b/demo-cxx/demo.cc
@@ -9,13 +9,41 @@
 
 ThingC::~ThingC() { std::cout << "done with ThingC" << std::endl; }
 
-std::unique_ptr<ThingC> make_demo(rust::Str appname) {
+std::unique_ptr<ThingC> make_demo(::rust::Str appname) {
   return std::unique_ptr<ThingC>(new ThingC(std::string(appname)));
 }
 
 const std::string &get_name(const ThingC &thing) { return thing.appname; }
 
-void do_thing(SharedThing state) { print_r(*state.y); }
+std::unique_ptr<std::vector<uint8_t>> do_thing(SharedThing state) {
+  print_r(*state.y);
+  auto vec = std::unique_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>());
+  for (uint8_t i = 0; i < 10; i++) {
+    vec->push_back(i * i);
+  }
+  return vec;
+}
+
+JsonBlob get_jb(const ::rust::Vec<uint8_t>& vec) {
+  JsonBlob retval;
+
+  std::cout << "incoming vec length is " << vec.size() << "\n";
+  auto vec_copy = static_cast<std::vector<uint8_t>>(vec);
+  std::cout << "vec_copy length is " << vec_copy.size() << "\n";
+  std::cout << "vec_copy[0] is " << (int)vec_copy[0] << "\n";
+
+  auto blob = std::unique_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>());
+  for (uint8_t i = 0; i < 10; i++) {
+    blob->push_back(i * 2);
+  }
+
+  auto json = std::unique_ptr<std::string>(new std::string("{\"demo\": 23}"));
+
+  retval.json = std::move(json);
+  retval.blob = std::move(blob);
+
+  return retval;
+}
 
 } // namespace example
 } // namespace org
diff --git a/demo-cxx/demo.h b/demo-cxx/demo.h
index fafc474..eea0af7 100644
--- a/demo-cxx/demo.h
+++ b/demo-cxx/demo.h
@@ -15,10 +15,12 @@
 };
 
 struct SharedThing;
+struct JsonBlob;
 
-std::unique_ptr<ThingC> make_demo(rust::Str appname);
+std::unique_ptr<ThingC> make_demo(::rust::Str appname);
 const std::string &get_name(const ThingC &thing);
-void do_thing(SharedThing state);
+std::unique_ptr<std::vector<uint8_t>> do_thing(SharedThing state);
+JsonBlob get_jb(const ::rust::Vec<uint8_t>& vec);
 
 } // namespace example
 } // namespace org
diff --git a/demo-rs/src/main.rs b/demo-rs/src/main.rs
index 66dfc79..8bf9926 100644
--- a/demo-rs/src/main.rs
+++ b/demo-rs/src/main.rs
@@ -6,13 +6,19 @@
         x: UniquePtr<ThingC>,
     }
 
+    struct JsonBlob {
+        json: UniquePtr<CxxString>,
+        blob: UniquePtr<Vector<u8>>,
+    }
+
     extern "C" {
         include!("demo-cxx/demo.h");
 
         type ThingC;
         fn make_demo(appname: &str) -> UniquePtr<ThingC>;
         fn get_name(thing: &ThingC) -> &CxxString;
-        fn do_thing(state: SharedThing);
+        fn do_thing(state: SharedThing) -> UniquePtr<Vector<u8>>;
+        fn get_jb(v: &Vec<u8>) -> JsonBlob;
     }
 
     extern "Rust" {
@@ -31,9 +37,24 @@
     let x = ffi::make_demo("demo of cxx::bridge");
     println!("this is a {}", ffi::get_name(x.as_ref().unwrap()));
 
-    ffi::do_thing(ffi::SharedThing {
+    let vec = ffi::do_thing(ffi::SharedThing {
         z: 222,
         y: Box::new(ThingR(333)),
         x,
     });
+
+    println!("vec length = {}", vec.as_ref().unwrap().size());
+    for (i, v) in vec.as_ref().unwrap().into_iter().enumerate() {
+        println!("vec[{}] = {}", i, v);
+    }
+
+    let mut rv: Vec<u8> = Vec::new();
+    for _ in 0..1000 {
+        rv.push(33);
+    }
+    let jb = ffi::get_jb(&rv);
+    println!("json: {}", jb.json.as_ref().unwrap());
+    for (i, v) in jb.blob.as_ref().unwrap().into_iter().enumerate() {
+        println!("jb.blob[{}] = {}", i, v);
+    }
 }
diff --git a/gen/include.rs b/gen/include.rs
index 8f38fe3..077d03e 100644
--- a/gen/include.rs
+++ b/gen/include.rs
@@ -36,6 +36,7 @@
     pub exception: bool,
     pub memory: bool,
     pub string: bool,
+    pub vector: bool,
     pub type_traits: bool,
     pub utility: bool,
     pub base_tsd: bool,
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);
+}
diff --git a/include/cxx.h b/include/cxx.h
index 637372a..35e9059 100644
--- a/include/cxx.h
+++ b/include/cxx.h
@@ -5,6 +5,7 @@
 #include <exception>
 #include <iosfwd>
 #include <string>
+#include <vector>
 #include <type_traits>
 #include <utility>
 #if defined(_WIN32)
@@ -83,6 +84,27 @@
 };
 #endif // CXXBRIDGE02_RUST_STR
 
+#ifndef CXXBRIDGE02_RUST_VEC
+#define CXXBRIDGE02_RUST_VEC
+template <typename T>
+class Vec final {
+public:
+  size_t size() const noexcept;
+  explicit operator std::vector<T>() const noexcept;
+
+private:
+  Vec() noexcept;
+  Vec(const Vec &other) noexcept;
+  Vec &operator=(Vec other) noexcept;
+  void drop() noexcept;
+  
+  // Repr
+  const T *ptr;
+  size_t len;
+  size_t capacity;
+};
+#endif // CXXBRIDGE02_RUST_VEC
+
 #ifndef CXXBRIDGE02_RUST_SLICE
 #define CXXBRIDGE02_RUST_SLICE
 template <typename T>
@@ -234,14 +256,11 @@
 };
 #endif // CXXBRIDGE02_RUST_ERROR
 
-#ifndef CXXBRIDGE02_RUST_ISIZE
-#define CXXBRIDGE02_RUST_ISIZE
 #if defined(_WIN32)
 using isize = SSIZE_T;
 #else
 using isize = ssize_t;
 #endif
-#endif // CXXBRIDGE02_RUST_ISIZE
 
 std::ostream &operator<<(std::ostream &, const String &);
 std::ostream &operator<<(std::ostream &, const Str &);
diff --git a/macro/Cargo.toml b/macro/Cargo.toml
index ca0e326..99ae923 100644
--- a/macro/Cargo.toml
+++ b/macro/Cargo.toml
@@ -19,7 +19,7 @@
 syn = { version = "1.0", features = ["full"] }
 
 [dev-dependencies]
-cxx = { version = "0.2", path = ".." }
+cxx = { version = "0.2.7-alpha-1", path = ".." }
 
 [package.metadata.docs.rs]
 targets = ["x86_64-unknown-linux-gnu"]
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 8b3602a..b329276 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -1,12 +1,14 @@
 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::{
     self, check, mangle, Api, ExternFn, ExternType, Signature, Struct, Type, Types,
 };
 use proc_macro2::{Ident, Span, TokenStream};
 use quote::{format_ident, quote, quote_spanned, ToTokens};
-use syn::{parse_quote, Error, ItemMod, Result, Token};
+use syn::{parse_quote, spanned::Spanned, Error, ItemMod, Result, Token};
 
 pub fn bridge(namespace: &Namespace, ffi: ItemMod) -> Result<TokenStream> {
     let ident = &ffi.ident;
@@ -22,6 +24,38 @@
     let mut hidden = TokenStream::new();
     let mut has_rust_type = false;
 
+    // "Header" to define newtypes locally so we can implement
+    // traits on them.
+    expanded.extend(quote! {
+        pub struct Vector<T>(pub ::cxx::RealVector<T>);
+        impl<T: cxx::private::VectorTarget<T>> Vector<T> {
+            pub fn size(&self) -> usize {
+                self.0.size()
+            }
+            pub fn get(&self, pos: usize) -> Option<&T> {
+                self.0.get(pos)
+            }
+            pub fn get_unchecked(&self, pos: usize) -> &T {
+                self.0.get_unchecked(pos)
+            }
+            pub fn is_empty(&self) -> bool {
+                self.0.is_empty()
+            }
+            pub fn push_back(&mut self, item: &T) {
+                self.0.push_back(item)
+            }
+        }
+        impl<'a, T: cxx::private::VectorTarget<T>> IntoIterator for &'a Vector<T> {
+            type Item = &'a T;
+            type IntoIter = <&'a ::cxx::RealVector<T> as IntoIterator>::IntoIter;
+
+            fn into_iter(self) -> Self::IntoIter {
+                self.0.into_iter()
+            }
+        }
+        unsafe impl<T> Send for Vector<T> where T: Send + cxx::private::VectorTarget<T> {}
+    });
+
     for api in &apis {
         if let Api::RustType(ety) = api {
             expanded.extend(expand_rust_type(ety));
@@ -58,10 +92,34 @@
                     hidden.extend(expand_rust_box(namespace, ident));
                 }
             }
+        } else if let Type::RustVec(ty) = ty {
+            if let Type::Ident(ident) = &ty.inner {
+                hidden.extend(expand_rust_vec(namespace, &ty.inner, ident));
+            }
         } else if let Type::UniquePtr(ptr) = ty {
             if let Type::Ident(ident) = &ptr.inner {
                 if Atom::from(ident).is_none() {
-                    expanded.extend(expand_unique_ptr(namespace, ident, types));
+                    expanded.extend(expand_unique_ptr(namespace, &ptr.inner, types));
+                }
+            } else if let Type::Vector(_) = &ptr.inner {
+                // Generate code for unique_ptr<vector<T>> if T is not an atom
+                // or if T is a primitive.
+                // Code for primitives is already generated
+                match Atom::from(ident) {
+                    None => expanded.extend(expand_unique_ptr(namespace, &ptr.inner, types)),
+                    Some(atom) => {
+                        if atom.is_valid_vector_target() {
+                            expanded.extend(expand_unique_ptr(namespace, &ptr.inner, types));
+                        }
+                    }
+                }
+            }
+        } else if let Type::Vector(ptr) = ty {
+            if let Type::Ident(ident) = &ptr.inner {
+                if Atom::from(ident).is_none() {
+                    // Generate code for Vector<T> if T is not an atom
+                    // Code for atoms is already generated
+                    expanded.extend(expand_vector(namespace, &ptr.inner));
                 }
             }
         }
@@ -197,10 +255,12 @@
             }
             Type::RustBox(_) => quote!(::std::boxed::Box::into_raw(#var)),
             Type::UniquePtr(_) => quote!(::cxx::UniquePtr::into_raw(#var)),
+            Type::RustVec(_) => quote!(::cxx::RustVec::from(#var)),
             Type::Ref(ty) => match &ty.inner {
                 Type::Ident(ident) if ident == RustString => {
                     quote!(::cxx::private::RustString::from_ref(#var))
                 }
+                Type::RustVec(_) => quote!(::cxx::RustVec::from_ref(#var)),
                 _ => quote!(#var),
             },
             Type::Str(_) => quote!(::cxx::private::RustStr::from(#var)),
@@ -523,9 +583,42 @@
     }
 }
 
-fn expand_unique_ptr(namespace: &Namespace, ident: &Ident, types: &Types) -> TokenStream {
-    let name = ident.to_string();
-    let prefix = format!("cxxbridge02$unique_ptr${}{}$", namespace, ident);
+fn expand_rust_vec(namespace: &Namespace, ty: &Type, ident: &Ident) -> TokenStream {
+    let inner = ty;
+    let mangled = ty.to_mangled(&namespace.segments) + "$";
+    let link_prefix = format!("cxxbridge02$rust_vec${}", mangled);
+    let link_drop = format!("{}drop", link_prefix);
+    let link_vector_from = format!("{}vector_from", link_prefix);
+    let link_len = format!("{}len", link_prefix);
+
+    let local_prefix = format_ident!("{}__vec_", ident);
+    let local_drop = format_ident!("{}drop", local_prefix);
+    let local_vector_from = format_ident!("{}vector_from", local_prefix);
+    let local_len = format_ident!("{}len", local_prefix);
+
+    let span = ty.span();
+    quote_spanned! {span=>
+        #[doc(hidden)]
+        #[export_name = #link_drop]
+        unsafe extern "C" fn #local_drop(this: *mut ::cxx::RustVec<#inner>) {
+            std::ptr::drop_in_place(this);
+        }
+        #[export_name = #link_vector_from]
+        unsafe extern "C" fn #local_vector_from(this: *mut ::cxx::RustVec<#inner>, vector: *mut ::cxx::RealVector<#inner>) {
+            this.as_ref().unwrap().into_vector(vector.as_mut().unwrap());
+        }
+        #[export_name = #link_len]
+        unsafe extern "C" fn #local_len(this: *const ::cxx::RustVec<#inner>) -> usize {
+            this.as_ref().unwrap().len()
+        }
+    }
+}
+
+fn expand_unique_ptr(namespace: &Namespace, ty: &Type, types: &Types) -> TokenStream {
+    let name = ty.to_typename(&namespace.segments);
+    let inner = ty;
+    let mangled = ty.to_mangled(&namespace.segments) + "$";
+    let prefix = format!("cxxbridge02$unique_ptr${}", mangled);
     let link_null = format!("{}null", prefix);
     let link_new = format!("{}new", prefix);
     let link_raw = format!("{}raw", prefix);
@@ -533,8 +626,8 @@
     let link_release = format!("{}release", prefix);
     let link_drop = format!("{}drop", prefix);
 
-    let new_method = if types.structs.contains_key(ident) {
-        Some(quote! {
+    let new_method = match ty {
+        Type::Ident(ident) if types.structs.contains_key(ident) => Some(quote! {
             fn __new(mut value: Self) -> *mut ::std::ffi::c_void {
                 extern "C" {
                     #[link_name = #link_new]
@@ -544,13 +637,12 @@
                 unsafe { __new(&mut repr, &mut value) }
                 repr
             }
-        })
-    } else {
-        None
+        }),
+        _ => None,
     };
 
     quote! {
-        unsafe impl ::cxx::private::UniquePtrTarget for #ident {
+        unsafe impl ::cxx::private::UniquePtrTarget for #inner {
             const __NAME: &'static str = #name;
             fn __null() -> *mut ::std::ffi::c_void {
                 extern "C" {
@@ -565,7 +657,7 @@
             unsafe fn __raw(raw: *mut Self) -> *mut ::std::ffi::c_void {
                 extern "C" {
                     #[link_name = #link_raw]
-                    fn __raw(this: *mut *mut ::std::ffi::c_void, raw: *mut #ident);
+                    fn __raw(this: *mut *mut ::std::ffi::c_void, raw: *mut #inner);
                 }
                 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
                 __raw(&mut repr, raw);
@@ -574,14 +666,14 @@
             unsafe fn __get(repr: *mut ::std::ffi::c_void) -> *const Self {
                 extern "C" {
                     #[link_name = #link_get]
-                    fn __get(this: *const *mut ::std::ffi::c_void) -> *const #ident;
+                    fn __get(this: *const *mut ::std::ffi::c_void) -> *const #inner;
                 }
                 __get(&repr)
             }
             unsafe fn __release(mut repr: *mut ::std::ffi::c_void) -> *mut Self {
                 extern "C" {
                     #[link_name = #link_release]
-                    fn __release(this: *mut *mut ::std::ffi::c_void) -> *mut #ident;
+                    fn __release(this: *mut *mut ::std::ffi::c_void) -> *mut #inner;
                 }
                 __release(&mut repr)
             }
@@ -596,6 +688,90 @@
     }
 }
 
+fn expand_vector(namespace: &Namespace, ty: &Type) -> TokenStream {
+    let inner = ty;
+    let mangled = ty.to_mangled(&namespace.segments) + "$";
+    let prefix = format!("cxxbridge02$std$vector${}", mangled);
+    let link_length = format!("{}length", prefix);
+    let link_get_unchecked = format!("{}get_unchecked", prefix);
+    let link_push_back = format!("{}push_back", prefix);
+
+    quote! {
+        impl ::cxx::private::VectorTarget<#inner> for #inner {
+            fn get_unchecked(v: &::cxx::RealVector<#inner>, pos: usize) -> &#inner {
+                extern "C" {
+                    #[link_name = #link_get_unchecked]
+                    fn __get_unchecked(_: &::cxx::RealVector<#inner>, _: usize) -> &#inner;
+                }
+                unsafe {
+                    __get_unchecked(v, pos)
+                }
+            }
+            fn vector_length(v: &::cxx::RealVector<#inner>) -> usize {
+                unsafe {
+                    extern "C" {
+                        #[link_name = #link_length]
+                        fn __vector_length(_: &::cxx::RealVector<#inner>) -> usize;
+                    }
+                    __vector_length(v)
+                }
+            }
+            fn push_back(v: &::cxx::RealVector<#inner>, item: &#inner) {
+                unsafe {
+                    extern "C" {
+                        #[link_name = #link_push_back]
+                        fn __push_back(_: &::cxx::RealVector<#inner>, _: &#inner) -> usize;
+                    }
+                    __push_back(v, item);
+                }
+            }
+        }
+    }
+}
+
+pub fn expand_vector_builtin(ident: Ident) -> TokenStream {
+    let ty = Type::Ident(ident);
+    let inner = &ty;
+    let namespace = Namespace { segments: vec![] };
+    let mangled = ty.to_mangled(&namespace.segments) + "$";
+    let prefix = format!("cxxbridge02$std$vector${}", mangled);
+    let link_length = format!("{}length", prefix);
+    let link_get_unchecked = format!("{}get_unchecked", prefix);
+    let link_push_back = format!("{}push_back", prefix);
+
+    quote! {
+        impl VectorTarget<#inner> for #inner {
+            fn get_unchecked(v: &RealVector<#inner>, pos: usize) -> &#inner {
+                extern "C" {
+                    #[link_name = #link_get_unchecked]
+                    fn __get_unchecked(_: &RealVector<#inner>, _: usize) -> &#inner;
+                }
+                unsafe {
+                    __get_unchecked(v, pos)
+                }
+            }
+            fn vector_length(v: &RealVector<#inner>) -> usize {
+                unsafe {
+                    extern "C" {
+                        #[link_name = #link_length]
+                        fn __vector_length(_: &RealVector<#inner>) -> usize;
+                    }
+                    __vector_length(v)
+                }
+            }
+            fn push_back(v: &RealVector<#inner>, item: &#inner) {
+                unsafe {
+                    extern "C" {
+                        #[link_name = #link_push_back]
+                        fn __push_back(_: &RealVector<#inner>, _: &#inner) -> usize;
+                    }
+                    __push_back(v, item);
+                }
+            }
+        }
+    }
+}
+
 fn expand_return_type(ret: &Option<Type>) -> TokenStream {
     match ret {
         Some(ret) => quote!(-> #ret),
@@ -613,11 +789,16 @@
     match ty {
         Type::Ident(ident) if ident == RustString => quote!(::cxx::private::RustString),
         Type::RustBox(ty) | Type::UniquePtr(ty) => {
-            let inner = &ty.inner;
+            let inner = expand_extern_type(&ty.inner);
             quote!(*mut #inner)
         }
+        Type::RustVec(ty) => quote!(::cxx::RustVec<#ty>),
         Type::Ref(ty) => match &ty.inner {
             Type::Ident(ident) if ident == RustString => quote!(&::cxx::private::RustString),
+            Type::RustVec(ty) => {
+                let inner = expand_extern_type(&ty.inner);
+                quote!(&::cxx::RustVec<#inner>)
+            }
             _ => quote!(#ty),
         },
         Type::Str(_) => quote!(::cxx::private::RustStr),
diff --git a/macro/src/lib.rs b/macro/src/lib.rs
index b56f58e..87fe405 100644
--- a/macro/src/lib.rs
+++ b/macro/src/lib.rs
@@ -14,7 +14,7 @@
 
 use crate::syntax::namespace::Namespace;
 use proc_macro::TokenStream;
-use syn::{parse_macro_input, ItemMod};
+use syn::{parse_macro_input, Ident, ItemMod};
 
 /// `#[cxx::bridge] mod ffi { ... }`
 ///
@@ -44,3 +44,9 @@
         .unwrap_or_else(|err| err.to_compile_error())
         .into()
 }
+
+#[proc_macro]
+pub fn vector_builtin(input: TokenStream) -> TokenStream {
+    let ident = parse_macro_input!(input as Ident);
+    expand::expand_vector_builtin(ident).into()
+}
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);
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) => {
diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs
index efdd1fa..27f5f6d 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -27,6 +27,9 @@
         fn c_return_sliceu8(shared: &Shared) -> &[u8];
         fn c_return_rust_string() -> String;
         fn c_return_unique_ptr_string() -> UniquePtr<CxxString>;
+        fn c_return_unique_ptr_vector_u8() -> UniquePtr<Vector<u8>>;
+        fn c_return_unique_ptr_vector_f64() -> UniquePtr<Vector<f64>>;
+        fn c_return_unique_ptr_vector_shared() -> UniquePtr<Vector<Shared>>;
 
         fn c_take_primitive(n: usize);
         fn c_take_shared(shared: Shared);
@@ -38,11 +41,19 @@
         fn c_take_sliceu8(s: &[u8]);
         fn c_take_rust_string(s: String);
         fn c_take_unique_ptr_string(s: UniquePtr<CxxString>);
+        fn c_take_unique_ptr_vector_u8(s: UniquePtr<Vector<u8>>);
+        fn c_take_unique_ptr_vector_f64(s: UniquePtr<Vector<f64>>);
+        fn c_take_unique_ptr_vector_shared(s: UniquePtr<Vector<Shared>>);
+
+        fn c_take_vec_u8(v: &Vec<u8>);
+        fn c_take_vec_shared(v: &Vec<Shared>);
         fn c_take_callback(callback: fn(String) -> usize);
 
         fn c_try_return_void() -> Result<()>;
         fn c_try_return_primitive() -> Result<usize>;
         fn c_fail_return_primitive() -> Result<usize>;
+        fn c_try_return_string() -> Result<UniquePtr<CxxString>>;
+        fn c_fail_return_string() -> Result<UniquePtr<CxxString>>;
         fn c_try_return_box() -> Result<Box<R>>;
         fn c_try_return_ref(s: &String) -> Result<&String>;
         fn c_try_return_str(s: &str) -> Result<&str>;
diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc
index 619485a..9f11d9f 100644
--- a/tests/ffi/tests.cc
+++ b/tests/ffi/tests.cc
@@ -1,3 +1,4 @@
+#include <numeric>
 #include "tests/ffi/tests.h"
 #include "tests/ffi/lib.rs.h"
 #include <cstring>
@@ -57,6 +58,31 @@
   return std::unique_ptr<std::string>(new std::string("2020"));
 }
 
+std::unique_ptr<std::vector<uint8_t>> c_return_unique_ptr_vector_u8() {
+  auto retval = std::unique_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>());
+  retval->push_back(86);
+  retval->push_back(75);
+  retval->push_back(30);
+  retval->push_back(9);
+  return retval;
+}
+
+std::unique_ptr<std::vector<double>> c_return_unique_ptr_vector_f64() {
+  auto retval = std::unique_ptr<std::vector<double>>(new std::vector<double>());
+  retval->push_back(86.0);
+  retval->push_back(75.0);
+  retval->push_back(30.0);
+  retval->push_back(9.5);
+  return retval;
+}
+
+std::unique_ptr<std::vector<Shared>> c_return_unique_ptr_vector_shared() {
+  auto retval = std::unique_ptr<std::vector<Shared>>(new std::vector<Shared>());
+  retval->push_back(Shared{1010});
+  retval->push_back(Shared{1011});
+  return retval;
+}
+
 void c_take_primitive(size_t n) {
   if (n == 2020) {
     cxx_test_suite_set_correct();
@@ -118,6 +144,43 @@
   }
 }
 
+void c_take_unique_ptr_vector_u8(std::unique_ptr<std::vector<uint8_t>> v) {
+  if (v->size() == 4) {
+    cxx_test_suite_set_correct();
+  }
+}
+
+void c_take_unique_ptr_vector_f64(std::unique_ptr<std::vector<double>> v) {
+  if (v->size() == 4) {
+    cxx_test_suite_set_correct();
+  }
+}
+
+void c_take_unique_ptr_vector_shared(std::unique_ptr<std::vector<Shared>> v) {
+  if (v->size() == 2) {
+    cxx_test_suite_set_correct();
+  }
+}
+
+void c_take_vec_u8(const ::rust::Vec<uint8_t>& v) {
+  auto cv = static_cast<std::vector<uint8_t>>(v);
+  uint8_t sum = std::accumulate(cv.begin(), cv.end(), 0);
+  if (sum == 200) {
+    cxx_test_suite_set_correct();
+  }
+}
+
+void c_take_vec_shared(const ::rust::Vec<Shared>& v) {
+  auto cv = static_cast<std::vector<Shared>>(v);
+  uint32_t sum = 0;
+  for (auto i: cv) {
+    sum += i.z;
+  }
+  if (sum == 2021) {
+    cxx_test_suite_set_correct();
+  }
+}
+
 void c_take_callback(rust::Fn<size_t(rust::String)> callback) {
   callback("2020");
 }
@@ -128,6 +191,14 @@
 
 size_t c_fail_return_primitive() { throw std::logic_error("logic error"); }
 
+std::unique_ptr<std::string> c_try_return_string() {
+  return std::unique_ptr<std::string>(new std::string("ok"));
+}
+
+std::unique_ptr<std::string> c_fail_return_string() { 
+  throw std::logic_error("logic error getting string"); 
+}
+
 rust::Box<R> c_try_return_box() { return c_return_box(); }
 
 const rust::String &c_try_return_ref(const rust::String &s) { return s; }
diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h
index ed6d541..9e75c37 100644
--- a/tests/ffi/tests.h
+++ b/tests/ffi/tests.h
@@ -29,6 +29,9 @@
 rust::Slice<uint8_t> c_return_sliceu8(const Shared &shared);
 rust::String c_return_rust_string();
 std::unique_ptr<std::string> c_return_unique_ptr_string();
+std::unique_ptr<std::vector<uint8_t>> c_return_unique_ptr_vector_u8();
+std::unique_ptr<std::vector<double>> c_return_unique_ptr_vector_f64();
+std::unique_ptr<std::vector<Shared>> c_return_unique_ptr_vector_shared();
 
 void c_take_primitive(size_t n);
 void c_take_shared(Shared shared);
@@ -40,11 +43,19 @@
 void c_take_sliceu8(rust::Slice<uint8_t> s);
 void c_take_rust_string(rust::String s);
 void c_take_unique_ptr_string(std::unique_ptr<std::string> s);
+void c_take_unique_ptr_vector_u8(std::unique_ptr<std::vector<uint8_t>> v);
+void c_take_unique_ptr_vector_f64(std::unique_ptr<std::vector<double>> v);
+void c_take_unique_ptr_vector_shared(std::unique_ptr<std::vector<Shared>> v);
+
+void c_take_vec_u8(const ::rust::Vec<uint8_t>& v);
+void c_take_vec_shared(const ::rust::Vec<Shared>& v);
 void c_take_callback(rust::Fn<size_t(rust::String)> callback);
 
 void c_try_return_void();
 size_t c_try_return_primitive();
 size_t c_fail_return_primitive();
+std::unique_ptr<std::string> c_try_return_string();
+std::unique_ptr<std::string> c_fail_return_string();
 rust::Box<R> c_try_return_box();
 const rust::String &c_try_return_ref(const rust::String &);
 rust::Str c_try_return_str(rust::Str);
diff --git a/tests/test.rs b/tests/test.rs
index 1cd85df..17fcfca 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -32,6 +32,45 @@
     assert_eq!(b"2020\0", ffi::c_return_sliceu8(&shared));
     assert_eq!("2020", ffi::c_return_rust_string());
     assert_eq!("2020", ffi::c_return_unique_ptr_string().to_str().unwrap());
+    assert_eq!(
+        4,
+        ffi::c_return_unique_ptr_vector_u8()
+            .as_ref()
+            .unwrap()
+            .size()
+    );
+    assert_eq!(
+        200_u8,
+        ffi::c_return_unique_ptr_vector_u8()
+            .as_ref()
+            .unwrap()
+            .into_iter()
+            .sum()
+    );
+    assert_eq!(
+        200.5_f64,
+        ffi::c_return_unique_ptr_vector_f64()
+            .as_ref()
+            .unwrap()
+            .into_iter()
+            .sum()
+    );
+    assert_eq!(
+        2,
+        ffi::c_return_unique_ptr_vector_shared()
+            .as_ref()
+            .unwrap()
+            .size()
+    );
+    assert_eq!(
+        2021_usize,
+        ffi::c_return_unique_ptr_vector_shared()
+            .as_ref()
+            .unwrap()
+            .into_iter()
+            .map(|o| o.z)
+            .sum()
+    );
 }
 
 #[test]
@@ -42,6 +81,18 @@
         "logic error",
         ffi::c_fail_return_primitive().unwrap_err().what(),
     );
+    assert_eq!(
+        "ok",
+        ffi::c_try_return_string()
+            .unwrap()
+            .as_ref()
+            .unwrap()
+            .to_string()
+    );
+    assert_eq!(
+        "logic error getting string",
+        ffi::c_fail_return_string().unwrap_err().what(),
+    );
     assert_eq!(2020, *ffi::c_try_return_box().unwrap());
     assert_eq!("2020", *ffi::c_try_return_ref(&"2020".to_owned()).unwrap());
     assert_eq!("2020", ffi::c_try_return_str("2020").unwrap());
@@ -65,6 +116,22 @@
     check!(ffi::c_take_unique_ptr_string(
         ffi::c_return_unique_ptr_string()
     ));
+    check!(ffi::c_take_unique_ptr_vector_u8(
+        ffi::c_return_unique_ptr_vector_u8()
+    ));
+    check!(ffi::c_take_unique_ptr_vector_f64(
+        ffi::c_return_unique_ptr_vector_f64()
+    ));
+    check!(ffi::c_take_unique_ptr_vector_shared(
+        ffi::c_return_unique_ptr_vector_shared()
+    ));
+
+    check!(ffi::c_take_vec_u8(&[86_u8, 75_u8, 30_u8, 9_u8].to_vec()));
+
+    check!(ffi::c_take_vec_shared(&vec![
+        ffi::Shared { z: 1010 },
+        ffi::Shared { z: 1011 }
+    ]));
 }
 
 #[test]
diff --git a/third-party/Cargo.lock b/third-party/Cargo.lock
index 2e70499..4552f46 100644
--- a/third-party/Cargo.lock
+++ b/third-party/Cargo.lock
@@ -54,6 +54,15 @@
 ]
 
 [[package]]
+name = "codespan"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21094c000d5db8035900662bbfddec754e79f795324254ac0817f36e5ccfc3f5"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
 name = "codespan-reporting"
 version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -69,6 +78,7 @@
 dependencies = [
  "anyhow",
  "cc",
+ "codespan",
  "codespan-reporting",
  "cxx-test-suite",
  "cxxbridge-macro",