X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Ftypes.rs;h=bc015f04bd8ecf4ec4add92e3e4c76528b2940be;hb=170f4b624053ee1a95dbbc8efe96ec8ffb1fcb4e;hp=8b9606dec3fb467a56ced3ef071313d402e5ee0e;hpb=995561a6e039d662ca2726ea455de158ffde154f;p=ldk-c-bindings diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index 8b9606d..bc015f0 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -1339,14 +1339,27 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "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>(&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 { @@ -1368,7 +1381,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { 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!(), @@ -2188,7 +2201,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // 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 @@ -2198,12 +2211,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } 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 @@ -2227,7 +2242,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // 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); @@ -2475,10 +2490,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // ****************************************************** fn write_template_generics<'b, W: std::io::Write>(&self, w: &mut W, args: &mut dyn Iterator, 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 @@ -2490,6 +2506,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { 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 {