Implement fallible Rust functions
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index fcfa1d9..defa565 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -136,7 +136,7 @@
});
let ret = expand_extern_return_type(&efn.ret, types);
let mut outparam = None;
- if indirect_return(&efn.ret, types) {
+ if indirect_return(efn, types) {
let ret = expand_extern_type(efn.ret.as_ref().unwrap());
outparam = Some(quote!(__return: *mut #ret));
}
@@ -154,7 +154,7 @@
let decl = expand_cxx_function_decl(namespace, efn, types);
let args = &efn.args;
let ret = expand_return_type(&efn.ret);
- let indirect_return = indirect_return(&efn.ret, types);
+ let indirect_return = indirect_return(efn, types);
let vars = efn.args.iter().map(|arg| {
let var = &arg.ident;
match &arg.ty {
@@ -267,9 +267,7 @@
}
});
let mut outparam = None;
- let call = quote! {
- ::cxx::private::catch_unwind(__fn, move || super::#ident(#(#vars),*))
- };
+ let call = quote!(super::#ident(#(#vars),*));
let mut expr = efn
.ret
.as_ref()
@@ -289,12 +287,22 @@
_ => None,
})
.unwrap_or(call);
- if indirect_return(&efn.ret, types) {
+ let indirect_return = indirect_return(efn, types);
+ if indirect_return {
let ret = expand_extern_type(efn.ret.as_ref().unwrap());
outparam = Some(quote!(__return: *mut #ret));
+ }
+ if efn.throws {
+ expr = quote!(::cxx::private::r#try(__return, #expr));
+ } else if indirect_return {
expr = quote!(::std::ptr::write(__return, #expr));
}
- let ret = expand_extern_return_type(&efn.ret, types);
+ expr = quote!(::cxx::private::catch_unwind(__fn, move || #expr));
+ let ret = if efn.throws {
+ quote!(-> ::std::option::Option<::cxx::private::RustStr>)
+ } else {
+ expand_extern_return_type(&efn.ret, types)
+ };
let link_name = format!("{}cxxbridge02${}", namespace, ident);
let local_name = format_ident!("__{}", ident);
let catch_unwind_label = format!("::{}", ident);
@@ -407,9 +415,10 @@
}
}
-fn indirect_return(ret: &Option<Type>, types: &Types) -> bool {
- ret.as_ref()
- .map_or(false, |ret| types.needs_indirect_abi(ret))
+fn indirect_return(efn: &ExternFn, types: &Types) -> bool {
+ efn.ret
+ .as_ref()
+ .map_or(false, |ret| efn.throws || types.needs_indirect_abi(ret))
}
fn expand_extern_type(ty: &Type) -> TokenStream {