Implement Vec<String>
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index ab1206c..0869c2c 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -260,6 +260,10 @@
                     None => quote!(::cxx::private::RustString::from_ref(#var)),
                     Some(_) => quote!(::cxx::private::RustString::from_mut(#var)),
                 },
+                Type::RustVec(vec) if vec.inner == RustString => match ty.mutability {
+                    None => quote!(::cxx::private::RustVec::from_ref_vec_string(#var)),
+                    Some(_) => quote!(::cxx::private::RustVec::from_mut_vec_string(#var)),
+                },
                 Type::RustVec(_) => match ty.mutability {
                     None => quote!(::cxx::private::RustVec::from_ref(#var)),
                     Some(_) => quote!(::cxx::private::RustVec::from_mut(#var)),
@@ -332,13 +336,23 @@
                 Some(quote!(#call.map(|r| r.into_string())))
             }
             Type::RustBox(_) => Some(quote!(#call.map(|r| ::std::boxed::Box::from_raw(r)))),
-            Type::RustVec(_) => Some(quote!(#call.map(|r| r.into_vec()))),
+            Type::RustVec(vec) => {
+                if vec.inner == RustString {
+                    Some(quote!(#call.map(|r| r.into_vec_string())))
+                } else {
+                    Some(quote!(#call.map(|r| r.into_vec())))
+                }
+            }
             Type::UniquePtr(_) => Some(quote!(#call.map(|r| ::cxx::UniquePtr::from_raw(r)))),
             Type::Ref(ty) => match &ty.inner {
                 Type::Ident(ident) if ident == RustString => match ty.mutability {
                     None => Some(quote!(#call.map(|r| r.as_string()))),
                     Some(_) => Some(quote!(#call.map(|r| r.as_mut_string()))),
                 },
+                Type::RustVec(vec) if vec.inner == RustString => match ty.mutability {
+                    None => Some(quote!(#call.map(|r| r.as_vec_string()))),
+                    Some(_) => Some(quote!(#call.map(|r| r.as_mut_vec_string()))),
+                },
                 Type::RustVec(_) => match ty.mutability {
                     None => Some(quote!(#call.map(|r| r.as_vec()))),
                     Some(_) => Some(quote!(#call.map(|r| r.as_mut_vec()))),
@@ -353,13 +367,23 @@
         efn.ret.as_ref().and_then(|ret| match ret {
             Type::Ident(ident) if ident == RustString => Some(quote!(#call.into_string())),
             Type::RustBox(_) => Some(quote!(::std::boxed::Box::from_raw(#call))),
-            Type::RustVec(_) => Some(quote!(#call.into_vec())),
+            Type::RustVec(vec) => {
+                if vec.inner == RustString {
+                    Some(quote!(#call.into_vec_string()))
+                } else {
+                    Some(quote!(#call.into_vec()))
+                }
+            }
             Type::UniquePtr(_) => Some(quote!(::cxx::UniquePtr::from_raw(#call))),
             Type::Ref(ty) => match &ty.inner {
                 Type::Ident(ident) if ident == RustString => match ty.mutability {
                     None => Some(quote!(#call.as_string())),
                     Some(_) => Some(quote!(#call.as_mut_string())),
                 },
+                Type::RustVec(vec) if vec.inner == RustString => match ty.mutability {
+                    None => Some(quote!(#call.as_vec_string())),
+                    Some(_) => Some(quote!(#call.as_mut_vec_string())),
+                },
                 Type::RustVec(_) => match ty.mutability {
                     None => Some(quote!(#call.as_vec())),
                     Some(_) => Some(quote!(#call.as_mut_vec())),
@@ -508,13 +532,23 @@
                 quote!(::std::mem::take((*#ident).as_mut_string()))
             }
             Type::RustBox(_) => quote!(::std::boxed::Box::from_raw(#ident)),
-            Type::RustVec(_) => quote!(::std::mem::take((*#ident).as_mut_vec())),
+            Type::RustVec(vec) => {
+                if vec.inner == RustString {
+                    quote!(::std::mem::take((*#ident).as_mut_vec_string()))
+                } else {
+                    quote!(::std::mem::take((*#ident).as_mut_vec()))
+                }
+            }
             Type::UniquePtr(_) => quote!(::cxx::UniquePtr::from_raw(#ident)),
             Type::Ref(ty) => match &ty.inner {
                 Type::Ident(i) if i == RustString => match ty.mutability {
                     None => quote!(#ident.as_string()),
                     Some(_) => quote!(#ident.as_mut_string()),
                 },
+                Type::RustVec(vec) if vec.inner == RustString => match ty.mutability {
+                    None => quote!(#ident.as_vec_string()),
+                    Some(_) => quote!(#ident.as_mut_vec_string()),
+                },
                 Type::RustVec(_) => match ty.mutability {
                     None => quote!(#ident.as_vec()),
                     Some(_) => quote!(#ident.as_mut_vec()),
@@ -549,13 +583,23 @@
                 Some(quote!(::cxx::private::RustString::from(#call)))
             }
             Type::RustBox(_) => Some(quote!(::std::boxed::Box::into_raw(#call))),
-            Type::RustVec(_) => Some(quote!(::cxx::private::RustVec::from(#call))),
+            Type::RustVec(vec) => {
+                if vec.inner == RustString {
+                    Some(quote!(::cxx::private::RustVec::from_vec_string(#call)))
+                } else {
+                    Some(quote!(::cxx::private::RustVec::from(#call)))
+                }
+            }
             Type::UniquePtr(_) => Some(quote!(::cxx::UniquePtr::into_raw(#call))),
             Type::Ref(ty) => match &ty.inner {
                 Type::Ident(ident) if ident == RustString => match ty.mutability {
                     None => Some(quote!(::cxx::private::RustString::from_ref(#call))),
                     Some(_) => Some(quote!(::cxx::private::RustString::from_mut(#call))),
                 },
+                Type::RustVec(vec) if vec.inner == RustString => match ty.mutability {
+                    None => Some(quote!(::cxx::private::RustVec::from_ref_vec_string(#call))),
+                    Some(_) => Some(quote!(::cxx::private::RustVec::from_mut_vec_string(#call))),
+                },
                 Type::RustVec(_) => match ty.mutability {
                     None => Some(quote!(::cxx::private::RustVec::from_ref(#call))),
                     Some(_) => Some(quote!(::cxx::private::RustVec::from_mut(#call))),
diff --git a/src/cxx.cc b/src/cxx.cc
index b953904..e00fd6a 100644
--- a/src/cxx.cc
+++ b/src/cxx.cc
@@ -280,7 +280,8 @@
 
 #define FOR_EACH_RUST_VEC(MACRO)                                               \
   FOR_EACH_NUMERIC(MACRO)                                                      \
-  MACRO(bool, bool)
+  MACRO(bool, bool)                                                            \
+  MACRO(string, rust::String)
 
 extern "C" {
 FOR_EACH_STD_VECTOR(STD_VECTOR_OPS)
diff --git a/src/rust_vec.rs b/src/rust_vec.rs
index 9ff4bbf..5e7082a 100644
--- a/src/rust_vec.rs
+++ b/src/rust_vec.rs
@@ -1,3 +1,6 @@
+use crate::rust_string::RustString;
+use std::mem::ManuallyDrop;
+
 #[repr(C)]
 pub struct RustVec<T> {
     repr: Vec<T>,
@@ -40,3 +43,37 @@
         self.repr.as_ptr()
     }
 }
+
+impl RustVec<RustString> {
+    pub fn from_vec_string(v: Vec<String>) -> Self {
+        let mut v = ManuallyDrop::new(v);
+        let ptr = v.as_mut_ptr().cast::<RustString>();
+        let len = v.len();
+        let cap = v.capacity();
+        Self::from(unsafe { Vec::from_raw_parts(ptr, len, cap) })
+    }
+
+    pub fn from_ref_vec_string(v: &Vec<String>) -> &Self {
+        Self::from_ref(unsafe { &*(v as *const Vec<String> as *const Vec<RustString>) })
+    }
+
+    pub fn from_mut_vec_string(v: &mut Vec<String>) -> &mut Self {
+        Self::from_mut(unsafe { &mut *(v as *mut Vec<String> as *mut Vec<RustString>) })
+    }
+
+    pub fn into_vec_string(self) -> Vec<String> {
+        let mut v = ManuallyDrop::new(self.repr);
+        let ptr = v.as_mut_ptr().cast::<String>();
+        let len = v.len();
+        let cap = v.capacity();
+        unsafe { Vec::from_raw_parts(ptr, len, cap) }
+    }
+
+    pub fn as_vec_string(&self) -> &Vec<String> {
+        unsafe { &*(&self.repr as *const Vec<RustString> as *const Vec<String>) }
+    }
+
+    pub fn as_mut_vec_string(&mut self) -> &mut Vec<String> {
+        unsafe { &mut *(&mut self.repr as *mut Vec<RustString> as *mut Vec<String>) }
+    }
+}
diff --git a/src/symbols/rust_string.rs b/src/symbols/rust_string.rs
index 63d4ba7..d8e0f4a 100644
--- a/src/symbols/rust_string.rs
+++ b/src/symbols/rust_string.rs
@@ -3,6 +3,11 @@
 use std::slice;
 use std::str;
 
+#[repr(C)]
+pub(crate) struct RustString {
+    repr: String,
+}
+
 #[export_name = "cxxbridge03$string$new"]
 unsafe extern "C" fn string_new(this: &mut MaybeUninit<String>) {
     ptr::write(this.as_mut_ptr(), String::new());
diff --git a/src/symbols/rust_vec.rs b/src/symbols/rust_vec.rs
index 9ce87ab..5465471 100644
--- a/src/symbols/rust_vec.rs
+++ b/src/symbols/rust_vec.rs
@@ -1,8 +1,9 @@
+use super::rust_string::RustString;
 use std::mem;
 use std::ptr;
 
 #[repr(C)]
-pub struct RustVec<T> {
+pub(crate) struct RustVec<T> {
     repr: Vec<T>,
 }
 
@@ -13,38 +14,38 @@
     };
 }
 
-macro_rules! rust_vec_shims_for_primitive {
-    ($ty:ident) => {
+macro_rules! rust_vec_shims {
+    ($segment:expr, $ty:ty) => {
         const_assert_eq!(mem::size_of::<[usize; 3]>(), mem::size_of::<Vec<$ty>>());
         const_assert_eq!(mem::align_of::<usize>(), mem::align_of::<Vec<$ty>>());
 
         const _: () = {
             attr! {
-                #[export_name = concat!("cxxbridge03$rust_vec$", stringify!($ty), "$new")]
+                #[export_name = concat!("cxxbridge03$rust_vec$", $segment, "$new")]
                 unsafe extern "C" fn __new(this: *mut RustVec<$ty>) {
                     ptr::write(this, RustVec { repr: Vec::new() });
                 }
             }
             attr! {
-                #[export_name = concat!("cxxbridge03$rust_vec$", stringify!($ty), "$drop")]
+                #[export_name = concat!("cxxbridge03$rust_vec$", $segment, "$drop")]
                 unsafe extern "C" fn __drop(this: *mut RustVec<$ty>) {
                     ptr::drop_in_place(this);
                 }
             }
             attr! {
-                #[export_name = concat!("cxxbridge03$rust_vec$", stringify!($ty), "$len")]
+                #[export_name = concat!("cxxbridge03$rust_vec$", $segment, "$len")]
                 unsafe extern "C" fn __len(this: *const RustVec<$ty>) -> usize {
                     (*this).repr.len()
                 }
             }
             attr! {
-                #[export_name = concat!("cxxbridge03$rust_vec$", stringify!($ty), "$data")]
+                #[export_name = concat!("cxxbridge03$rust_vec$", $segment, "$data")]
                 unsafe extern "C" fn __data(this: *const RustVec<$ty>) -> *const $ty {
                     (*this).repr.as_ptr()
                 }
             }
             attr! {
-                #[export_name = concat!("cxxbridge03$rust_vec$", stringify!($ty), "$stride")]
+                #[export_name = concat!("cxxbridge03$rust_vec$", $segment, "$stride")]
                 unsafe extern "C" fn __stride() -> usize {
                     mem::size_of::<$ty>()
                 }
@@ -53,6 +54,12 @@
     };
 }
 
+macro_rules! rust_vec_shims_for_primitive {
+    ($ty:ident) => {
+        rust_vec_shims!(stringify!($ty), $ty);
+    };
+}
+
 rust_vec_shims_for_primitive!(bool);
 rust_vec_shims_for_primitive!(u8);
 rust_vec_shims_for_primitive!(u16);
@@ -64,3 +71,5 @@
 rust_vec_shims_for_primitive!(i64);
 rust_vec_shims_for_primitive!(f32);
 rust_vec_shims_for_primitive!(f64);
+
+rust_vec_shims!("string", RustString);
diff --git a/syntax/check.rs b/syntax/check.rs
index c54430c..71fab3b 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -92,8 +92,9 @@
 
         match Atom::from(ident) {
             None | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize) | Some(I8)
-            | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32) | Some(F64) => return,
-            Some(Bool) | Some(RustString) => { /* todo */ }
+            | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32) | Some(F64)
+            | Some(RustString) => return,
+            Some(Bool) => { /* todo */ }
             Some(CxxString) => {}
         }
     }
diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs
index d69163a..cb688f3 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -46,6 +46,7 @@
         fn c_return_rust_vec() -> Vec<u8>;
         fn c_return_ref_rust_vec(c: &C) -> &Vec<u8>;
         fn c_return_mut_rust_vec(c: &mut C) -> &mut Vec<u8>;
+        fn c_return_rust_vec_string() -> Vec<String>;
         fn c_return_identity(_: usize) -> usize;
         fn c_return_sum(_: usize, _: usize) -> usize;
         fn c_return_enum(n: u16) -> Enum;
@@ -65,10 +66,12 @@
         fn c_take_ref_vector(v: &CxxVector<u8>);
         fn c_take_rust_vec(v: Vec<u8>);
         fn c_take_rust_vec_shared(v: Vec<Shared>);
+        fn c_take_rust_vec_string(v: Vec<String>);
         fn c_take_rust_vec_index(v: Vec<u8>);
         fn c_take_rust_vec_shared_index(v: Vec<Shared>);
         fn c_take_rust_vec_shared_forward_iterator(v: Vec<Shared>);
         fn c_take_ref_rust_vec(v: &Vec<u8>);
+        fn c_take_ref_rust_vec_string(v: &Vec<String>);
         fn c_take_ref_rust_vec_index(v: &Vec<u8>);
         fn c_take_ref_rust_vec_copy(v: &Vec<u8>);
         /*
@@ -87,6 +90,7 @@
         fn c_try_return_rust_string() -> Result<String>;
         fn c_try_return_unique_ptr_string() -> Result<UniquePtr<CxxString>>;
         fn c_try_return_rust_vec() -> Result<Vec<u8>>;
+        fn c_try_return_rust_vec_string() -> Result<Vec<String>>;
         fn c_try_return_ref_rust_vec(c: &C) -> Result<&Vec<u8>>;
 
         fn get(self: &C) -> usize;
@@ -121,6 +125,7 @@
         fn r_return_rust_string() -> String;
         fn r_return_unique_ptr_string() -> UniquePtr<CxxString>;
         fn r_return_rust_vec() -> Vec<u8>;
+        fn r_return_rust_vec_string() -> Vec<String>;
         fn r_return_ref_rust_vec(shared: &Shared) -> &Vec<u8>;
         fn r_return_mut_rust_vec(shared: &mut Shared) -> &mut Vec<u8>;
         fn r_return_identity(_: usize) -> usize;
@@ -138,7 +143,9 @@
         fn r_take_rust_string(s: String);
         fn r_take_unique_ptr_string(s: UniquePtr<CxxString>);
         fn r_take_rust_vec(v: Vec<u8>);
+        fn r_take_rust_vec_string(v: Vec<String>);
         fn r_take_ref_rust_vec(v: &Vec<u8>);
+        fn r_take_ref_rust_vec_string(v: &Vec<String>);
         fn r_take_enum(e: Enum);
 
         fn r_try_return_void() -> Result<()>;
@@ -224,6 +231,10 @@
     Vec::new()
 }
 
+fn r_return_rust_vec_string() -> Vec<String> {
+    Vec::new()
+}
+
 fn r_return_ref_rust_vec(shared: &ffi::Shared) -> &Vec<u8> {
     let _ = shared;
     unimplemented!()
@@ -297,10 +308,18 @@
     let _ = v;
 }
 
+fn r_take_rust_vec_string(v: Vec<String>) {
+    let _ = v;
+}
+
 fn r_take_ref_rust_vec(v: &Vec<u8>) {
     let _ = v;
 }
 
+fn r_take_ref_rust_vec_string(v: &Vec<String>) {
+    let _ = v;
+}
+
 fn r_take_enum(e: ffi::Enum) {
     let _ = e;
 }
diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc
index b213930..b45e8ae 100644
--- a/tests/ffi/tests.cc
+++ b/tests/ffi/tests.cc
@@ -119,6 +119,10 @@
   throw std::runtime_error("unimplemented");
 }
 
+rust::Vec<rust::String> c_return_rust_vec_string() {
+  throw std::runtime_error("unimplemented");
+}
+
 size_t c_return_identity(size_t n) { return n; }
 
 size_t c_return_sum(size_t n1, size_t n2) { return n1 + n2; }
@@ -241,6 +245,11 @@
   }
 }
 
+void c_take_rust_vec_string(rust::Vec<rust::String> v) {
+  (void)v;
+  cxx_test_suite_set_correct();
+}
+
 void c_take_rust_vec_shared_forward_iterator(rust::Vec<Shared> v) {
   // Exercise requirements of ForwardIterator
   // https://en.cppreference.com/w/cpp/named_req/ForwardIterator
@@ -267,6 +276,11 @@
   }
 }
 
+void c_take_ref_rust_vec_string(const rust::Vec<rust::String> &v) {
+  (void)v;
+  cxx_test_suite_set_correct();
+}
+
 void c_take_ref_rust_vec_index(const rust::Vec<uint8_t> &v) {
   if (v[0] == 86 && v.at(0) == 86 && v.front() == 86 && v[1] == 75 &&
       v.at(1) == 75 && v[3] == 9 && v.at(3) == 9 && v.back() == 9) {
@@ -323,6 +337,10 @@
   throw std::runtime_error("unimplemented");
 }
 
+rust::Vec<rust::String> c_try_return_rust_vec_string() {
+  throw std::runtime_error("unimplemented");
+}
+
 const rust::Vec<uint8_t> &c_try_return_ref_rust_vec(const C &c) {
   (void)c;
   throw std::runtime_error("unimplemented");
diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h
index fe644eb..0efbd62 100644
--- a/tests/ffi/tests.h
+++ b/tests/ffi/tests.h
@@ -50,6 +50,7 @@
 rust::Vec<uint8_t> c_return_rust_vec();
 const rust::Vec<uint8_t> &c_return_ref_rust_vec(const C &c);
 rust::Vec<uint8_t> &c_return_mut_rust_vec(C &c);
+rust::Vec<rust::String> c_return_rust_vec_string();
 size_t c_return_identity(size_t n);
 size_t c_return_sum(size_t n1, size_t n2);
 Enum c_return_enum(uint16_t n);
@@ -71,9 +72,11 @@
 void c_take_rust_vec(rust::Vec<uint8_t> v);
 void c_take_rust_vec_index(rust::Vec<uint8_t> v);
 void c_take_rust_vec_shared(rust::Vec<Shared> v);
+void c_take_rust_vec_string(rust::Vec<rust::String> v);
 void c_take_rust_vec_shared_index(rust::Vec<Shared> v);
 void c_take_rust_vec_shared_forward_iterator(rust::Vec<Shared> v);
 void c_take_ref_rust_vec(const rust::Vec<uint8_t> &v);
+void c_take_ref_rust_vec_string(const rust::Vec<rust::String> &v);
 void c_take_ref_rust_vec_index(const rust::Vec<uint8_t> &v);
 void c_take_ref_rust_vec_copy(const rust::Vec<uint8_t> &v);
 /*
@@ -92,6 +95,7 @@
 rust::String c_try_return_rust_string();
 std::unique_ptr<std::string> c_try_return_unique_ptr_string();
 rust::Vec<uint8_t> c_try_return_rust_vec();
+rust::Vec<rust::String> c_try_return_rust_vec_string();
 const rust::Vec<uint8_t> &c_try_return_ref_rust_vec(const C &c);
 
 } // namespace tests