From 6adbe96a03e129820d161b12bff80e748c68f68e Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 6 Sep 2021 00:53:56 +0000 Subject: [PATCH] Map Vecs to slices when constructing a getter for a public field This adds logic to allow constructing a getter for a public Vec field where the inner items are opaque structs. In order to do this we map them as slices, which will end up generating Vecs with elements which all have their `is_owned` flags unset. --- c-bindings-gen/src/main.rs | 27 ++++++++++---------- c-bindings-gen/src/types.rs | 49 +++++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/c-bindings-gen/src/main.rs b/c-bindings-gen/src/main.rs index 5ac8380..bfadca0 100644 --- a/c-bindings-gen/src/main.rs +++ b/c-bindings-gen/src/main.rs @@ -618,20 +618,19 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct, } if let Some(ident) = &field.ident { - let ref_type = syn::Type::Reference(syn::TypeReference { - and_token: syn::Token!(&)(Span::call_site()), lifetime: None, mutability: None, - elem: Box::new(field.ty.clone()) }); - if types.understood_c_type(&ref_type, Some(&gen_types)) { - writeln_arg_docs(w, &field.attrs, "", types, Some(&gen_types), vec![].drain(..), Some(&ref_type)); - write!(w, "#[no_mangle]\npub extern \"C\" fn {}_get_{}(this_ptr: &{}) -> ", struct_name, ident, struct_name).unwrap(); - types.write_c_type(w, &ref_type, Some(&gen_types), true); - write!(w, " {{\n\tlet mut inner_val = &mut this_ptr.get_native_mut_ref().{};\n\t", ident).unwrap(); - let local_var = types.write_to_c_conversion_new_var(w, &format_ident!("inner_val"), &ref_type, Some(&gen_types), true); - if local_var { write!(w, "\n\t").unwrap(); } - types.write_to_c_conversion_inline_prefix(w, &ref_type, Some(&gen_types), true); - write!(w, "inner_val").unwrap(); - types.write_to_c_conversion_inline_suffix(w, &ref_type, Some(&gen_types), true); - writeln!(w, "\n}}").unwrap(); + if let Some(ref_type) = types.create_ownable_reference(&field.ty, Some(&gen_types)) { + if types.understood_c_type(&ref_type, Some(&gen_types)) { + writeln_arg_docs(w, &field.attrs, "", types, Some(&gen_types), vec![].drain(..), Some(&ref_type)); + write!(w, "#[no_mangle]\npub extern \"C\" fn {}_get_{}(this_ptr: &{}) -> ", struct_name, ident, struct_name).unwrap(); + types.write_c_type(w, &ref_type, Some(&gen_types), true); + write!(w, " {{\n\tlet mut inner_val = &mut this_ptr.get_native_mut_ref().{};\n\t", ident).unwrap(); + let local_var = types.write_to_c_conversion_new_var(w, &format_ident!("inner_val"), &ref_type, Some(&gen_types), true); + if local_var { write!(w, "\n\t").unwrap(); } + types.write_to_c_conversion_inline_prefix(w, &ref_type, Some(&gen_types), true); + write!(w, "inner_val").unwrap(); + types.write_to_c_conversion_inline_suffix(w, &ref_type, Some(&gen_types), true); + writeln!(w, "\n}}").unwrap(); + } } if types.understood_c_type(&field.ty, Some(&gen_types)) { diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index d17148f..ed26df7 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -1431,6 +1431,49 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } } + /// Constructs a reference to the given type, possibly tweaking the type if relevant to make it + /// convertable to C. + pub fn create_ownable_reference(&self, t: &syn::Type, generics: Option<&GenericTypes>) -> Option { + let default_value = Some(syn::Type::Reference(syn::TypeReference { + and_token: syn::Token!(&)(Span::call_site()), lifetime: None, mutability: None, + elem: Box::new(t.clone()) })); + match t { + syn::Type::Path(p) => { + if let Some(resolved_path) = self.maybe_resolve_path(&p.path, generics) { + if resolved_path != "Vec" { return default_value; } + if p.path.segments.len() != 1 { unimplemented!(); } + let only_seg = p.path.segments.iter().next().unwrap(); + if let syn::PathArguments::AngleBracketed(args) = &only_seg.arguments { + if args.args.len() != 1 { unimplemented!(); } + let inner_arg = args.args.iter().next().unwrap(); + if let syn::GenericArgument::Type(ty) = &inner_arg { + let mut can_create = self.c_type_has_inner(&ty); + if let syn::Type::Path(inner) = ty { + if inner.path.segments.len() == 1 && + format!("{}", inner.path.segments[0].ident) == "Vec" { + can_create = true; + } + } + if !can_create { return default_value; } + if let Some(inner_ty) = self.create_ownable_reference(&ty, generics) { + return Some(syn::Type::Reference(syn::TypeReference { + and_token: syn::Token![&](Span::call_site()), + lifetime: None, + mutability: None, + elem: Box::new(syn::Type::Slice(syn::TypeSlice { + bracket_token: syn::token::Bracket { span: Span::call_site() }, + elem: Box::new(inner_ty) + })) + })); + } else { return default_value; } + } else { unimplemented!(); } + } else { unimplemented!(); } + } else { return None; } + }, + _ => default_value, + } + } + // ************************************************* // *** Type definition during main.rs processing *** // ************************************************* @@ -1442,12 +1485,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { pub fn c_type_has_inner_from_path(&self, full_path: &str) -> bool { self.crate_types.opaques.get(full_path).is_some() } + /// Returns true if the object at the given path is mapped as X { inner: *mut origX, .. }. pub fn c_type_has_inner(&self, ty: &syn::Type) -> bool { match ty { syn::Type::Path(p) => { - let full_path = self.resolve_path(&p.path, None); - self.c_type_has_inner_from_path(&full_path) + if let Some(full_path) = self.maybe_resolve_path(&p.path, None) { + self.c_type_has_inner_from_path(&full_path) + } else { false } }, syn::Type::Reference(r) => { self.c_type_has_inner(&*r.elem) -- 2.30.2