Implement struct toposort
diff --git a/gen/src/toposort.rs b/gen/src/toposort.rs
index 97b10f9..62a1148 100644
--- a/gen/src/toposort.rs
+++ b/gen/src/toposort.rs
@@ -1,8 +1,44 @@
-use crate::syntax::{Api, Types};
-use std::iter::FromIterator;
+use crate::syntax::{Api, Struct, Type, Types};
+use std::collections::btree_map::{BTreeMap as Map, Entry};
 
-pub fn sort<'a>(apis: &'a [Api], types: &Types) -> Vec<&'a Api> {
-    // TODO https://github.com/dtolnay/cxx/issues/292
-    let _ = types;
-    Vec::from_iter(apis)
+enum Mark {
+    Visiting,
+    Visited,
+}
+
+pub fn sort<'a>(apis: &'a [Api], types: &Types<'a>) -> Vec<&'a Struct> {
+    let mut sorted = Vec::new();
+    let ref mut marks = Map::new();
+    for api in apis {
+        if let Api::Struct(strct) = api {
+            visit(strct, &mut sorted, marks, types);
+        }
+    }
+    sorted
+}
+
+fn visit<'a>(
+    strct: &'a Struct,
+    sorted: &mut Vec<&'a Struct>,
+    marks: &mut Map<*const Struct, Mark>,
+    types: &Types<'a>,
+) {
+    match marks.entry(strct) {
+        Entry::Occupied(entry) => match entry.get() {
+            Mark::Visiting => panic!("not a DAG"), // FIXME
+            Mark::Visited => return,
+        },
+        Entry::Vacant(entry) => {
+            entry.insert(Mark::Visiting);
+        }
+    }
+    for field in &strct.fields {
+        if let Type::Ident(ident) = &field.ty {
+            if let Some(inner) = types.structs.get(&ident.rust) {
+                visit(inner, sorted, marks, types);
+            }
+        }
+    }
+    marks.insert(strct, Mark::Visited);
+    sorted.push(strct);
 }
diff --git a/gen/src/write.rs b/gen/src/write.rs
index c806e55..414ea46 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -76,14 +76,8 @@
         }
     }
 
-    for api in toposort::sort(apis, out.types) {
+    for api in apis {
         match api {
-            Api::Struct(strct) => {
-                out.next_section();
-                if !out.types.cxx.contains(&strct.name.rust) {
-                    write_struct(out, strct);
-                }
-            }
             Api::Enum(enm) => {
                 out.next_section();
                 if out.types.cxx.contains(&enm.name.rust) {
@@ -102,6 +96,13 @@
         }
     }
 
+    for strct in toposort::sort(apis, out.types) {
+        out.next_section();
+        if !out.types.cxx.contains(&strct.name.rust) {
+            write_struct(out, strct);
+        }
+    }
+
     out.next_section();
     for api in apis {
         if let Api::TypeAlias(ety) = api {