Use Symbol for mangled names throughout code generators
diff --git a/gen/write.rs b/gen/write.rs
index 4df404c..c100691 100644
--- a/gen/write.rs
+++ b/gen/write.rs
@@ -2,6 +2,7 @@
 use crate::gen::{include, Opt};
 use crate::syntax::atom::Atom::{self, *};
 use crate::syntax::namespace::Namespace;
+use crate::syntax::symbol::Symbol;
 use crate::syntax::{
     mangle, Api, ExternFn, ExternType, Receiver, Signature, Struct, Type, Types, Var,
 };
@@ -334,7 +335,7 @@
     for method in methods {
         write!(out, "  ");
         let sig = &method.sig;
-        let local_name = method.ident.to_string();
+        let local_name = Symbol::from(&method.ident);
         write_rust_function_shim_decl(out, &local_name, sig, None, false);
         writeln!(out, ";");
     }
@@ -504,12 +505,12 @@
     types: &Types,
 ) {
     out.next_section();
-    let r_trampoline = format!("{}cxxbridge02${}${}$1", out.namespace, efn.ident, var);
+    let r_trampoline = mangle::r_trampoline(&out.namespace, efn, var);
     let indirect_call = true;
     write_rust_function_decl_impl(out, &r_trampoline, f, types, indirect_call);
 
     out.next_section();
-    let c_trampoline = format!("{}cxxbridge02${}${}$0", out.namespace, efn.ident, var);
+    let c_trampoline = mangle::c_trampoline(&out.namespace, efn, var);
     write_rust_function_shim_impl(out, &c_trampoline, f, types, &r_trampoline, indirect_call);
 }
 
@@ -521,7 +522,7 @@
 
 fn write_rust_function_decl_impl(
     out: &mut OutFile,
-    link_name: &str,
+    link_name: &Symbol,
     sig: &Signature,
     types: &Types,
     indirect_call: bool,
@@ -565,7 +566,7 @@
     for line in efn.doc.to_string().lines() {
         writeln!(out, "//{}", line);
     }
-    let local_name = efn.ident.to_string();
+    let local_name = Symbol::from(&efn.ident);
     let invoke = mangle::extern_fn(&out.namespace, efn);
     let indirect_call = false;
     write_rust_function_shim_impl(out, &local_name, efn, types, &invoke, indirect_call);
@@ -573,7 +574,7 @@
 
 fn write_rust_function_shim_decl(
     out: &mut OutFile,
-    local_name: &str,
+    local_name: &Symbol,
     sig: &Signature,
     receiver: Option<&Receiver>,
     indirect_call: bool,
@@ -604,10 +605,10 @@
 
 fn write_rust_function_shim_impl(
     out: &mut OutFile,
-    local_name: &str,
+    local_name: &Symbol,
     sig: &Signature,
     types: &Types,
-    invoke: &str,
+    invoke: &Symbol,
     indirect_call: bool,
 ) {
     if out.header && sig.receiver.is_some() {
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index d8bd241..2155ba0 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -1,5 +1,6 @@
 use crate::syntax::atom::Atom::{self, *};
 use crate::syntax::namespace::Namespace;
+use crate::syntax::symbol::Symbol;
 use crate::syntax::{
     self, check, mangle, Api, ExternFn, ExternType, Signature, Struct, Type, Types,
 };
@@ -331,8 +332,8 @@
     sig: &Signature,
     types: &Types,
 ) -> TokenStream {
-    let c_trampoline = format!("{}cxxbridge02${}${}$0", namespace, efn.ident, var);
-    let r_trampoline = format!("{}cxxbridge02${}${}$1", namespace, efn.ident, var);
+    let c_trampoline = mangle::c_trampoline(namespace, efn, var);
+    let r_trampoline = mangle::r_trampoline(namespace, efn, var);
     let local_name = parse_quote!(__);
     let catch_unwind_label = format!("::{}::{}", efn.ident, var);
     let shim = expand_rust_function_shim_impl(
@@ -385,7 +386,7 @@
 fn expand_rust_function_shim_impl(
     sig: &Signature,
     types: &Types,
-    link_name: &str,
+    link_name: &Symbol,
     local_name: Ident,
     catch_unwind_label: String,
     invoke: Option<&Ident>,
diff --git a/syntax/mangle.rs b/syntax/mangle.rs
index f2616d2..6f4e0d8 100644
--- a/syntax/mangle.rs
+++ b/syntax/mangle.rs
@@ -1,5 +1,7 @@
 use crate::syntax::namespace::Namespace;
-use crate::syntax::{symbol, ExternFn};
+use crate::syntax::symbol::{self, Symbol};
+use crate::syntax::ExternFn;
+use proc_macro2::Ident;
 
 const CXXBRIDGE: &str = "cxxbridge02";
 
@@ -9,10 +11,19 @@
     };
 }
 
-pub fn extern_fn(namespace: &Namespace, efn: &ExternFn) -> String {
+pub fn extern_fn(namespace: &Namespace, efn: &ExternFn) -> Symbol {
     match &efn.receiver {
         Some(receiver) => join!(namespace, CXXBRIDGE, receiver.ident, efn.ident),
         None => join!(namespace, CXXBRIDGE, efn.ident),
     }
-    .to_string()
+}
+
+// The C half of a function pointer trampoline.
+pub fn c_trampoline(namespace: &Namespace, efn: &ExternFn, var: &Ident) -> Symbol {
+    join!(extern_fn(namespace, efn), var, 0)
+}
+
+// The Rust half of a function pointer trampoline.
+pub fn r_trampoline(namespace: &Namespace, efn: &ExternFn, var: &Ident) -> Symbol {
+    join!(extern_fn(namespace, efn), var, 1)
 }
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 81b1a2f..49bb299 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -11,7 +11,7 @@
 pub mod namespace;
 mod parse;
 pub mod set;
-mod symbol;
+pub mod symbol;
 mod tokens;
 pub mod types;
 
diff --git a/syntax/symbol.rs b/syntax/symbol.rs
index a40baaf..fa8e587 100644
--- a/syntax/symbol.rs
+++ b/syntax/symbol.rs
@@ -19,6 +19,12 @@
     }
 }
 
+impl From<&Ident> for Symbol {
+    fn from(ident: &Ident) -> Self {
+        Symbol(ident.to_string())
+    }
+}
+
 impl Symbol {
     fn push(&mut self, segment: &dyn Display) {
         let len_before = self.0.len();
@@ -37,7 +43,9 @@
 }
 
 impl Segment for str {}
+impl Segment for usize {}
 impl Segment for Ident {}
+impl Segment for Symbol {}
 
 impl Segment for Namespace {
     fn write(&self, symbol: &mut Symbol) {