if supertrait.paren_token.is_some() || supertrait.lifetimes.is_some() {
unimplemented!();
}
- if let Some(ident) = supertrait.path.get_ident() {
- match (&format!("{}", ident) as &str, &ident) {
+ // First try to resolve path to find in-crate traits, but if that doesn't work
+ // assume its a prelude trait (eg Clone, etc) and just use the single ident.
+ if let Some(path) = $types.maybe_resolve_path(&supertrait.path, None) {
+ match (&path as &str, &supertrait.path.segments.iter().last().unwrap().ident) {
$( $pat => $e, )*
}
- } else {
- let path = $types.resolve_path(&supertrait.path, None);
- match (&path as &str, &supertrait.path.segments.iter().last().unwrap().ident) {
+ } else if let Some(ident) = supertrait.path.get_ident() {
+ match (&format!("{}", ident) as &str, &ident) {
$( $pat => $e, )*
}
+ } else {
+ panic!("Supertrait unresolvable and not single-ident");
}
},
syn::TypeParamBound::Lifetime(_) => unimplemented!(),
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();
writeln!(w, "\t\tclone: Some({}_clone_void),", ident).unwrap();
},
(s, t) => {
- if s.starts_with("util::") {
- let supertrait_obj = types.crate_types.traits.get(s).unwrap();
+ if let Some(supertrait_obj) = types.crate_types.traits.get(s) {
writeln!(w, "\t\t{}: crate::{} {{", t, s).unwrap();
writeln!(w, "\t\t\tthis_arg: unsafe {{ (*this_arg).inner as *mut c_void }},").unwrap();
writeln!(w, "\t\t\tfree: None,").unwrap();
}
walk_supertraits!(trait_obj, types, (
(s, t) => {
- if s.starts_with("util::") {
+ if let Some(supertrait_obj) = types.crate_types.traits.get(s).cloned() {
writeln!(w, "use {}::{} as native{}Trait;", types.orig_crate, s, t).unwrap();
- let supertrait_obj = *types.crate_types.traits.get(s).unwrap();
for item in supertrait_obj.items.iter() {
match item {
syn::TraitItem::Method(m) => {