From a14e63e0b34eed7a6ed341e897ed1c2257dad13f Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 25 Sep 2020 13:25:35 -0400 Subject: [PATCH] [bindings] Support mapping slices which contain tuples (with refs) New work upstream puts tuples in slices, which is a very reasonable thing to expect, however we don't know how to generate conversions for such objects. Making it more complicated, upstream changes also include references to things inside such slices, which requires special handling to avoid creating dangling references. This adds support for converting such objects, noting that slices need to be converted first into Vecs which own their underlying objects and then need to map any reference types into references. --- c-bindings-gen/src/types.rs | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index 1ddbe3cb..46f6f984 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -1205,6 +1205,33 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { if let syn::Type::Path(p) = &*r.elem { write!(w, "{}", sliceconv(self.c_type_has_inner_from_path(&self.resolve_path(&p.path, generics)))).unwrap(); } else { unimplemented!(); } + } else if let syn::Type::Tuple(t) = &*s.elem { + assert!(!t.elems.is_empty()); + if prefix { + write!(w, "&local_").unwrap(); + } else { + let mut needs_map = false; + for e in t.elems.iter() { + if let syn::Type::Reference(_) = e { + needs_map = true; + } + } + if needs_map { + write!(w, ".iter().map(|(").unwrap(); + for i in 0..t.elems.len() { + write!(w, "{}{}", if i != 0 { ", " } else { "" }, ('a' as u8 + i as u8) as char).unwrap(); + } + write!(w, ")| (").unwrap(); + for (idx, e) in t.elems.iter().enumerate() { + if let syn::Type::Reference(_) = e { + write!(w, "{}{}", if idx != 0 { ", " } else { "" }, (idx as u8 + 'a' as u8) as char).unwrap(); + } else if let syn::Type::Path(_) = e { + write!(w, "{}*{}", if idx != 0 { ", " } else { "" }, (idx as u8 + 'a' as u8) as char).unwrap(); + } else { unimplemented!(); } + } + write!(w, ")).collect::>()[..]").unwrap(); + } + } } else { unimplemented!(); } }, syn::Type::Tuple(t) => { @@ -1491,6 +1518,24 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { is_ref = true; convert_container!("Slice", 1, || tyref.iter()); unimplemented!("convert_container should return true as container_lookup should succeed for slices"); + } else if let syn::Type::Tuple(t) = &*s.elem { + // When mapping into a temporary new var, we need to own all the underlying objects. + // Thus, we drop any references inside the tuple and convert with non-reference types. + let mut elems = syn::punctuated::Punctuated::new(); + for elem in t.elems.iter() { + if let syn::Type::Reference(r) = elem { + elems.push((*r.elem).clone()); + } else { + elems.push(elem.clone()); + } + } + let ty = [syn::Type::Tuple(syn::TypeTuple { + paren_token: t.paren_token, elems + })]; + is_ref = false; + ptr_for_ref = true; + convert_container!("Slice", 1, || ty.iter()); + unimplemented!("convert_container should return true as container_lookup should succeed for slices"); } else { unimplemented!() } }, syn::Type::Tuple(t) => { @@ -1808,6 +1853,10 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { for elem in tuple.elems.iter() { if let syn::Type::Path(p) = elem { write_path!(p, Some(&mut mangled_tuple_type)); + } else if let syn::Type::Reference(refelem) = elem { + if let syn::Type::Path(p) = &*refelem.elem { + write_path!(p, Some(&mut mangled_tuple_type)); + } else { return false; } } else { return false; } } write!(w, "Z").unwrap(); @@ -1963,6 +2012,17 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { self.check_create_container(mangled_container, "Vec", vec![&*r.elem], generics, false); true } else { false } + } else if let syn::Type::Tuple(_) = &*s.elem { + let mut args = syn::punctuated::Punctuated::new(); + args.push(syn::GenericArgument::Type((*s.elem).clone())); + let mut segments = syn::punctuated::Punctuated::new(); + segments.push(syn::PathSegment { + ident: syn::Ident::new("Vec", Span::call_site()), + arguments: syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + colon2_token: None, lt_token: syn::Token![<](Span::call_site()), args, gt_token: syn::Token![>](Span::call_site()), + }) + }); + 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) } else { false } }, syn::Type::Tuple(t) => { -- 2.30.2