self_ty: Option<String>,
parent: Option<&'b GenericTypes<'b, 'b>>,
typed_generics: HashMap<&'a syn::Ident, String>,
- default_generics: HashMap<&'a syn::Ident, (syn::Type, syn::Type)>,
+ default_generics: HashMap<&'a syn::Ident, (syn::Type, syn::Type, syn::Type)>,
}
impl<'a, 'p: 'a> GenericTypes<'a, 'p> {
pub fn new(self_ty: Option<String>) -> Self {
if non_lifetimes_processed { return false; }
non_lifetimes_processed = true;
if path != "std::ops::Deref" && path != "core::ops::Deref" {
+ let p = string_path_to_syn_path(&path);
+ let ref_ty = parse_quote!(&#p);
+ let mut_ref_ty = parse_quote!(&mut #p);
+ self.default_generics.insert(&type_param.ident, (syn::Type::Path(syn::TypePath { qself: None, path: p }), ref_ty, mut_ref_ty));
new_typed_generics.insert(&type_param.ident, Some(path));
- } else if trait_bound.path.segments.len() == 1 {
+ } else {
// If we're templated on Deref<Target = ConcreteThing>, store
// the reference type in `default_generics` which handles full
// types and not just paths.
if let syn::PathArguments::AngleBracketed(ref args) =
trait_bound.path.segments[0].arguments {
+ assert_eq!(trait_bound.path.segments.len(), 1);
for subargument in args.args.iter() {
match subargument {
syn::GenericArgument::Lifetime(_) => {},
syn::GenericArgument::Binding(ref b) => {
if &format!("{}", b.ident) != "Target" { return false; }
let default = &b.ty;
- self.default_generics.insert(&type_param.ident, (parse_quote!(&#default), parse_quote!(&#default)));
+ self.default_generics.insert(&type_param.ident, (parse_quote!(&#default), parse_quote!(&#default), parse_quote!(&mut #default)));
break 'bound_loop;
},
_ => unimplemented!(),
}
if let Some(default) = type_param.default.as_ref() {
assert!(type_param.bounds.is_empty());
- self.default_generics.insert(&type_param.ident, (default.clone(), parse_quote!(&#default)));
+ self.default_generics.insert(&type_param.ident, (default.clone(), parse_quote!(&#default), parse_quote!(&mut #default)));
}
},
_ => {},
qself: None, path: string_path_to_syn_path(&resolved)
});
let ref_ty = parse_quote!(&#ty);
+ let mut_ref_ty = parse_quote!(&mut #ty);
if types.crate_types.traits.get(&resolved).is_some() {
- self.default_generics.insert(p_ident, (ty, ref_ty));
+ self.default_generics.insert(p_ident, (ty, ref_ty, mut_ref_ty));
} else {
- self.default_generics.insert(p_ident, (ref_ty.clone(), ref_ty));
+ self.default_generics.insert(p_ident, (ref_ty.clone(), ref_ty, mut_ref_ty));
}
*gen = Some(resolved);
match ty {
syn::Type::Path(p) => {
if let Some(ident) = p.path.get_ident() {
- if let Some((ty, _)) = us.default_generics.get(ident) {
- return ty;
+ if let Some((ty, _, _)) = us.default_generics.get(ident) {
+ return self.resolve_type(ty);
}
}
},
- syn::Type::Reference(syn::TypeReference { elem, .. }) => {
+ syn::Type::Reference(syn::TypeReference { elem, mutability, .. }) => {
if let syn::Type::Path(p) = &**elem {
if let Some(ident) = p.path.get_ident() {
- if let Some((_, refty)) = us.default_generics.get(ident) {
- return refty;
+ if let Some((_, refty, mut_ref_ty)) = us.default_generics.get(ident) {
+ if mutability.is_some() {
+ return self.resolve_type(mut_ref_ty);
+ } else {
+ return self.resolve_type(refty);
+ }
}
}
}
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 i.base10_digits().parse::<usize>().unwrap() >= 32 {
let mut buf = Vec::new();
- self.write_rust_type(&mut buf, generics, &a.elem);
+ self.write_rust_type(&mut buf, generics, &a.elem, false);
let ty = String::from_utf8(buf).unwrap();
ty == "u8"
} else {
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!(),
}
if let Some(t) = single_contained {
if let syn::Type::Tuple(syn::TypeTuple { elems, .. }) = t {
- assert!(elems.is_empty());
let inner_name = self.get_c_mangled_container_type(vec![single_contained.unwrap()], generics, "Option").unwrap();
- return Some(("if ", vec![
- (format!(".is_none() {{ {}::None }} else {{ {}::Some /*",
- inner_name, inner_name), format!(""))
- ], " */}", ContainerPrefixLocation::PerConv));
+ if elems.is_empty() {
+ return Some(("if ", vec![
+ (format!(".is_none() {{ {}::None }} else {{ {}::Some /* ",
+ inner_name, inner_name), format!(""))
+ ], " */ }", ContainerPrefixLocation::PerConv));
+ } else {
+ return Some(("if ", vec![
+ (format!(".is_none() {{ {}::None }} else {{ {}::Some(",
+ inner_name, inner_name), format!("({}.unwrap())", var_access))
+ ], ") }", ContainerPrefixLocation::PerConv));
+ }
}
if let syn::Type::Reference(syn::TypeReference { elem, .. }) = t {
if let syn::Type::Slice(_) = &**elem {
}
}
- fn write_rust_path<W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, path: &syn::Path) {
+ 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();
}
}
if let syn::PathArguments::AngleBracketed(args) = &path.segments.iter().last().unwrap().arguments {
- self.write_rust_generic_arg(w, generics_resolver, args.args.iter());
+ self.write_rust_generic_arg(w, generics_resolver, args.args.iter(), with_ref_lifetime);
}
} else {
if path.leading_colon.is_some() {
if idx != 0 { write!(w, "::").unwrap(); }
write!(w, "{}", seg.ident).unwrap();
if let syn::PathArguments::AngleBracketed(args) = &seg.arguments {
- self.write_rust_generic_arg(w, generics_resolver, args.args.iter());
+ self.write_rust_generic_arg(w, generics_resolver, args.args.iter(), with_ref_lifetime);
}
}
}
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);
+ self.write_rust_path(w, generics_resolver, &tb.path, false, false);
},
_ => unimplemented!(),
}
if had_params { write!(w, ">").unwrap(); }
}
- pub fn write_rust_generic_arg<'b, W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, generics: impl Iterator<Item=&'b syn::GenericArgument>) {
+ pub fn write_rust_generic_arg<'b, W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, generics: impl Iterator<Item=&'b syn::GenericArgument>, with_ref_lifetime: bool) {
write!(w, "<").unwrap();
for (idx, arg) in generics.enumerate() {
if idx != 0 { write!(w, ", ").unwrap(); }
match arg {
- syn::GenericArgument::Type(t) => self.write_rust_type(w, generics_resolver, t),
+ syn::GenericArgument::Type(t) => self.write_rust_type(w, generics_resolver, t, with_ref_lifetime),
_ => unimplemented!(),
}
}
write!(w, ">").unwrap();
}
- pub fn write_rust_type<W: std::io::Write>(&self, w: &mut W, generics: Option<&GenericTypes>, t: &syn::Type) {
- 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);
+ 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 let Some(lft) = &r.lifetime {
write!(w, "'{} ", lft.ident).unwrap();
+ } else if with_ref_lifetime {
+ write!(w, "'static ").unwrap();
}
if r.mutability.is_some() {
write!(w, "mut ").unwrap();
}
- self.write_rust_type(w, generics, &*r.elem);
+ 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);
+ 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);
+ 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);
+ 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).
write!(w, "{}", sliceconv(false, None)).unwrap();
}
}
+ } else if let syn::Type::Array(_) = &*s.elem {
+ write!(w, "{}", sliceconv(false, Some(".map(|a| *a)"))).unwrap();
} else { unimplemented!(); }
},
syn::Type::Tuple(t) => {
// 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);
ptr_for_ref = true;
convert_container!("Slice", 1, || ty.iter());
unimplemented!("convert_container should return true as container_lookup should succeed for slices");
+ } else if let syn::Type::Array(_) = &*s.elem {
+ is_ref = false;
+ ptr_for_ref = true;
+ let arr_elem = [(*s.elem).clone()];
+ convert_container!("Slice", 1, || arr_elem.iter());
+ unimplemented!("convert_container should return true as container_lookup should succeed for slices");
} else { unimplemented!() }
},
syn::Type::Tuple(t) => {
// ******************************************************
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 {
// 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);
+ self.write_rust_path(w, generics, path, with_ref_lifetime, false);
} else {
// We shouldn't be mapping references in types, so panic here
unimplemented!();
let mut segments = syn::punctuated::Punctuated::new();
segments.push(parse_quote!(Vec<#args>));
self.write_c_type_intern(w, &syn::Type::Path(syn::TypePath { qself: None, path: syn::Path { leading_colon: None, segments } }), generics, false, is_mut, ptr_for_ref, with_ref_lifetime, c_ty)
+ } else if let syn::Type::Array(a) = &*s.elem {
+ if let syn::Expr::Lit(l) = &a.len {
+ if let syn::Lit::Int(i) = &l.lit {
+ let mut buf = Vec::new();
+ self.write_rust_type(&mut buf, generics, &*a.elem, false);
+ let arr_ty = String::from_utf8(buf).unwrap();
+
+ let arr_str = format!("[{}; {}]", arr_ty, i.base10_digits());
+ let ty = self.c_type_from_path(&arr_str, false, ptr_for_ref).unwrap()
+ .rsplitn(2, "::").next().unwrap();
+
+ let mangled_container = format!("CVec_{}Z", ty);
+ write!(w, "{}::{}", Self::generated_container_path(), mangled_container).unwrap();
+ self.check_create_container(mangled_container, "Vec", vec![&*s.elem], generics, false)
+ } else { false }
+ } else { false }
} else { false }
},
syn::Type::Tuple(t) => {