"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!(),
}
}
- fn write_rust_path<W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, path: &syn::Path, with_ref_lifetime: bool) {
+ fn write_rust_path<W: std::io::Write>(&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();
// 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();
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!(),
}
}
write!(w, ">").unwrap();
}
- pub fn write_rust_type<W: std::io::Write>(&self, w: &mut W, generics: Option<&GenericTypes>, t: &syn::Type, with_ref_lifetime: bool) {
- match generics.resolve_type(t) {
+ fn do_write_rust_type<W: std::io::Write>(&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();
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();
}
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<W: std::io::Write>(&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).
// 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!();