Merge pull request #403 from dtolnay/setnamespace

Implement set_namespace helper for OutFile
diff --git a/gen/src/alphasort.rs b/gen/src/alphasort.rs
index 95b49a6..5c21bc4 100644
--- a/gen/src/alphasort.rs
+++ b/gen/src/alphasort.rs
@@ -1,9 +1,11 @@
+use crate::syntax::namespace::Namespace;
 use crate::syntax::Api;
 use proc_macro2::Ident;
 use std::collections::BTreeMap;
 use std::iter::FromIterator;
 
 pub struct NamespaceEntries<'a> {
+    pub namespace: Namespace,
     direct: Vec<&'a Api>,
     nested: BTreeMap<&'a Ident, NamespaceEntries<'a>>,
 }
@@ -45,7 +47,17 @@
         .map(|(k, apis)| (k, sort_by_inner_namespace(apis, depth + 1)))
         .collect();
 
-    NamespaceEntries { direct, nested }
+    let namespace = apis
+        .first()
+        .copied()
+        .and_then(Api::namespace)
+        .map_or(Namespace::ROOT, |ns| ns.iter().take(depth).collect());
+
+    NamespaceEntries {
+        namespace,
+        direct,
+        nested,
+    }
 }
 
 #[cfg(test)]
diff --git a/gen/src/out.rs b/gen/src/out.rs
index 2733c32..bf880cc 100644
--- a/gen/src/out.rs
+++ b/gen/src/out.rs
@@ -2,6 +2,7 @@
 use crate::gen::builtin::Builtins;
 use crate::gen::include::Includes;
 use crate::gen::Opt;
+use crate::syntax::namespace::Namespace;
 use crate::syntax::Types;
 use std::cell::RefCell;
 use std::fmt::{self, Arguments, Write};
@@ -18,6 +19,7 @@
 #[derive(Default)]
 pub struct Content<'a> {
     bytes: String,
+    namespace: &'a Namespace,
     blocks: Vec<BlockBoundary<'a>>,
     section_pending: bool,
     blocks_pending: usize,
@@ -54,6 +56,10 @@
         self.content.get_mut().end_block(block);
     }
 
+    pub fn set_namespace(&mut self, namespace: &'a Namespace) {
+        self.content.get_mut().set_namespace(namespace);
+    }
+
     pub fn write_fmt(&self, args: Arguments) {
         let content = &mut *self.content.borrow_mut();
         Write::write_fmt(content, args).unwrap();
@@ -118,6 +124,16 @@
         self.push_block_boundary(BlockBoundary::End(block));
     }
 
+    pub fn set_namespace(&mut self, namespace: &'a Namespace) {
+        for name in self.namespace.iter().rev() {
+            self.end_block(Block::UserDefinedNamespace(name));
+        }
+        for name in namespace {
+            self.begin_block(Block::UserDefinedNamespace(name));
+        }
+        self.namespace = namespace;
+    }
+
     pub fn write_fmt(&mut self, args: Arguments) {
         Write::write_fmt(self, args).unwrap();
     }
@@ -147,6 +163,7 @@
     }
 
     fn flush(&mut self) {
+        self.set_namespace(Default::default());
         if self.blocks_pending > 0 {
             self.flush_blocks();
         }
diff --git a/gen/src/write.rs b/gen/src/write.rs
index 0b6a5aa..352d643 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -57,7 +57,8 @@
     }
 }
 
-fn gen_namespace_contents<'a>(out: &mut OutFile<'a>, ns_entries: &NamespaceEntries<'a>) {
+fn gen_namespace_contents<'a>(out: &mut OutFile<'a>, ns_entries: &'a NamespaceEntries<'a>) {
+    out.set_namespace(&ns_entries.namespace);
     let apis = ns_entries.direct_content();
 
     let mut methods_for_type = HashMap::new();
@@ -127,11 +128,8 @@
         }
     }
 
-    for (namespace, nested_ns_entries) in ns_entries.nested_content() {
-        let block = Block::UserDefinedNamespace(namespace);
-        out.begin_block(block);
+    for (_, nested_ns_entries) in ns_entries.nested_content() {
         gen_namespace_contents(out, nested_ns_entries);
-        out.end_block(block);
     }
 }
 
@@ -974,6 +972,7 @@
 }
 
 fn write_generic_instantiations(out: &mut OutFile) {
+    out.set_namespace(Default::default());
     out.begin_block(Block::ExternC);
     for ty in out.types {
         if let Type::RustBox(ty) = ty {
diff --git a/syntax/namespace.rs b/syntax/namespace.rs
index 834a1d5..7628b0a 100644
--- a/syntax/namespace.rs
+++ b/syntax/namespace.rs
@@ -2,6 +2,7 @@
 use crate::syntax::Api;
 use quote::IdentFragment;
 use std::fmt::{self, Display};
+use std::iter::FromIterator;
 use std::slice::Iter;
 use syn::parse::{Parse, ParseStream, Result};
 use syn::{Ident, Token};
@@ -10,7 +11,7 @@
     syn::custom_keyword!(namespace);
 }
 
-#[derive(Clone)]
+#[derive(Clone, Default)]
 pub struct Namespace {
     segments: Vec<Ident>,
 }
@@ -37,6 +38,13 @@
     }
 }
 
+impl Default for &Namespace {
+    fn default() -> Self {
+        const ROOT: &Namespace = &Namespace::ROOT;
+        ROOT
+    }
+}
+
 impl Parse for Namespace {
     fn parse(input: ParseStream) -> Result<Self> {
         let segments = QualifiedName::parse_quoted_or_unquoted(input)?.segments;
@@ -67,6 +75,16 @@
     }
 }
 
+impl<'a> FromIterator<&'a Ident> for Namespace {
+    fn from_iter<I>(idents: I) -> Self
+    where
+        I: IntoIterator<Item = &'a Ident>,
+    {
+        let segments = idents.into_iter().cloned().collect();
+        Namespace { segments }
+    }
+}
+
 impl Api {
     pub fn namespace(&self) -> Option<&Namespace> {
         match self {