Move vector element primitive macro to macro_rules
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 04003a0..1966d7a 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -681,43 +681,6 @@
     }
 }
 
-pub fn impl_vector_element_for_primitive(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_size = format!("{}size", prefix);
-    let link_get_unchecked = format!("{}get_unchecked", prefix);
-    let link_push_back = format!("{}push_back", prefix);
-
-    quote! {
-        unsafe impl VectorElement for #inner {
-            fn __vector_size(v: &CxxVector<#inner>) -> usize {
-                extern "C" {
-                    #[link_name = #link_size]
-                    fn __vector_size(_: &CxxVector<#inner>) -> usize;
-                }
-                unsafe { __vector_size(v) }
-            }
-            unsafe fn __get_unchecked(v: &CxxVector<#inner>, pos: usize) -> &#inner {
-                extern "C" {
-                    #[link_name = #link_get_unchecked]
-                    fn __get_unchecked(_: &CxxVector<#inner>, _: usize) -> *const #inner;
-                }
-                &*__get_unchecked(v, pos)
-            }
-            fn __push_back(v: &CxxVector<#inner>, item: &#inner) {
-                extern "C" {
-                    #[link_name = #link_push_back]
-                    fn __push_back(_: &CxxVector<#inner>, _: &#inner);
-                }
-                unsafe { __push_back(v, item) }
-            }
-        }
-    }
-}
-
 fn expand_return_type(ret: &Option<Type>) -> TokenStream {
     match ret {
         Some(ret) => quote!(-> #ret),
diff --git a/macro/src/lib.rs b/macro/src/lib.rs
index e6e5f2e..b56f58e 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, Ident, ItemMod};
+use syn::{parse_macro_input, ItemMod};
 
 /// `#[cxx::bridge] mod ffi { ... }`
 ///
@@ -44,9 +44,3 @@
         .unwrap_or_else(|err| err.to_compile_error())
         .into()
 }
-
-#[proc_macro]
-pub fn impl_vector_element_for_primitive(input: TokenStream) -> TokenStream {
-    let ident = parse_macro_input!(input as Ident);
-    expand::impl_vector_element_for_primitive(ident).into()
-}
diff --git a/src/concat.rs b/src/concat.rs
new file mode 100644
index 0000000..e67e50d
--- /dev/null
+++ b/src/concat.rs
@@ -0,0 +1,6 @@
+macro_rules! attr {
+    (#[$name:ident = $value:expr] $($rest:tt)*) => {
+        #[$name = $value]
+        $($rest)*
+    };
+}
diff --git a/src/cxx_vector.rs b/src/cxx_vector.rs
index 829e12a..f7fb5ac 100644
--- a/src/cxx_vector.rs
+++ b/src/cxx_vector.rs
@@ -1,4 +1,3 @@
-use cxxbridge_macro::impl_vector_element_for_primitive;
 use std::mem;
 
 /// Binding to C++ `std::vector<T>`.
@@ -82,6 +81,40 @@
     fn __push_back(v: &CxxVector<Self>, item: &Self);
 }
 
+macro_rules! impl_vector_element_for_primitive {
+    ($ty:ident) => {
+        unsafe impl VectorElement for $ty {
+            fn __vector_size(v: &CxxVector<$ty>) -> usize {
+                extern "C" {
+                    attr! {
+                        #[link_name = concat!("cxxbridge02$std$vector$", stringify!($ty), "$size")]
+                        fn __vector_size(_: &CxxVector<$ty>) -> usize;
+                    }
+                }
+                unsafe { __vector_size(v) }
+            }
+            unsafe fn __get_unchecked(v: &CxxVector<$ty>, pos: usize) -> &$ty {
+                extern "C" {
+                    attr! {
+                        #[link_name = concat!("cxxbridge02$std$vector$", stringify!($ty), "$get_unchecked")]
+                        fn __get_unchecked(_: &CxxVector<$ty>, _: usize) -> *const $ty;
+                    }
+                }
+                &*__get_unchecked(v, pos)
+            }
+            fn __push_back(v: &CxxVector<$ty>, item: &$ty) {
+                extern "C" {
+                    attr! {
+                        #[link_name = concat!("cxxbridge02$std$vector$", stringify!($ty), "$push_back")]
+                        fn __push_back(_: &CxxVector<$ty>, _: &$ty);
+                    }
+                }
+                unsafe { __push_back(v, item) }
+            }
+        }
+    };
+}
+
 impl_vector_element_for_primitive!(u8);
 impl_vector_element_for_primitive!(u16);
 impl_vector_element_for_primitive!(u32);
diff --git a/src/lib.rs b/src/lib.rs
index 1af4d0f..c9f4667 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -358,6 +358,8 @@
 
 #[macro_use]
 mod assert;
+#[macro_use]
+mod concat;
 
 mod cxx_string;
 mod cxx_vector;