syn::ReturnType::Type(_, rtype) => {
write!(w, ";\n\t{}", extra_indent).unwrap();
+ let self_segs_iter = first_seg_self(&*rtype);
if to_c && first_seg_self(&*rtype).is_some() {
// Assume rather blindly that we're returning an associated trait from a C fn call to a Rust trait object.
write!(w, "ret").unwrap();
- } else if !to_c && first_seg_self(&*rtype).is_some() {
- if let Some(mut remaining_path) = first_seg_self(&*rtype) {
- if let Some(associated_seg) = get_single_remaining_path_seg(&mut remaining_path) {
- // Build a fake path with only associated_seg and resolve it:
- let mut segments = syn::punctuated::Punctuated::new();
- segments.push(syn::PathSegment {
- ident: associated_seg.clone(), arguments: syn::PathArguments::None });
- let (_, real_path) = generics.unwrap().maybe_resolve_path(&syn::Path {
- leading_colon: None, segments }).unwrap();
-
- assert_eq!(real_path.segments.len(), 1);
- let real_ident = &real_path.segments.iter().next().unwrap().ident;
- if let Some(t) = types.crate_types.traits.get(&types.maybe_resolve_ident(&real_ident).unwrap()) {
- // We're returning an associated trait from a Rust fn call to a C trait
- // object.
- writeln!(w, "let mut rust_obj = {} {{ inner: Box::into_raw(Box::new(ret)), is_owned: true }};", this_type).unwrap();
- writeln!(w, "\t{}let mut ret = {}_as_{}(&rust_obj);", extra_indent, this_type, t.ident).unwrap();
- writeln!(w, "\t{}// We want to free rust_obj when ret gets drop()'d, not rust_obj, so wipe rust_obj's pointer and set ret's free() fn", extra_indent).unwrap();
- writeln!(w, "\t{}rust_obj.inner = std::ptr::null_mut();", extra_indent).unwrap();
- writeln!(w, "\t{}ret.free = Some({}_free_void);", extra_indent, this_type).unwrap();
- writeln!(w, "\t{}ret", extra_indent).unwrap();
- return;
- }
- }
- }
+ } else if !to_c && self_segs_iter.is_some() && self_segs_iter.unwrap().next().is_none() {
+ // If we're returning "Self" (and not "Self::X"), just do it manually
write!(w, "{} {{ inner: Box::into_raw(Box::new(ret)), is_owned: true }}", this_type).unwrap();
} else if to_c {
let new_var = types.write_from_c_conversion_new_var(w, &syn::Ident::new("ret", Span::call_site()), rtype, generics);
ExportStatus::Export => {},
ExportStatus::NoExport|ExportStatus::TestOnly => return,
}
+
+ // For cases where we have a concrete native object which implements a
+ // trait and need to return the C-mapped version of the trait, provide a
+ // From<> implementation which does all the work to ensure free is handled
+ // properly. This way we can call this method from deep in the
+ // type-conversion logic without actually knowing the concrete native type.
+ writeln!(w, "impl From<native{}> for crate::{} {{", ident, full_trait_path).unwrap();
+ writeln!(w, "\tfn from(obj: native{}) -> Self {{", ident).unwrap();
+ writeln!(w, "\t\tlet mut rust_obj = {} {{ inner: Box::into_raw(Box::new(obj)), is_owned: true }};", ident).unwrap();
+ writeln!(w, "\t\tlet mut ret = {}_as_{}(&rust_obj);", ident, trait_obj.ident).unwrap();
+ writeln!(w, "\t\t// We want to free rust_obj when ret gets drop()'d, not rust_obj, so wipe rust_obj's pointer and set ret's free() fn").unwrap();
+ writeln!(w, "\t\trust_obj.inner = std::ptr::null_mut();").unwrap();
+ writeln!(w, "\t\tret.free = Some({}_free_void);", ident).unwrap();
+ writeln!(w, "\t\tret\n\t}}\n}}").unwrap();
+
write!(w, "#[no_mangle]\npub extern \"C\" fn {}_as_{}(this_arg: *const {}) -> crate::{} {{\n", ident, trait_obj.ident, ident, full_trait_path).unwrap();
writeln!(w, "\tcrate::{} {{", full_trait_path).unwrap();
writeln!(w, "\t\tthis_arg: unsafe {{ (*this_arg).inner as *mut c_void }},").unwrap();
decl_lookup(w, &DeclType::StructImported, &resolved_path, is_ref, is_mut);
} else if self.crate_types.mirrored_enums.get(&resolved_path).is_some() {
decl_lookup(w, &DeclType::MirroredEnum, &resolved_path, is_ref, is_mut);
+ } else if let Some(t) = self.crate_types.traits.get(&resolved_path) {
+ decl_lookup(w, &DeclType::Trait(t), &resolved_path, is_ref, is_mut);
} else if let Some(ident) = single_ident_generic_path_to_ident(&p.path) {
- if let Some(t) = self.crate_types.traits.get(&resolved_path) {
- decl_lookup(w, &DeclType::Trait(t), &resolved_path, is_ref, is_mut);
- return;
- } else if let Some(_) = self.imports.get(ident) {
+ if let Some(_) = self.imports.get(ident) {
// crate_types lookup has to have succeeded:
panic!("Failed to print inline conversion for {}", ident);
} else if let Some(decl_type) = self.declared.get(ident) {
decl_lookup(w, decl_type, &self.maybe_resolve_ident(ident).unwrap(), is_ref, is_mut);
} else { unimplemented!(); }
- }
+ } else { unimplemented!(); }
},
syn::Type::Array(a) => {
// We assume all arrays contain only [int_literal; X]s.
DeclType::EnumIgnored|DeclType::StructImported if !is_ref =>
write!(w, "crate::{} {{ inner: Box::into_raw(Box::new(", decl_path).unwrap(),
DeclType::Trait(_) if is_ref => write!(w, "&").unwrap(),
+ DeclType::Trait(_) if !is_ref => {},
_ => panic!("{:?}", decl_path),
}
});
write!(w, ", is_owned: true }}").unwrap(),
DeclType::EnumIgnored|DeclType::StructImported if !is_ref => write!(w, ")), is_owned: true }}").unwrap(),
DeclType::Trait(_) if is_ref => {},
+ DeclType::Trait(_) => {
+ // This is used when we're converting a concrete Rust type into a C trait
+ // for use when a Rust trait method returns an associated type.
+ // Because all of our C traits implement From<RustTypesImplementingTraits>
+ // we can just call .into() here and be done.
+ write!(w, ".into()").unwrap()
+ },
_ => unimplemented!(),
});
}