Allow namespace override.

This change allows a

 #[namespace (namespace = A::B)]

attribute for each item in a cxx::bridge.

We now have a fair number of different types of name floating
around:
* C++ identifiers
* C++ fully-qualified names
* Rust identifiers
* Rust fully-qualified names (future, when we support sub-modules)
* Items with both a Rust and C++ name (a 'Pair')
* Types with only a known Rust name, which can be resolved to a
  C++ name.

This change attempts to put some sensible names for all these
things in syntax/mod.rs, and so that would be a good place to start
review.

At the moment, the Namespace (included in each CppName)
is ruthlessly cloned all over the place. As a given namespace is
likely to be applicable to many types and functions, it may
save significant memory in future to use Rc<> here. But let's not
optimise too early.
diff --git a/gen/src/write.rs b/gen/src/write.rs
index 3184604..2ff5b47 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -1,20 +1,17 @@
+use crate::gen::namespace_organizer::{sort_by_namespace, NamespaceEntries};
 use crate::gen::out::OutFile;
 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, Enum, ExternFn, ExternType, Signature, Struct, Type, Types, Var};
+use crate::syntax::{
+    mangle, Api, CppName, Enum, ExternFn, ExternType, ResolvableName, Signature, Struct, Type,
+    Types, Var,
+};
 use proc_macro2::Ident;
 use std::collections::HashMap;
 
-pub(super) fn gen(
-    namespace: &Namespace,
-    apis: &[Api],
-    types: &Types,
-    opt: &Opt,
-    header: bool,
-) -> OutFile {
-    let mut out_file = OutFile::new(namespace.clone(), header);
+pub(super) fn gen(apis: &[Api], types: &Types, opt: &Opt, header: bool) -> OutFile {
+    let mut out_file = OutFile::new(header);
     let out = &mut out_file;
 
     if header {
@@ -32,16 +29,36 @@
     write_include_cxxbridge(out, apis, types);
 
     out.next_section();
-    for name in namespace {
-        writeln!(out, "namespace {} {{", name);
+
+    let apis_by_namespace = sort_by_namespace(apis);
+
+    gen_namespace_contents(&apis_by_namespace, types, opt, header, out);
+
+    if !header {
+        out.next_section();
+        write_generic_instantiations(out, types);
     }
 
+    write!(out.front, "{}", out.include);
+
+    out_file
+}
+
+fn gen_namespace_contents(
+    ns_entries: &NamespaceEntries,
+    types: &Types,
+    opt: &Opt,
+    header: bool,
+    out: &mut OutFile,
+) {
+    let apis = &ns_entries.entries;
+
     out.next_section();
     for api in apis {
         match api {
-            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),
+            Api::Struct(strct) => write_struct_decl(out, &strct.ident.cxx.ident),
+            Api::CxxType(ety) => write_struct_using(out, &ety.ident.cxx),
+            Api::RustType(ety) => write_struct_decl(out, &ety.ident.cxx.ident),
             _ => {}
         }
     }
@@ -51,7 +68,7 @@
         if let Api::RustFunction(efn) = api {
             if let Some(receiver) = &efn.sig.receiver {
                 methods_for_type
-                    .entry(&receiver.ty)
+                    .entry(&receiver.ty.rust)
                     .or_insert_with(Vec::new)
                     .push(efn);
             }
@@ -62,22 +79,22 @@
         match api {
             Api::Struct(strct) => {
                 out.next_section();
-                if !types.cxx.contains(&strct.ident) {
-                    write_struct(out, strct);
+                if !types.cxx.contains(&strct.ident.rust) {
+                    write_struct(out, strct, types);
                 }
             }
             Api::Enum(enm) => {
                 out.next_section();
-                if types.cxx.contains(&enm.ident) {
+                if types.cxx.contains(&enm.ident.rust) {
                     check_enum(out, enm);
                 } else {
                     write_enum(out, enm);
                 }
             }
             Api::RustType(ety) => {
-                if let Some(methods) = methods_for_type.get(&ety.ident) {
+                if let Some(methods) = methods_for_type.get(&ety.ident.rust) {
                     out.next_section();
-                    write_struct_with_methods(out, ety, methods);
+                    write_struct_with_methods(out, ety, methods, types);
                 }
             }
             _ => {}
@@ -87,8 +104,8 @@
     out.next_section();
     for api in apis {
         if let Api::TypeAlias(ety) = api {
-            if types.required_trivial.contains_key(&ety.ident) {
-                check_trivial_extern_type(out, &ety.ident)
+            if types.required_trivial.contains_key(&ety.ident.rust) {
+                check_trivial_extern_type(out, &ety.ident.cxx)
             }
         }
     }
@@ -116,24 +133,18 @@
     }
 
     out.next_section();
-    for name in namespace.iter().rev() {
-        writeln!(out, "}} // namespace {}", name);
+
+    for (child_ns, child_ns_entries) in &ns_entries.children {
+        writeln!(out, "namespace {} {{", child_ns);
+        gen_namespace_contents(&child_ns_entries, types, opt, header, out);
+        writeln!(out, "}} // namespace {}", child_ns);
     }
-
-    if !header {
-        out.next_section();
-        write_generic_instantiations(out, types);
-    }
-
-    write!(out.front, "{}", out.include);
-
-    out_file
 }
 
 fn write_includes(out: &mut OutFile, types: &Types) {
     for ty in types {
         match ty {
-            Type::Ident(ident) => match Atom::from(ident) {
+            Type::Ident(ident) => match Atom::from(&ident.rust) {
                 Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(I8) | Some(I16) | Some(I32)
                 | Some(I64) => out.include.cstdint = true,
                 Some(Usize) => out.include.cstddef = true,
@@ -332,17 +343,17 @@
     out.end_block("namespace rust");
 }
 
-fn write_struct(out: &mut OutFile, strct: &Struct) {
-    let guard = format!("CXXBRIDGE05_STRUCT_{}{}", out.namespace, strct.ident);
+fn write_struct(out: &mut OutFile, strct: &Struct, types: &Types) {
+    let guard = format!("CXXBRIDGE05_STRUCT_{}", strct.ident.cxx.to_symbol());
     writeln!(out, "#ifndef {}", guard);
     writeln!(out, "#define {}", guard);
     for line in strct.doc.to_string().lines() {
         writeln!(out, "//{}", line);
     }
-    writeln!(out, "struct {} final {{", strct.ident);
+    writeln!(out, "struct {} final {{", strct.ident.cxx.ident);
     for field in &strct.fields {
         write!(out, "  ");
-        write_type_space(out, &field.ty);
+        write_type_space(out, &field.ty, types);
         writeln!(out, "{};", field.ident);
     }
     writeln!(out, "}};");
@@ -353,25 +364,39 @@
     writeln!(out, "struct {};", ident);
 }
 
-fn write_struct_using(out: &mut OutFile, ident: &Ident) {
-    writeln!(out, "using {} = {};", ident, ident);
+fn write_struct_using(out: &mut OutFile, ident: &CppName) {
+    writeln!(
+        out,
+        "using {} = {};",
+        ident.ident,
+        ident.to_fully_qualified()
+    );
 }
 
-fn write_struct_with_methods(out: &mut OutFile, ety: &ExternType, methods: &[&ExternFn]) {
-    let guard = format!("CXXBRIDGE05_STRUCT_{}{}", out.namespace, ety.ident);
+fn write_struct_with_methods(
+    out: &mut OutFile,
+    ety: &ExternType,
+    methods: &[&ExternFn],
+    types: &Types,
+) {
+    let guard = format!("CXXBRIDGE05_STRUCT_{}", ety.ident.cxx.to_symbol());
     writeln!(out, "#ifndef {}", guard);
     writeln!(out, "#define {}", guard);
     for line in ety.doc.to_string().lines() {
         writeln!(out, "//{}", line);
     }
-    writeln!(out, "struct {} final {{", ety.ident);
-    writeln!(out, "  {}() = delete;", ety.ident);
-    writeln!(out, "  {}(const {} &) = delete;", ety.ident, ety.ident);
+    writeln!(out, "struct {} final {{", ety.ident.cxx.ident);
+    writeln!(out, "  {}() = delete;", ety.ident.cxx.ident);
+    writeln!(
+        out,
+        "  {}(const {} &) = delete;",
+        ety.ident.cxx.ident, ety.ident.cxx.ident
+    );
     for method in methods {
         write!(out, "  ");
         let sig = &method.sig;
-        let local_name = method.ident.cxx.to_string();
-        write_rust_function_shim_decl(out, &local_name, sig, false);
+        let local_name = method.ident.cxx.ident.to_string();
+        write_rust_function_shim_decl(out, &local_name, sig, false, types);
         writeln!(out, ";");
     }
     writeln!(out, "}};");
@@ -379,13 +404,13 @@
 }
 
 fn write_enum(out: &mut OutFile, enm: &Enum) {
-    let guard = format!("CXXBRIDGE05_ENUM_{}{}", out.namespace, enm.ident);
+    let guard = format!("CXXBRIDGE05_ENUM_{}", enm.ident.cxx.to_symbol());
     writeln!(out, "#ifndef {}", guard);
     writeln!(out, "#define {}", guard);
     for line in enm.doc.to_string().lines() {
         writeln!(out, "//{}", line);
     }
-    write!(out, "enum class {} : ", enm.ident);
+    write!(out, "enum class {} : ", enm.ident.cxx.ident);
     write_atom(out, enm.repr);
     writeln!(out, " {{");
     for variant in &enm.variants {
@@ -396,7 +421,11 @@
 }
 
 fn check_enum(out: &mut OutFile, enm: &Enum) {
-    write!(out, "static_assert(sizeof({}) == sizeof(", enm.ident);
+    write!(
+        out,
+        "static_assert(sizeof({}) == sizeof(",
+        enm.ident.cxx.ident
+    );
     write_atom(out, enm.repr);
     writeln!(out, "), \"incorrect size\");");
     for variant in &enm.variants {
@@ -405,12 +434,12 @@
         writeln!(
             out,
             ">({}::{}) == {}, \"disagrees with the value in #[cxx::bridge]\");",
-            enm.ident, variant.ident, variant.discriminant,
+            enm.ident.cxx.ident, variant.ident, variant.discriminant,
         );
     }
 }
 
-fn check_trivial_extern_type(out: &mut OutFile, id: &Ident) {
+fn check_trivial_extern_type(out: &mut OutFile, id: &CppName) {
     // NOTE: The following two static assertions are just nice-to-have and not
     // necessary for soundness. That's because triviality is always declared by
     // the user in the form of an unsafe impl of cxx::ExternType:
@@ -429,6 +458,7 @@
     // not being recognized as such by the C++ type system due to a move
     // constructor or destructor.
 
+    let id = &id.to_fully_qualified();
     out.include.type_traits = true;
     writeln!(out, "static_assert(");
     writeln!(
@@ -450,7 +480,7 @@
     );
 }
 
-fn write_exception_glue(out: &mut OutFile, apis: &[Api]) {
+fn write_exception_glue(out: &mut OutFile, apis: &[&Api]) {
     let mut has_cxx_throws = false;
     for api in apis {
         if let Api::CxxFunction(efn) = api {
@@ -486,13 +516,17 @@
     } else {
         write_extern_return_type_space(out, &efn.ret, types);
     }
-    let mangled = mangle::extern_fn(&out.namespace, efn);
+    let mangled = mangle::extern_fn(efn, types);
     write!(out, "{}(", mangled);
     if let Some(receiver) = &efn.receiver {
         if receiver.mutability.is_none() {
             write!(out, "const ");
         }
-        write!(out, "{} &self", receiver.ty);
+        write!(
+            out,
+            "{} &self",
+            types.resolve(&receiver.ty).to_fully_qualified()
+        );
     }
     for (i, arg) in efn.args.iter().enumerate() {
         if i > 0 || efn.receiver.is_some() {
@@ -510,21 +544,26 @@
         if !efn.args.is_empty() || efn.receiver.is_some() {
             write!(out, ", ");
         }
-        write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
+        write_indirect_return_type_space(out, efn.ret.as_ref().unwrap(), types);
         write!(out, "*return$");
     }
     writeln!(out, ") noexcept {{");
     write!(out, "  ");
-    write_return_type(out, &efn.ret);
+    write_return_type(out, &efn.ret, types);
     match &efn.receiver {
         None => write!(out, "(*{}$)(", efn.ident.rust),
-        Some(receiver) => write!(out, "({}::*{}$)(", receiver.ty, efn.ident.rust),
+        Some(receiver) => write!(
+            out,
+            "({}::*{}$)(",
+            types.resolve(&receiver.ty).to_fully_qualified(),
+            efn.ident.rust
+        ),
     }
     for (i, arg) in efn.args.iter().enumerate() {
         if i > 0 {
             write!(out, ", ");
         }
-        write_type(out, &arg.ty);
+        write_type(out, &arg.ty, types);
     }
     write!(out, ")");
     if let Some(receiver) = &efn.receiver {
@@ -534,8 +573,13 @@
     }
     write!(out, " = ");
     match &efn.receiver {
-        None => write!(out, "{}", efn.ident.cxx),
-        Some(receiver) => write!(out, "&{}::{}", receiver.ty, efn.ident.cxx),
+        None => write!(out, "{}", efn.ident.cxx.to_fully_qualified()),
+        Some(receiver) => write!(
+            out,
+            "&{}::{}",
+            types.resolve(&receiver.ty).to_fully_qualified(),
+            efn.ident.cxx.ident
+        ),
     }
     writeln!(out, ";");
     write!(out, "  ");
@@ -548,7 +592,7 @@
     if indirect_return {
         out.include.new = true;
         write!(out, "new (return$) ");
-        write_indirect_return_type(out, efn.ret.as_ref().unwrap());
+        write_indirect_return_type(out, efn.ret.as_ref().unwrap(), types);
         write!(out, "(");
     } else if efn.ret.is_some() {
         write!(out, "return ");
@@ -570,10 +614,10 @@
             write!(out, ", ");
         }
         if let Type::RustBox(_) = &arg.ty {
-            write_type(out, &arg.ty);
+            write_type(out, &arg.ty, types);
             write!(out, "::from_raw({})", arg.ident);
         } else if let Type::UniquePtr(_) = &arg.ty {
-            write_type(out, &arg.ty);
+            write_type(out, &arg.ty, types);
             write!(out, "({})", arg.ident);
         } else if arg.ty == RustString {
             write!(
@@ -582,7 +626,7 @@
                 arg.ident,
             );
         } else if let Type::RustVec(_) = arg.ty {
-            write_type(out, &arg.ty);
+            write_type(out, &arg.ty, types);
             write!(out, "(::rust::unsafe_bitcopy, *{})", arg.ident);
         } else if types.needs_indirect_abi(&arg.ty) {
             out.include.utility = true;
@@ -632,17 +676,17 @@
     types: &Types,
 ) {
     out.next_section();
-    let r_trampoline = mangle::r_trampoline(&out.namespace, efn, var);
+    let r_trampoline = mangle::r_trampoline(efn, var, types);
     let indirect_call = true;
     write_rust_function_decl_impl(out, &r_trampoline, f, types, indirect_call);
 
     out.next_section();
-    let c_trampoline = mangle::c_trampoline(&out.namespace, efn, var).to_string();
+    let c_trampoline = mangle::c_trampoline(efn, var, types).to_string();
     write_rust_function_shim_impl(out, &c_trampoline, f, types, &r_trampoline, indirect_call);
 }
 
 fn write_rust_function_decl(out: &mut OutFile, efn: &ExternFn, types: &Types, _: &Option<String>) {
-    let link_name = mangle::extern_fn(&out.namespace, efn);
+    let link_name = mangle::extern_fn(efn, types);
     let indirect_call = false;
     write_rust_function_decl_impl(out, &link_name, efn, types, indirect_call);
 }
@@ -665,7 +709,11 @@
         if receiver.mutability.is_none() {
             write!(out, "const ");
         }
-        write!(out, "{} &self", receiver.ty);
+        write!(
+            out,
+            "{} &self",
+            types.resolve(&receiver.ty).to_fully_qualified()
+        );
         needs_comma = true;
     }
     for arg in &sig.args {
@@ -679,7 +727,7 @@
         if needs_comma {
             write!(out, ", ");
         }
-        write_return_type(out, &sig.ret);
+        write_return_type(out, &sig.ret, types);
         write!(out, "*return$");
         needs_comma = true;
     }
@@ -697,10 +745,14 @@
         writeln!(out, "//{}", line);
     }
     let local_name = match &efn.sig.receiver {
-        None => efn.ident.cxx.to_string(),
-        Some(receiver) => format!("{}::{}", receiver.ty, efn.ident.cxx),
+        None => efn.ident.cxx.ident.to_string(),
+        Some(receiver) => format!(
+            "{}::{}",
+            types.resolve(&receiver.ty).ident,
+            efn.ident.cxx.ident
+        ),
     };
-    let invoke = mangle::extern_fn(&out.namespace, efn);
+    let invoke = mangle::extern_fn(efn, types);
     let indirect_call = false;
     write_rust_function_shim_impl(out, &local_name, efn, types, &invoke, indirect_call);
 }
@@ -710,14 +762,15 @@
     local_name: &str,
     sig: &Signature,
     indirect_call: bool,
+    types: &Types,
 ) {
-    write_return_type(out, &sig.ret);
+    write_return_type(out, &sig.ret, types);
     write!(out, "{}(", local_name);
     for (i, arg) in sig.args.iter().enumerate() {
         if i > 0 {
             write!(out, ", ");
         }
-        write_type_space(out, &arg.ty);
+        write_type_space(out, &arg.ty, types);
         write!(out, "{}", arg.ident);
     }
     if indirect_call {
@@ -749,7 +802,7 @@
         // We've already defined this inside the struct.
         return;
     }
-    write_rust_function_shim_decl(out, local_name, sig, indirect_call);
+    write_rust_function_shim_decl(out, local_name, sig, indirect_call, types);
     if out.header {
         writeln!(out, ";");
         return;
@@ -759,7 +812,7 @@
         if arg.ty != RustString && types.needs_indirect_abi(&arg.ty) {
             out.include.utility = true;
             write!(out, "  ::rust::ManuallyDrop<");
-            write_type(out, &arg.ty);
+            write_type(out, &arg.ty, types);
             writeln!(out, "> {}$(::std::move({0}));", arg.ident);
         }
     }
@@ -767,18 +820,18 @@
     let indirect_return = indirect_return(sig, types);
     if indirect_return {
         write!(out, "::rust::MaybeUninit<");
-        write_type(out, sig.ret.as_ref().unwrap());
+        write_type(out, sig.ret.as_ref().unwrap(), types);
         writeln!(out, "> return$;");
         write!(out, "  ");
     } else if let Some(ret) = &sig.ret {
         write!(out, "return ");
         match ret {
             Type::RustBox(_) => {
-                write_type(out, ret);
+                write_type(out, ret, types);
                 write!(out, "::from_raw(");
             }
             Type::UniquePtr(_) => {
-                write_type(out, ret);
+                write_type(out, ret, types);
                 write!(out, "(");
             }
             Type::Ref(_) => write!(out, "*"),
@@ -844,10 +897,10 @@
     writeln!(out, "}}");
 }
 
-fn write_return_type(out: &mut OutFile, ty: &Option<Type>) {
+fn write_return_type(out: &mut OutFile, ty: &Option<Type>, types: &Types) {
     match ty {
         None => write!(out, "void "),
-        Some(ty) => write_type_space(out, ty),
+        Some(ty) => write_type_space(out, ty, types),
     }
 }
 
@@ -857,27 +910,27 @@
         .map_or(false, |ret| sig.throws || types.needs_indirect_abi(ret))
 }
 
-fn write_indirect_return_type(out: &mut OutFile, ty: &Type) {
+fn write_indirect_return_type(out: &mut OutFile, ty: &Type, types: &Types) {
     match ty {
         Type::RustBox(ty) | Type::UniquePtr(ty) => {
-            write_type_space(out, &ty.inner);
+            write_type_space(out, &ty.inner, types);
             write!(out, "*");
         }
         Type::Ref(ty) => {
             if ty.mutability.is_none() {
                 write!(out, "const ");
             }
-            write_type(out, &ty.inner);
+            write_type(out, &ty.inner, types);
             write!(out, " *");
         }
         Type::Str(_) => write!(out, "::rust::Str::Repr"),
         Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr"),
-        _ => write_type(out, ty),
+        _ => write_type(out, ty, types),
     }
 }
 
-fn write_indirect_return_type_space(out: &mut OutFile, ty: &Type) {
-    write_indirect_return_type(out, ty);
+fn write_indirect_return_type_space(out: &mut OutFile, ty: &Type, types: &Types) {
+    write_indirect_return_type(out, ty, types);
     match ty {
         Type::RustBox(_) | Type::UniquePtr(_) | Type::Ref(_) => {}
         Type::Str(_) | Type::SliceRefU8(_) => write!(out, " "),
@@ -888,32 +941,32 @@
 fn write_extern_return_type_space(out: &mut OutFile, ty: &Option<Type>, types: &Types) {
     match ty {
         Some(Type::RustBox(ty)) | Some(Type::UniquePtr(ty)) => {
-            write_type_space(out, &ty.inner);
+            write_type_space(out, &ty.inner, types);
             write!(out, "*");
         }
         Some(Type::Ref(ty)) => {
             if ty.mutability.is_none() {
                 write!(out, "const ");
             }
-            write_type(out, &ty.inner);
+            write_type(out, &ty.inner, types);
             write!(out, " *");
         }
         Some(Type::Str(_)) => write!(out, "::rust::Str::Repr "),
         Some(Type::SliceRefU8(_)) => write!(out, "::rust::Slice<uint8_t>::Repr "),
         Some(ty) if types.needs_indirect_abi(ty) => write!(out, "void "),
-        _ => write_return_type(out, ty),
+        _ => write_return_type(out, ty, types),
     }
 }
 
 fn write_extern_arg(out: &mut OutFile, arg: &Var, types: &Types) {
     match &arg.ty {
         Type::RustBox(ty) | Type::UniquePtr(ty) | Type::CxxVector(ty) => {
-            write_type_space(out, &ty.inner);
+            write_type_space(out, &ty.inner, types);
             write!(out, "*");
         }
         Type::Str(_) => write!(out, "::rust::Str::Repr "),
         Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr "),
-        _ => write_type_space(out, &arg.ty),
+        _ => write_type_space(out, &arg.ty, types),
     }
     if types.needs_indirect_abi(&arg.ty) {
         write!(out, "*");
@@ -921,37 +974,37 @@
     write!(out, "{}", arg.ident);
 }
 
-fn write_type(out: &mut OutFile, ty: &Type) {
+fn write_type(out: &mut OutFile, ty: &Type, types: &Types) {
     match ty {
-        Type::Ident(ident) => match Atom::from(ident) {
+        Type::Ident(ident) => match Atom::from(&ident.rust) {
             Some(atom) => write_atom(out, atom),
-            None => write!(out, "{}", ident),
+            None => write!(out, "{}", types.resolve(ident).to_fully_qualified()),
         },
         Type::RustBox(ty) => {
             write!(out, "::rust::Box<");
-            write_type(out, &ty.inner);
+            write_type(out, &ty.inner, types);
             write!(out, ">");
         }
         Type::RustVec(ty) => {
             write!(out, "::rust::Vec<");
-            write_type(out, &ty.inner);
+            write_type(out, &ty.inner, types);
             write!(out, ">");
         }
         Type::UniquePtr(ptr) => {
             write!(out, "::std::unique_ptr<");
-            write_type(out, &ptr.inner);
+            write_type(out, &ptr.inner, types);
             write!(out, ">");
         }
         Type::CxxVector(ty) => {
             write!(out, "::std::vector<");
-            write_type(out, &ty.inner);
+            write_type(out, &ty.inner, types);
             write!(out, ">");
         }
         Type::Ref(r) => {
             if r.mutability.is_none() {
                 write!(out, "const ");
             }
-            write_type(out, &r.inner);
+            write_type(out, &r.inner, types);
             write!(out, " &");
         }
         Type::Slice(_) => {
@@ -967,7 +1020,7 @@
         Type::Fn(f) => {
             write!(out, "::rust::{}<", if f.throws { "TryFn" } else { "Fn" });
             match &f.ret {
-                Some(ret) => write_type(out, ret),
+                Some(ret) => write_type(out, ret, types),
                 None => write!(out, "void"),
             }
             write!(out, "(");
@@ -975,7 +1028,7 @@
                 if i > 0 {
                     write!(out, ", ");
                 }
-                write_type(out, &arg.ty);
+                write_type(out, &arg.ty, types);
             }
             write!(out, ")>");
         }
@@ -1003,8 +1056,8 @@
     }
 }
 
-fn write_type_space(out: &mut OutFile, ty: &Type) {
-    write_type(out, ty);
+fn write_type_space(out: &mut OutFile, ty: &Type, types: &Types) {
+    write_type(out, ty, types);
     write_space_after_type(out, ty);
 }
 
@@ -1025,28 +1078,20 @@
 
 // Only called for legal referent types of unique_ptr and element types of
 // std::vector and Vec.
-fn to_typename(namespace: &Namespace, ty: &Type) -> String {
+fn to_typename(ty: &Type, types: &Types) -> String {
     match ty {
-        Type::Ident(ident) => {
-            let mut path = String::new();
-            for name in namespace {
-                path += &name.to_string();
-                path += "::";
-            }
-            path += &ident.to_string();
-            path
-        }
-        Type::CxxVector(ptr) => format!("::std::vector<{}>", to_typename(namespace, &ptr.inner)),
+        Type::Ident(ident) => types.resolve(&ident).to_fully_qualified(),
+        Type::CxxVector(ptr) => format!("::std::vector<{}>", to_typename(&ptr.inner, types)),
         _ => unreachable!(),
     }
 }
 
 // Only called for legal referent types of unique_ptr and element types of
 // std::vector and Vec.
-fn to_mangled(namespace: &Namespace, ty: &Type) -> String {
+fn to_mangled(ty: &Type, types: &Types) -> Symbol {
     match ty {
-        Type::Ident(_) => to_typename(namespace, ty).replace("::", "$"),
-        Type::CxxVector(ptr) => format!("std$vector${}", to_mangled(namespace, &ptr.inner)),
+        Type::Ident(ident) => ident.to_symbol(types),
+        Type::CxxVector(ptr) => to_mangled(&ptr.inner, types).prefix_with("std$vector$"),
         _ => unreachable!(),
     }
 }
@@ -1057,19 +1102,20 @@
         if let Type::RustBox(ty) = ty {
             if let Type::Ident(inner) = &ty.inner {
                 out.next_section();
-                write_rust_box_extern(out, inner);
+                write_rust_box_extern(out, &types.resolve(&inner));
             }
         } else if let Type::RustVec(ty) = ty {
             if let Type::Ident(inner) = &ty.inner {
-                if Atom::from(inner).is_none() {
+                if Atom::from(&inner.rust).is_none() {
                     out.next_section();
-                    write_rust_vec_extern(out, inner);
+                    write_rust_vec_extern(out, inner, types);
                 }
             }
         } else if let Type::UniquePtr(ptr) = ty {
             if let Type::Ident(inner) = &ptr.inner {
-                if Atom::from(inner).is_none()
-                    && (!types.aliases.contains_key(inner) || types.explicit_impls.contains(ty))
+                if Atom::from(&inner.rust).is_none()
+                    && (!types.aliases.contains_key(&inner.rust)
+                        || types.explicit_impls.contains(ty))
                 {
                     out.next_section();
                     write_unique_ptr(out, inner, types);
@@ -1077,8 +1123,9 @@
             }
         } else if let Type::CxxVector(ptr) = ty {
             if let Type::Ident(inner) = &ptr.inner {
-                if Atom::from(inner).is_none()
-                    && (!types.aliases.contains_key(inner) || types.explicit_impls.contains(ty))
+                if Atom::from(&inner.rust).is_none()
+                    && (!types.aliases.contains_key(&inner.rust)
+                        || types.explicit_impls.contains(ty))
                 {
                     out.next_section();
                     write_cxx_vector(out, ty, inner, types);
@@ -1093,12 +1140,12 @@
     for ty in types {
         if let Type::RustBox(ty) = ty {
             if let Type::Ident(inner) = &ty.inner {
-                write_rust_box_impl(out, inner);
+                write_rust_box_impl(out, &types.resolve(&inner));
             }
         } else if let Type::RustVec(ty) = ty {
             if let Type::Ident(inner) = &ty.inner {
-                if Atom::from(inner).is_none() {
-                    write_rust_vec_impl(out, inner);
+                if Atom::from(&inner.rust).is_none() {
+                    write_rust_vec_impl(out, inner, types);
                 }
             }
         }
@@ -1107,14 +1154,9 @@
     out.end_block("namespace rust");
 }
 
-fn write_rust_box_extern(out: &mut OutFile, ident: &Ident) {
-    let mut inner = String::new();
-    for name in &out.namespace {
-        inner += &name.to_string();
-        inner += "::";
-    }
-    inner += &ident.to_string();
-    let instance = inner.replace("::", "$");
+fn write_rust_box_extern(out: &mut OutFile, ident: &CppName) {
+    let inner = ident.to_fully_qualified();
+    let instance = ident.to_symbol();
 
     writeln!(out, "#ifndef CXXBRIDGE05_RUST_BOX_{}", instance);
     writeln!(out, "#define CXXBRIDGE05_RUST_BOX_{}", instance);
@@ -1131,10 +1173,10 @@
     writeln!(out, "#endif // CXXBRIDGE05_RUST_BOX_{}", instance);
 }
 
-fn write_rust_vec_extern(out: &mut OutFile, element: &Ident) {
+fn write_rust_vec_extern(out: &mut OutFile, element: &ResolvableName, types: &Types) {
     let element = Type::Ident(element.clone());
-    let inner = to_typename(&out.namespace, &element);
-    let instance = to_mangled(&out.namespace, &element);
+    let inner = to_typename(&element, types);
+    let instance = to_mangled(&element, types);
 
     writeln!(out, "#ifndef CXXBRIDGE05_RUST_VEC_{}", instance);
     writeln!(out, "#define CXXBRIDGE05_RUST_VEC_{}", instance);
@@ -1166,14 +1208,9 @@
     writeln!(out, "#endif // CXXBRIDGE05_RUST_VEC_{}", instance);
 }
 
-fn write_rust_box_impl(out: &mut OutFile, ident: &Ident) {
-    let mut inner = String::new();
-    for name in &out.namespace {
-        inner += &name.to_string();
-        inner += "::";
-    }
-    inner += &ident.to_string();
-    let instance = inner.replace("::", "$");
+fn write_rust_box_impl(out: &mut OutFile, ident: &CppName) {
+    let inner = ident.to_fully_qualified();
+    let instance = ident.to_symbol();
 
     writeln!(out, "template <>");
     writeln!(out, "void Box<{}>::uninit() noexcept {{", inner);
@@ -1186,10 +1223,10 @@
     writeln!(out, "}}");
 }
 
-fn write_rust_vec_impl(out: &mut OutFile, element: &Ident) {
+fn write_rust_vec_impl(out: &mut OutFile, element: &ResolvableName, types: &Types) {
     let element = Type::Ident(element.clone());
-    let inner = to_typename(&out.namespace, &element);
-    let instance = to_mangled(&out.namespace, &element);
+    let inner = to_typename(&element, types);
+    let instance = to_mangled(&element, types);
 
     writeln!(out, "template <>");
     writeln!(out, "Vec<{}>::Vec() noexcept {{", inner);
@@ -1225,9 +1262,9 @@
     writeln!(out, "}}");
 }
 
-fn write_unique_ptr(out: &mut OutFile, ident: &Ident, types: &Types) {
+fn write_unique_ptr(out: &mut OutFile, ident: &ResolvableName, types: &Types) {
     let ty = Type::Ident(ident.clone());
-    let instance = to_mangled(&out.namespace, &ty);
+    let instance = to_mangled(&ty, types);
 
     writeln!(out, "#ifndef CXXBRIDGE05_UNIQUE_PTR_{}", instance);
     writeln!(out, "#define CXXBRIDGE05_UNIQUE_PTR_{}", instance);
@@ -1241,8 +1278,8 @@
 fn write_unique_ptr_common(out: &mut OutFile, ty: &Type, types: &Types) {
     out.include.new = true;
     out.include.utility = true;
-    let inner = to_typename(&out.namespace, ty);
-    let instance = to_mangled(&out.namespace, ty);
+    let inner = to_typename(ty, types);
+    let instance = to_mangled(ty, types);
 
     let can_construct_from_value = match ty {
         // Some aliases are to opaque types; some are to trivial types. We can't
@@ -1250,7 +1287,7 @@
         // bindings for a "new" method anyway. But the Rust code can't be called
         // for Opaque types because the 'new' method is not implemented.
         Type::Ident(ident) => {
-            types.structs.contains_key(ident) || types.aliases.contains_key(ident)
+            types.structs.contains_key(&ident.rust) || types.aliases.contains_key(&ident.rust)
         }
         _ => false,
     };
@@ -1315,10 +1352,10 @@
     writeln!(out, "}}");
 }
 
-fn write_cxx_vector(out: &mut OutFile, vector_ty: &Type, element: &Ident, types: &Types) {
+fn write_cxx_vector(out: &mut OutFile, vector_ty: &Type, element: &ResolvableName, types: &Types) {
     let element = Type::Ident(element.clone());
-    let inner = to_typename(&out.namespace, &element);
-    let instance = to_mangled(&out.namespace, &element);
+    let inner = to_typename(&element, types);
+    let instance = to_mangled(&element, types);
 
     writeln!(out, "#ifndef CXXBRIDGE05_VECTOR_{}", instance);
     writeln!(out, "#define CXXBRIDGE05_VECTOR_{}", instance);