X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Ftypes.rs;h=ecc508dbca8d26ff0ab7ec92df486562e39095d6;hb=50af954e76be66d0a1a4e3ba210bd849c4780b8d;hp=1a737d17cf11203ef1720015164d75ed7e3dd060;hpb=45ad3320df3768514d968c70fc4b6a9d50028050;p=ldk-c-bindings diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index 1a737d1..ecc508d 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -147,7 +147,7 @@ pub fn export_status(attrs: &[syn::Attribute]) -> ExportStatus { } pub fn assert_simple_bound(bound: &syn::TraitBound) { - if bound.paren_token.is_some() || bound.lifetimes.is_some() { unimplemented!(); } + if bound.paren_token.is_some() { unimplemented!(); } if let syn::TraitBoundModifier::Maybe(_) = bound.modifier { unimplemented!(); } } @@ -205,10 +205,10 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { } /// Learn the generics in generics in the current context, given a TypeResolver. - pub fn learn_generics<'b, 'c>(&mut self, generics: &'a syn::Generics, types: &'b TypeResolver<'a, 'c>) -> bool { + pub fn learn_generics_with_impls<'b, 'c>(&mut self, generics: &'a syn::Generics, impld_generics: &'a syn::PathArguments, types: &'b TypeResolver<'a, 'c>) -> bool { let mut new_typed_generics = HashMap::new(); // First learn simple generics... - for generic in generics.params.iter() { + for (idx, generic) in generics.params.iter().enumerate() { match generic { syn::GenericParam::Type(type_param) => { let mut non_lifetimes_processed = false; @@ -260,6 +260,15 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { 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), parse_quote!(&mut #default))); + } else if type_param.bounds.is_empty() { + if let syn::PathArguments::AngleBracketed(args) = impld_generics { + match &args.args[idx] { + syn::GenericArgument::Type(ty) => { + self.default_generics.insert(&type_param.ident, (ty.clone(), parse_quote!(&#ty), parse_quote!(&mut #ty))); + } + _ => unimplemented!(), + } + } } }, _ => {}, @@ -270,6 +279,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { for pred in wh.predicates.iter() { if let syn::WherePredicate::Type(t) = pred { if let syn::Type::Path(p) = &t.bounded_ty { + if first_seg_self(&t.bounded_ty).is_some() && p.path.segments.len() == 1 { continue; } if p.qself.is_some() { return false; } if p.path.leading_colon.is_some() { return false; } let mut p_iter = p.path.segments.iter(); @@ -315,6 +325,11 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { true } + /// Learn the generics in generics in the current context, given a TypeResolver. + pub fn learn_generics<'b, 'c>(&mut self, generics: &'a syn::Generics, types: &'b TypeResolver<'a, 'c>) -> bool { + self.learn_generics_with_impls(generics, &syn::PathArguments::None, types) + } + /// Learn the associated types from the trait in the current context. pub fn learn_associated_types<'b, 'c>(&mut self, t: &'a syn::ItemTrait, types: &'b TypeResolver<'a, 'c>) { for item in t.items.iter() { @@ -936,6 +951,10 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::ecdsa::RecoverableSignature" => Some("crate::c_types::RecoverableSignature"), "bitcoin::secp256k1::SecretKey" if is_ref => Some("*const [u8; 32]"), "bitcoin::secp256k1::SecretKey" if !is_ref => Some("crate::c_types::SecretKey"), + "bitcoin::secp256k1::Scalar" if is_ref => Some("*const crate::c_types::BigEndianScalar"), + "bitcoin::secp256k1::Scalar" if !is_ref => Some("crate::c_types::BigEndianScalar"), + "bitcoin::secp256k1::ecdh::SharedSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), + "bitcoin::blockdata::script::Script" if is_ref => Some("crate::c_types::u8slice"), "bitcoin::blockdata::script::Script" if !is_ref => Some("crate::c_types::derived::CVec_u8Z"), "bitcoin::blockdata::transaction::OutPoint" => Some("crate::lightning::chain::transaction::OutPoint"), @@ -1021,6 +1040,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::ecdsa::RecoverableSignature" => Some(""), "bitcoin::secp256k1::SecretKey" if is_ref => Some("&::bitcoin::secp256k1::SecretKey::from_slice(&unsafe { *"), "bitcoin::secp256k1::SecretKey" if !is_ref => Some(""), + "bitcoin::secp256k1::Scalar" if !is_ref => Some(""), + "bitcoin::secp256k1::ecdh::SharedSecret" if !is_ref => Some("::bitcoin::secp256k1::ecdh::SharedSecret::from_bytes("), + "bitcoin::blockdata::script::Script" if is_ref => Some("&::bitcoin::blockdata::script::Script::from(Vec::from("), "bitcoin::blockdata::script::Script" if !is_ref => Some("::bitcoin::blockdata::script::Script::from("), "bitcoin::blockdata::transaction::Transaction"|"bitcoin::Transaction" if is_ref => Some("&"), @@ -1104,6 +1126,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::ecdsa::RecoverableSignature" => Some(".into_rust()"), "bitcoin::secp256k1::SecretKey" if !is_ref => Some(".into_rust()"), "bitcoin::secp256k1::SecretKey" if is_ref => Some("}[..]).unwrap()"), + "bitcoin::secp256k1::Scalar" if !is_ref => Some(".into_rust()"), + "bitcoin::secp256k1::ecdh::SharedSecret" if !is_ref => Some(".data)"), + "bitcoin::blockdata::script::Script" if is_ref => Some(".to_slice()))"), "bitcoin::blockdata::script::Script" if !is_ref => Some(".into_rust())"), "bitcoin::blockdata::transaction::Transaction"|"bitcoin::Transaction" => Some(".into_bitcoin()"), @@ -1196,6 +1221,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::ecdsa::RecoverableSignature" => Some("crate::c_types::RecoverableSignature::from_rust(&"), "bitcoin::secp256k1::SecretKey" if is_ref => Some(""), "bitcoin::secp256k1::SecretKey" if !is_ref => Some("crate::c_types::SecretKey::from_rust("), + "bitcoin::secp256k1::Scalar" if !is_ref => Some("crate::c_types::BigEndianScalar::from_rust("), + "bitcoin::secp256k1::ecdh::SharedSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), + "bitcoin::blockdata::script::Script" if is_ref => Some("crate::c_types::u8slice::from_slice(&"), "bitcoin::blockdata::script::Script" if !is_ref => Some(""), "bitcoin::blockdata::transaction::Transaction"|"bitcoin::Transaction" if is_ref => Some("crate::c_types::Transaction::from_bitcoin("), @@ -1273,6 +1301,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::ecdsa::RecoverableSignature" => Some(")"), "bitcoin::secp256k1::SecretKey" if !is_ref => Some(")"), "bitcoin::secp256k1::SecretKey" if is_ref => Some(".as_ref()"), + "bitcoin::secp256k1::Scalar" if !is_ref => Some(")"), + "bitcoin::secp256k1::ecdh::SharedSecret" if !is_ref => Some(".secret_bytes() }"), + "bitcoin::blockdata::script::Script" if is_ref => Some("[..])"), "bitcoin::blockdata::script::Script" if !is_ref => Some(".into_bytes().into()"), "bitcoin::blockdata::transaction::Transaction"|"bitcoin::Transaction" => Some(")"), @@ -1381,7 +1412,19 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { if let Some(resolved) = self.maybe_resolve_path(&p.path, generics) { 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 } + // We want to move to using `Option_` mappings where possible rather than + // manual mappings, as it makes downstream bindings simpler and is more + // clear for users. Thus, we default to false but override for a few + // types which had mappings defined when we were avoiding the `Option_`s. + match &resolved as &str { + "lightning::ln::PaymentSecret" => true, + "lightning::ln::PaymentHash" => true, + "lightning::ln::PaymentPreimage" => true, + "lightning::ln::channelmanager::PaymentId" => true, + "bitcoin::hash_types::BlockHash" => true, + "secp256k1::PublicKey"|"bitcoin::secp256k1::PublicKey" => true, + _ => false, + } } else { unimplemented!(); } }, syn::Type::Tuple(_) => false, @@ -1456,7 +1499,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { (".is_none() { core::ptr::null_mut() } else { ".to_owned(), format!("({}.unwrap())", var_access)) ], " }", ContainerPrefixLocation::OutsideConv)); } - } else if self.is_primitive(&inner_path) || self.c_type_from_path(&inner_path, false, false).is_none() { + } else if !self.is_transparent_container("Option", is_ref, [single_contained.unwrap()].iter().map(|a| *a), generics) { if self.is_primitive(&inner_path) || (!is_contained_ref && !is_ref) || only_contained_has_inner { let inner_name = self.get_c_mangled_container_type(vec![single_contained.unwrap()], generics, "Option").unwrap(); return Some(("if ", vec![ @@ -1477,12 +1520,18 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } 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 { @@ -2039,6 +2088,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { 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) => { @@ -2391,6 +2442,12 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { 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) => { @@ -2901,6 +2958,22 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { 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) => {