X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Ftypes.rs;h=74db47ccb35054f45943fcbc90d973cc68215d03;hb=11063db7153ff78d289674672099d69af0ff6a8d;hp=d17148fe25d1378d2ecec2d9c1f2a4f10394f8e5;hpb=ed6eb46f7b4e0d4c869ad08dffc600b4e93e2129;p=ldk-c-bindings diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index d17148f..74db47c 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 generics.resolve_type(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) @@ -1809,6 +1854,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } else if let syn::Type::Reference(r) = &*s.elem { if let syn::Type::Path(p) = &*r.elem { write!(w, "{}", sliceconv(self.c_type_has_inner_from_path(&self.resolve_path(&p.path, generics)), None)).unwrap(); + } else if let syn::Type::Slice(_) = &*r.elem { + write!(w, "{}", sliceconv(false, None)).unwrap(); } else { unimplemented!(); } } else if let syn::Type::Tuple(t) = &*s.elem { assert!(!t.elems.is_empty()); @@ -1875,7 +1922,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { DeclType::EnumIgnored|DeclType::StructImported if !is_ref => write!(w, "crate::{} {{ inner: ObjOps::heap_alloc(", decl_path).unwrap(), DeclType::Trait(_) if is_ref => write!(w, "").unwrap(), - DeclType::Trait(_) if !is_ref => {}, + DeclType::Trait(_) if !is_ref => write!(w, "Into::into(").unwrap(), _ => panic!("{:?}", decl_path), } }); @@ -1901,7 +1948,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // for use when a Rust trait method returns an associated type. // Because all of our C traits implement From // we can just call .into() here and be done. - write!(w, ".into()").unwrap() + write!(w, ")").unwrap() }, _ => unimplemented!(), }); @@ -2109,7 +2156,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { if let syn::PathArguments::AngleBracketed(args) = &p.path.segments.iter().next().unwrap().arguments { convert_container!(resolved_path, args.args.len(), || args.args.iter().map(|arg| { if let syn::GenericArgument::Type(ty) = arg { - ty + generics.resolve_type(ty) } else { unimplemented!(); } })); } else { unimplemented!(); } @@ -2142,7 +2189,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } else if let syn::Type::Reference(ty) = &*s.elem { let tyref = [&*ty.elem]; is_ref = true; - convert_container!("Slice", 1, || tyref.iter().map(|t| *t)); + convert_container!("Slice", 1, || tyref.iter().map(|t| generics.resolve_type(*t))); 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. @@ -2417,62 +2464,68 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } else { return false; } } } - if let syn::Type::Tuple(tuple) = arg { - if tuple.elems.len() == 0 { - write!(w, "None").unwrap(); - write!(mangled_type, "None").unwrap(); - } else { - let mut mangled_tuple_type: Vec = Vec::new(); - - // Figure out what the mangled type should look like. To disambiguate - // ((A, B), C) and (A, B, C) we prefix the generic args with a _ and suffix - // them with a Z. Ideally we wouldn't use Z, but not many special chars are - // available for use in type names. - write!(w, "C{}Tuple_", tuple.elems.len()).unwrap(); - write!(mangled_type, "C{}Tuple_", tuple.elems.len()).unwrap(); - write!(mangled_tuple_type, "C{}Tuple_", tuple.elems.len()).unwrap(); - 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 { + match generics.resolve_type(arg) { + syn::Type::Tuple(tuple) => { + if tuple.elems.len() == 0 { + write!(w, "None").unwrap(); + write!(mangled_type, "None").unwrap(); + } else { + let mut mangled_tuple_type: Vec = Vec::new(); + + // Figure out what the mangled type should look like. To disambiguate + // ((A, B), C) and (A, B, C) we prefix the generic args with a _ and suffix + // them with a Z. Ideally we wouldn't use Z, but not many special chars are + // available for use in type names. + write!(w, "C{}Tuple_", tuple.elems.len()).unwrap(); + write!(mangled_type, "C{}Tuple_", tuple.elems.len()).unwrap(); + write!(mangled_tuple_type, "C{}Tuple_", tuple.elems.len()).unwrap(); + 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; } - } else { return false; } - } - write!(w, "Z").unwrap(); - write!(mangled_type, "Z").unwrap(); - write!(mangled_tuple_type, "Z").unwrap(); - if !self.check_create_container(String::from_utf8(mangled_tuple_type).unwrap(), - &format!("{}Tuple", tuple.elems.len()), tuple.elems.iter().collect(), generics, is_ref) { - return false; + } + write!(w, "Z").unwrap(); + write!(mangled_type, "Z").unwrap(); + write!(mangled_tuple_type, "Z").unwrap(); + if !self.check_create_container(String::from_utf8(mangled_tuple_type).unwrap(), + &format!("{}Tuple", tuple.elems.len()), tuple.elems.iter().collect(), generics, is_ref) { + return false; + } } - } - } else if let syn::Type::Path(p_arg) = arg { - write_path!(p_arg, None); - } else if let syn::Type::Reference(refty) = arg { - if let syn::Type::Path(p_arg) = &*refty.elem { + }, + syn::Type::Path(p_arg) => { write_path!(p_arg, None); - } else if let syn::Type::Slice(_) = &*refty.elem { - // write_c_type will actually do exactly what we want here, we just need to - // make it a pointer so that its an option. Note that we cannot always convert - // the Vec-as-slice (ie non-ref types) containers, so sometimes need to be able - // to edit it, hence we use *mut here instead of *const. - if args.len() != 1 { return false; } - write!(w, "*mut ").unwrap(); - self.write_c_type(w, arg, None, true); - } else { return false; } - } else if let syn::Type::Array(a) = arg { - if let syn::Type::Path(p_arg) = &*a.elem { - let resolved = self.resolve_path(&p_arg.path, generics); - if !self.is_primitive(&resolved) { return false; } - if let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(len), .. }) = &a.len { - if self.c_type_from_path(&format!("[{}; {}]", resolved, len.base10_digits()), is_ref, ptr_for_ref).is_none() { return false; } - write!(w, "_{}{}", resolved, len.base10_digits()).unwrap(); - write!(mangled_type, "_{}{}", resolved, len.base10_digits()).unwrap(); + }, + syn::Type::Reference(refty) => { + if let syn::Type::Path(p_arg) = &*refty.elem { + write_path!(p_arg, None); + } else if let syn::Type::Slice(_) = &*refty.elem { + // write_c_type will actually do exactly what we want here, we just need to + // make it a pointer so that its an option. Note that we cannot always convert + // the Vec-as-slice (ie non-ref types) containers, so sometimes need to be able + // to edit it, hence we use *mut here instead of *const. + if args.len() != 1 { return false; } + write!(w, "*mut ").unwrap(); + self.write_c_type(w, arg, None, true); } else { return false; } - } else { return false; } - } else { return false; } + }, + syn::Type::Array(a) => { + if let syn::Type::Path(p_arg) = &*a.elem { + let resolved = self.resolve_path(&p_arg.path, generics); + if !self.is_primitive(&resolved) { return false; } + if let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(len), .. }) = &a.len { + if self.c_type_from_path(&format!("[{}; {}]", resolved, len.base10_digits()), is_ref, ptr_for_ref).is_none() { return false; } + write!(w, "_{}{}", resolved, len.base10_digits()).unwrap(); + write!(mangled_type, "_{}{}", resolved, len.base10_digits()).unwrap(); + } else { return false; } + } else { return false; } + }, + _ => { return false; }, + } } if self.is_transparent_container(ident, is_ref, args.iter().map(|a| *a)) { return true; } // Push the "end of type" Z @@ -2598,6 +2651,20 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } else { return false; }; write!(w, "{}::{}", Self::generated_container_path(), mangled_container).unwrap(); self.check_create_container(mangled_container, "Vec", vec![&*r.elem], generics, false) + } else if let syn::Type::Slice(sl2) = &*r.elem { + if let syn::Type::Reference(r2) = &*sl2.elem { + if let syn::Type::Path(p) = &*r2.elem { + // Slices with slices with opaque types (with is_owned flags) are mapped as non-ref Vecs + let resolved = self.resolve_path(&p.path, generics); + let mangled_container = if let Some(ident) = self.crate_types.opaques.get(&resolved) { + format!("CVec_CVec_{}ZZ", ident) + } else { return false; }; + write!(w, "{}::{}", Self::generated_container_path(), mangled_container).unwrap(); + let inner = &r2.elem; + let vec_ty: syn::Type = syn::parse_quote!(Vec<#inner>); + self.check_create_container(mangled_container, "Vec", vec![&vec_ty], generics, false) + } else { false } + } else { false } } else { false } } else if let syn::Type::Tuple(_) = &*s.elem { let mut args = syn::punctuated::Punctuated::<_, syn::token::Comma>::new();