Support calling Rust methods from C++

These methods can be declared in the bridge by naming the first
argument self and making it a reference to the containing class, e.g.,
  fn get(self: &R) -> usize;
  fn set(self: &mut R, n: usize);
This syntax requires Rust 1.43.
diff --git a/demo-cxx/demo.cc b/demo-cxx/demo.cc
index 6fc2465..bc0d976 100644
--- a/demo-cxx/demo.cc
+++ b/demo-cxx/demo.cc
@@ -18,7 +18,10 @@
   return std::unique_ptr<ThingC>(new ThingC(std::string(appname)));
 }
 
-void do_thing(SharedThing state) { print_r(*state.y); }
+void do_thing(SharedThing state) {
+  print_r(*state.y);
+  state.y->print();
+}
 
 } // namespace example
 } // namespace org
diff --git a/demo-rs/src/main.rs b/demo-rs/src/main.rs
index 759bbe1..713a1d1 100644
--- a/demo-rs/src/main.rs
+++ b/demo-rs/src/main.rs
@@ -19,6 +19,7 @@
     extern "Rust" {
         type ThingR;
         fn print_r(r: &ThingR);
+        fn print(self: &ThingR);
     }
 }
 
@@ -28,6 +29,12 @@
     println!("called back with r={}", r.0);
 }
 
+impl ThingR {
+    fn print(&self) {
+        println!("method called back with r={}", self.0);
+    }
+}
+
 fn main() {
     let x = ffi::make_demo("demo of cxx::bridge");
     println!("this is a {}", x.as_ref().unwrap().get_name());
diff --git a/gen/write.rs b/gen/write.rs
index 41b5b37..7e1caac 100644
--- a/gen/write.rs
+++ b/gen/write.rs
@@ -2,7 +2,7 @@
 use crate::gen::out::OutFile;
 use crate::gen::{include, Opt};
 use crate::syntax::atom::Atom::{self, *};
-use crate::syntax::{Api, ExternFn, Receiver, Signature, Struct, Type, Types, Var};
+use crate::syntax::{Api, ExternFn, ExternType, Receiver, Signature, Struct, Type, Types, Var};
 use proc_macro2::Ident;
 
 pub(super) fn gen(
@@ -45,9 +45,25 @@
     }
 
     for api in apis {
-        if let Api::Struct(strct) = api {
-            out.next_section();
-            write_struct(out, strct);
+        match api {
+            Api::Struct(strct) => {
+                out.next_section();
+                write_struct(out, strct);
+            }
+            Api::RustType(ety) => {
+                let methods = apis.iter().filter_map(|api| match api {
+                    Api::RustFunction(efn) => match &efn.sig.receiver {
+                        Some(rcvr) if rcvr.ident == ety.ident => Some(efn),
+                        _ => None,
+                    },
+                    _ => None,
+                }).collect::<Vec<_>>();
+                if !methods.is_empty() {
+                    out.next_section();
+                    write_struct_with_methods(out, ety, methods);
+                }
+            }
+            _ => {}
         }
     }
 
@@ -300,6 +316,21 @@
     writeln!(out, "using {} = {};", ident, ident);
 }
 
+fn write_struct_with_methods(out: &mut OutFile, ety: &ExternType, methods: Vec<&ExternFn>) {
+    for line in ety.doc.to_string().lines() {
+        writeln!(out, "//{}", line);
+    }
+    writeln!(out, "struct {} final {{", ety.ident);
+    for method in &methods {
+        write!(out, "  ");
+        let sig = &method.sig;
+        let local_name = method.ident.to_string();
+        write_rust_function_shim_decl(out, &local_name, sig, None, false);
+        writeln!(out, ";");
+    }
+    writeln!(out, "}};");
+}
+
 fn write_exception_glue(out: &mut OutFile, apis: &[Api]) {
     let mut has_cxx_throws = false;
     for api in apis {
@@ -326,7 +357,11 @@
     } else {
         write_extern_return_type_space(out, &efn.ret, types);
     }
-    write!(out, "{}cxxbridge02${}(", out.namespace, efn.ident);
+    let receiver_type = match &efn.receiver {
+        Some(base) => base.ident.to_string(),
+        None => "_".to_string(),
+    };
+    write!(out, "{}cxxbridge02${}${}(", out.namespace, receiver_type, efn.ident);
     if let Some(base) = &efn.receiver {
         write!(out, "{} *__receiver$", base.ident);
     }
@@ -471,7 +506,11 @@
 }
 
 fn write_rust_function_decl(out: &mut OutFile, efn: &ExternFn, types: &Types) {
-    let link_name = format!("{}cxxbridge02${}", out.namespace, efn.ident);
+    let receiver_type = match &efn.receiver {
+        Some(base) => base.ident.to_string(),
+        None => "_".to_string(),
+    };
+    let link_name = format!("{}cxxbridge02${}${}", out.namespace, receiver_type, efn.ident);
     let indirect_call = false;
     write_rust_function_decl_impl(out, &link_name, efn, types, indirect_call);
 }
@@ -490,6 +529,10 @@
     }
     write!(out, "{}(", link_name);
     let mut needs_comma = false;
+    if let Some(base) = &sig.receiver {
+        write!(out, "{} &__receiver$", base.ident);
+        needs_comma = true;
+    }
     for arg in &sig.args {
         if needs_comma {
             write!(out, ", ");
@@ -519,20 +562,26 @@
         writeln!(out, "//{}", line);
     }
     let local_name = efn.ident.to_string();
-    let invoke = format!("{}cxxbridge02${}", out.namespace, efn.ident);
+    let receiver_type = match &efn.receiver {
+        Some(base) => base.ident.to_string(),
+        None => "_".to_string(),
+    };
+    let invoke = format!("{}cxxbridge02${}${}", out.namespace, receiver_type, efn.ident);
     let indirect_call = false;
     write_rust_function_shim_impl(out, &local_name, efn, types, &invoke, indirect_call);
 }
 
-fn write_rust_function_shim_impl(
+fn write_rust_function_shim_decl(
     out: &mut OutFile,
     local_name: &str,
     sig: &Signature,
-    types: &Types,
-    invoke: &str,
+    receiver: Option<&Receiver>,
     indirect_call: bool,
 ) {
     write_return_type(out, &sig.ret);
+    if let Some(base) = receiver {
+        write!(out, "{}::", base.ident);
+    }
     write!(out, "{}(", local_name);
     for (i, arg) in sig.args.iter().enumerate() {
         if i > 0 {
@@ -551,6 +600,21 @@
     if !sig.throws {
         write!(out, " noexcept");
     }
+}
+
+fn write_rust_function_shim_impl(
+    out: &mut OutFile,
+    local_name: &str,
+    sig: &Signature,
+    types: &Types,
+    invoke: &str,
+    indirect_call: bool,
+) {
+    if out.header && sig.receiver.is_some() {
+        // We've already defined this inside the struct.
+        return;
+    }
+    write_rust_function_shim_decl(out, local_name, sig, sig.receiver.as_ref(), indirect_call);
     if out.header {
         writeln!(out, ";");
     } else {
@@ -589,8 +653,11 @@
             write!(out, "::rust::Str::Repr error$ = ");
         }
         write!(out, "{}(", invoke);
+        if let Some(_) = &sig.receiver {
+            write!(out, "*this");
+        }
         for (i, arg) in sig.args.iter().enumerate() {
-            if i > 0 {
+            if i > 0 || sig.receiver.is_some() {
                 write!(out, ", ");
             }
             match &arg.ty {
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 998b47e..2d3166a 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -154,7 +154,11 @@
         let ret = expand_extern_type(efn.ret.as_ref().unwrap());
         outparam = Some(quote!(__return: *mut #ret));
     }
-    let link_name = format!("{}cxxbridge02${}", namespace, ident);
+    let receiver_type = match &efn.receiver {
+        Some(base) => base.ident.to_string(),
+        None => "_".to_string(),
+    };
+    let link_name = format!("{}cxxbridge02${}${}", namespace, receiver_type, ident);
     let local_name = format_ident!("__{}", ident);
     quote! {
         #[link_name = #link_name]
@@ -366,7 +370,11 @@
 
 fn expand_rust_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types) -> TokenStream {
     let ident = &efn.ident;
-    let link_name = format!("{}cxxbridge02${}", namespace, ident);
+    let receiver_type = match &efn.receiver {
+        Some(base) => base.ident.to_string(),
+        None => "_".to_string(),
+    };
+    let link_name = format!("{}cxxbridge02${}${}", namespace, receiver_type, ident);
     let local_name = format_ident!("__{}", ident);
     let catch_unwind_label = format!("::{}", ident);
     let invoke = Some(ident);
@@ -388,6 +396,13 @@
     catch_unwind_label: String,
     invoke: Option<&Ident>,
 ) -> TokenStream {
+    let receiver = sig.receiver.iter().map(|base| {
+        let ident = &base.ident;
+        match base.mutability {
+            None => quote!(__receiver: &#ident),
+            Some(_) => quote!(__receiver: &mut #ident),
+        }
+    });
     let args = sig.args.iter().map(|arg| {
         let ident = &arg.ident;
         let ty = expand_extern_type(&arg.ty);
@@ -397,6 +412,7 @@
             quote!(#ident: #ty)
         }
     });
+    let all_args = receiver.chain(args);
 
     let vars = sig.args.iter().map(|arg| {
         let ident = &arg.ident;
@@ -418,7 +434,10 @@
     });
 
     let mut call = match invoke {
-        Some(ident) => quote!(super::#ident),
+        Some(ident) => match sig.receiver {
+            None => quote!(super::#ident),
+            Some(_) => quote!(__receiver.#ident),
+        },
         None => quote!(__extern),
     };
     call.extend(quote! { (#(#vars),*) });
@@ -476,7 +495,7 @@
     quote! {
         #[doc(hidden)]
         #[export_name = #link_name]
-        unsafe extern "C" fn #local_name(#(#args,)* #outparam #pointer) #ret {
+        unsafe extern "C" fn #local_name(#(#all_args,)* #outparam #pointer) #ret {
             let __fn = concat!(module_path!(), #catch_unwind_label);
             #expr
         }
diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs
index a720a80..4da5740 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -56,6 +56,7 @@
 
     extern "Rust" {
         type R;
+        type R2;
 
         fn r_return_primitive() -> usize;
         fn r_return_shared() -> Shared;
@@ -80,11 +81,28 @@
         fn r_try_return_void() -> Result<()>;
         fn r_try_return_primitive() -> Result<usize>;
         fn r_fail_return_primitive() -> Result<usize>;
+
+        fn r_return_r2(n: usize) -> Box<R2>;
+        fn get(self: &R2) -> usize;
+        fn set(self: &mut R2, n: usize) -> usize;
     }
 }
 
 pub type R = usize;
 
+pub struct R2(usize);
+
+impl R2 {
+    fn get(&self) -> usize {
+        self.0
+    }
+
+    fn set(&mut self, n: usize) -> usize {
+        self.0 = n;
+        n
+    }
+}
+
 #[derive(Debug)]
 struct Error;
 
@@ -187,3 +205,7 @@
 fn r_fail_return_primitive() -> Result<usize, Error> {
     Err(Error)
 }
+
+fn r_return_r2(n: usize) -> Box<R2> {
+    Box::new(R2(n))
+}
diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc
index 2daae53..8893ee8 100644
--- a/tests/ffi/tests.cc
+++ b/tests/ffi/tests.cc
@@ -181,6 +181,13 @@
     ASSERT(std::strcmp(e.what(), "rust error") == 0);
   }
 
+  auto r2 = r_return_r2(2020);
+  ASSERT(r2->get() == 2020);
+  ASSERT(r2->set(2021) == 2021);
+  ASSERT(r2->get() == 2021);
+  ASSERT(r2->set(2020) == 2020);
+  ASSERT(r2->get() == 2020);
+
   cxx_test_suite_set_correct();
   return nullptr;
 }