let modname = if module != "" {
module.clone() + "::" + &modident
} else {
+ self.dependencies.insert(m.ident);
modident.clone()
};
self.load_module(modname, m.attrs, m.content.unwrap().1);
"crate::c_types"
}
+ /// This should just be a closure, but doing so gets an error like
+ /// error: reached the recursion limit while instantiating `types::TypeResolver::is_transpar...c/types.rs:1358:104: 1358:110]>>`
+ /// which implies the concrete function instantiation of `is_transparent_container` ends up
+ /// being recursive.
+ fn deref_type<'one, 'b: 'one> (obj: &'one &'b syn::Type) -> &'b syn::Type { *obj }
+
/// Returns true if the path containing the given args is a "transparent" container, ie an
/// Option or a container which does not require a generated continer class.
fn is_transparent_container<'i, I: Iterator<Item=&'i syn::Type>>(&self, full_path: &str, _is_ref: bool, mut args: I, generics: Option<&GenericTypes>) -> bool {
if full_path == "Option" {
let inner = args.next().unwrap();
assert!(args.next().is_none());
- match inner {
- syn::Type::Reference(_) => true,
+ match generics.resolve_type(inner) {
+ syn::Type::Reference(r) => {
+ let elem = &*r.elem;
+ match elem {
+ syn::Type::Path(_) =>
+ self.is_transparent_container(full_path, true, [elem].iter().map(Self::deref_type), generics),
+ _ => true,
+ }
+ },
syn::Type::Array(a) => {
if let syn::Expr::Lit(l) = &a.len {
if let syn::Lit::Int(i) = &l.lit {
if self.c_type_has_inner_from_path(&resolved) { return true; }
if self.is_primitive(&resolved) { return false; }
if self.c_type_from_path(&resolved, false, false).is_some() { true } else { false }
- } else { true }
+ } else { unimplemented!(); }
},
syn::Type::Tuple(_) => false,
_ => unimplemented!(),
// For slices (and Options), we refuse to directly map them as is_ref when they
// aren't opaque types containing an inner pointer. This is due to the fact that,
// in both cases, the actual higher-level type is non-is_ref.
- let ty_has_inner = if $args_len == 1 {
+ let (ty_has_inner, ty_is_trait) = if $args_len == 1 {
let ty = $args_iter().next().unwrap();
if $container_type == "Slice" && to_c {
// "To C ptr_for_ref" means "return the regular object with is_owned
}
if let syn::Type::Reference(t) = ty {
if let syn::Type::Path(p) = &*t.elem {
- self.c_type_has_inner_from_path(&self.resolve_path(&p.path, generics))
- } else { false }
+ let resolved = self.resolve_path(&p.path, generics);
+ (self.c_type_has_inner_from_path(&resolved), self.crate_types.traits.get(&resolved).is_some())
+ } else { (false, false) }
} else if let syn::Type::Path(p) = ty {
- self.c_type_has_inner_from_path(&self.resolve_path(&p.path, generics))
- } else { false }
- } else { true };
+ let resolved = self.resolve_path(&p.path, generics);
+ (self.c_type_has_inner_from_path(&resolved), self.crate_types.traits.get(&resolved).is_some())
+ } else { (false, false) }
+ } else { (true, false) };
// Options get a bunch of special handling, since in general we map Option<>al
// types into the same C type as non-Option-wrapped types. This ends up being
// If the inner element contains an inner pointer, we will just use that,
// avoiding the need to map elements to references. Otherwise we'll need to
// do an extra mapping step.
- needs_ref_map = !only_contained_has_inner && $container_type == "Option";
+ needs_ref_map = !only_contained_has_inner && !ty_is_trait && $container_type == "Option";
} else {
only_contained_type = Some(arg);
only_contained_type_nonref = Some(arg);
// ******************************************************
fn write_template_generics<'b, W: std::io::Write>(&self, w: &mut W, args: &mut dyn Iterator<Item=&'b syn::Type>, generics: Option<&GenericTypes>, is_ref: bool) -> bool {
- for (idx, t) in args.enumerate() {
+ for (idx, orig_t) in args.enumerate() {
if idx != 0 {
write!(w, ", ").unwrap();
}
+ let t = generics.resolve_type(orig_t);
if let syn::Type::Reference(r_arg) = t {
assert!(!is_ref); // We don't currently support outer reference types for non-primitive inners
if let syn::Type::Path(p_arg) = &*r_arg.elem {
let resolved = self.resolve_path(&p_arg.path, generics);
assert!(self.crate_types.opaques.get(&resolved).is_some() ||
+ self.crate_types.traits.get(&resolved).is_some() ||
self.c_type_from_path(&resolved, true, true).is_some(), "Template generics should be opaque or have a predefined mapping");
} else { unimplemented!(); }
} else if let syn::Type::Path(p_arg) = t {