X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Ftypes.rs;h=bc015f04bd8ecf4ec4add92e3e4c76528b2940be;hb=170f4b624053ee1a95dbbc8efe96ec8ffb1fcb4e;hp=5187477d7b6824cb353fc0ca8235349c889631e8;hpb=257e3956c377b9610bc01925ceecca450d8735cc;p=ldk-c-bindings diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index 5187477..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!(), @@ -1652,7 +1665,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } } - fn write_rust_path(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, path: &syn::Path, with_ref_lifetime: bool) { + fn write_rust_path(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, path: &syn::Path, with_ref_lifetime: bool, generated_crate_ref: bool) { if let Some(resolved) = self.maybe_resolve_path(&path, generics_resolver) { if self.is_primitive(&resolved) { write!(w, "{}", path.get_ident().unwrap()).unwrap(); @@ -1661,9 +1674,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // checking for "bitcoin" explicitly. if resolved.starts_with("bitcoin::") || Self::in_rust_prelude(&resolved) { write!(w, "{}", resolved).unwrap(); - // If we're printing a generic argument, it needs to reference the crate, otherwise - // the original crate: - } else if self.maybe_resolve_path(&path, None).as_ref() == Some(&resolved) { + } else if !generated_crate_ref { + // If we're printing a generic argument, it needs to reference the crate, otherwise + // the original crate. write!(w, "{}", self.real_rust_type_mapping(&resolved)).unwrap(); } else { write!(w, "crate::{}", resolved).unwrap(); @@ -1700,7 +1713,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { match bound { syn::TypeParamBound::Trait(tb) => { if tb.paren_token.is_some() || tb.lifetimes.is_some() { unimplemented!(); } - self.write_rust_path(w, generics_resolver, &tb.path, false); + self.write_rust_path(w, generics_resolver, &tb.path, false, false); }, _ => unimplemented!(), } @@ -1724,13 +1737,19 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } write!(w, ">").unwrap(); } - pub fn write_rust_type(&self, w: &mut W, generics: Option<&GenericTypes>, t: &syn::Type, with_ref_lifetime: bool) { - match generics.resolve_type(t) { + fn do_write_rust_type(&self, w: &mut W, generics: Option<&GenericTypes>, t: &syn::Type, with_ref_lifetime: bool, force_crate_ref: bool) { + let real_ty = generics.resolve_type(t); + let mut generate_crate_ref = force_crate_ref || t != real_ty; + match real_ty { syn::Type::Path(p) => { if p.qself.is_some() { unimplemented!(); } - self.write_rust_path(w, generics, &p.path, with_ref_lifetime); + if let Some(resolved_ty) = self.maybe_resolve_path(&p.path, generics) { + generate_crate_ref |= self.maybe_resolve_path(&p.path, None).as_ref() != Some(&resolved_ty); + if self.crate_types.traits.get(&resolved_ty).is_none() { generate_crate_ref = false; } + } + self.write_rust_path(w, generics, &p.path, with_ref_lifetime, generate_crate_ref); }, syn::Type::Reference(r) => { write!(w, "&").unwrap(); @@ -1742,11 +1761,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { if r.mutability.is_some() { write!(w, "mut ").unwrap(); } - self.write_rust_type(w, generics, &*r.elem, with_ref_lifetime); + self.do_write_rust_type(w, generics, &*r.elem, with_ref_lifetime, generate_crate_ref); }, syn::Type::Array(a) => { write!(w, "[").unwrap(); - self.write_rust_type(w, generics, &a.elem, with_ref_lifetime); + self.do_write_rust_type(w, generics, &a.elem, with_ref_lifetime, generate_crate_ref); if let syn::Expr::Lit(l) = &a.len { if let syn::Lit::Int(i) = &l.lit { write!(w, "; {}]", i).unwrap(); @@ -1755,20 +1774,24 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } syn::Type::Slice(s) => { write!(w, "[").unwrap(); - self.write_rust_type(w, generics, &s.elem, with_ref_lifetime); + self.do_write_rust_type(w, generics, &s.elem, with_ref_lifetime, generate_crate_ref); write!(w, "]").unwrap(); }, syn::Type::Tuple(s) => { write!(w, "(").unwrap(); for (idx, t) in s.elems.iter().enumerate() { if idx != 0 { write!(w, ", ").unwrap(); } - self.write_rust_type(w, generics, &t, with_ref_lifetime); + self.do_write_rust_type(w, generics, &t, with_ref_lifetime, generate_crate_ref); } write!(w, ")").unwrap(); }, _ => unimplemented!(), } } + pub fn write_rust_type(&self, w: &mut W, generics: Option<&GenericTypes>, t: &syn::Type, with_ref_lifetime: bool) { + self.do_write_rust_type(w, generics, t, with_ref_lifetime, false); + } + /// Prints a constructor for something which is "uninitialized" (but obviously not actually /// unint'd memory). @@ -2178,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 @@ -2188,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 @@ -2217,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); @@ -2465,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 @@ -2480,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 { @@ -2761,7 +2788,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // lifetime, of which the only real available choice is `static`, obviously. write!(w, "&'static {}", crate_pfx).unwrap(); if !c_ty { - self.write_rust_path(w, generics, path, with_ref_lifetime); + self.write_rust_path(w, generics, path, with_ref_lifetime, false); } else { // We shouldn't be mapping references in types, so panic here unimplemented!();