X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Ftypes.rs;h=740e8bdd2732fba3cdd4d1a4e62515431c78eae1;hb=42f443826a74246e49d8fbbd2590c061ca8308be;hp=9ef83f2a41a97221305f3aaeaecdf38f315ac712;hpb=ddf74802a4421f1ea1e221d801b3c342a32fade4;p=ldk-c-bindings diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index 9ef83f2..740e8bd 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -167,17 +167,18 @@ pub struct GenericTypes<'a, 'b> { self_ty: Option<(String, &'a syn::Path)>, parent: Option<&'b GenericTypes<'b, 'b>>, typed_generics: HashMap<&'a syn::Ident, (String, Option<&'a syn::Path>)>, + default_generics: HashMap<&'a syn::Ident, (&'a syn::Type, syn::Type)>, } impl<'a, 'p: 'a> GenericTypes<'a, 'p> { pub fn new(self_ty: Option<(String, &'a syn::Path)>) -> Self { - Self { self_ty, parent: None, typed_generics: HashMap::new(), } + Self { self_ty, parent: None, typed_generics: HashMap::new(), default_generics: HashMap::new(), } } /// push a new context onto the stack, allowing for a new set of generics to be learned which /// will override any lower contexts, but which will still fall back to resoltion via lower /// contexts. pub fn push_ctx<'c>(&'c self) -> GenericTypes<'a, 'c> { - GenericTypes { self_ty: None, parent: Some(self), typed_generics: HashMap::new(), } + GenericTypes { self_ty: None, parent: Some(self), typed_generics: HashMap::new(), default_generics: HashMap::new(), } } /// Learn the generics in generics in the current context, given a TypeResolver. @@ -200,7 +201,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { if path == "Sized" { continue; } if non_lifetimes_processed { return false; } non_lifetimes_processed = true; - let new_ident = if path != "std::ops::Deref" { + let new_ident = if path != "std::ops::Deref" && path != "core::ops::Deref" { path = "crate::".to_string() + &path; Some(&trait_bound.path) } else { None }; @@ -208,6 +209,10 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { } else { return false; } } } + if let Some(default) = type_param.default.as_ref() { + assert!(type_param.bounds.is_empty()); + self.default_generics.insert(&type_param.ident, (default, parse_quote!(&#default))); + } }, _ => {}, } @@ -221,7 +226,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { if p.path.leading_colon.is_some() { return false; } let mut p_iter = p.path.segments.iter(); if let Some(gen) = self.typed_generics.get_mut(&p_iter.next().unwrap().ident) { - if gen.0 != "std::ops::Deref" { return false; } + if gen.0 != "std::ops::Deref" && gen.0 != "core::ops::Deref" { return false; } if &format!("{}", p_iter.next().unwrap().ident) != "Target" { return false; } let mut non_lifetimes_processed = false; @@ -264,7 +269,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { // implement Deref for relevant types). We don't // bother to implement it for associated types, however, so we just // ignore such bounds. - let new_ident = if path != "std::ops::Deref" { + let new_ident = if path != "std::ops::Deref" && path != "core::ops::Deref" { path = "crate::".to_string() + &path; Some(&tr.path) } else { None }; @@ -296,6 +301,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { None } } + /// Attempt to resolve a Path as a generic parameter and return the full path. as both a string /// and syn::Path. pub fn maybe_resolve_path<'b>(&'b self, path: &syn::Path) -> Option<(&'b String, &'a syn::Path)> { @@ -327,6 +333,34 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { } } +trait ResolveType<'a> { fn resolve_type(&'a self, ty: &'a syn::Type) -> &'a syn::Type; } +impl<'a, 'b, 'c: 'a + 'b> ResolveType<'c> for Option<&GenericTypes<'a, 'b>> { + fn resolve_type(&'c self, ty: &'c syn::Type) -> &'c syn::Type { + if let Some(us) = self { + 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; + } + } + }, + syn::Type::Reference(syn::TypeReference { elem, .. }) => { + 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; + } + } + } + } + _ => {}, + } + } + ty + } +} + #[derive(Clone, PartialEq)] // The type of declaration and the object itself pub enum DeclType<'a> { @@ -781,6 +815,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { match ty { "()" => true, "crate::c_types::Signature" => true, + "crate::c_types::RecoverableSignature" => true, "crate::c_types::TxOut" => true, _ => false, } @@ -807,10 +842,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "[u8; 3]" if !is_ref => Some("crate::c_types::ThreeBytes"), // Used for RGB values "str" if is_ref => Some("crate::c_types::Str"), - "String" if !is_ref => Some("crate::c_types::derived::CVec_u8Z"), - "String" if is_ref => Some("crate::c_types::Str"), + "alloc::string::String"|"String" => Some("crate::c_types::Str"), - "std::time::Duration" => Some("u64"), + "std::time::Duration"|"core::time::Duration" => Some("u64"), "std::time::SystemTime" => Some("u64"), "std::io::Error" => Some("crate::c_types::IOError"), @@ -819,6 +853,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some("crate::c_types::PublicKey"), "bitcoin::secp256k1::Signature" => Some("crate::c_types::Signature"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some("crate::c_types::RecoverableSignature"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if is_ref => Some("*const [u8; 32]"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -844,8 +879,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "lightning::ln::PaymentHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), "lightning::ln::PaymentPreimage" if is_ref => Some("*const [u8; 32]"), "lightning::ln::PaymentPreimage" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), - "lightning::ln::PaymentSecret" if is_ref => Some("crate::c_types::ThirtyTwoBytes"), - "lightning::ln::PaymentSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), + "lightning::ln::PaymentSecret" => Some("crate::c_types::ThirtyTwoBytes"), // Override the default since Records contain an fmt with a lifetime: "lightning::util::logger::Record" => Some("*const std::os::raw::c_char"), @@ -879,11 +913,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "[usize]" if is_ref => Some(""), "str" if is_ref => Some(""), - "String" if !is_ref => Some("String::from_utf8("), + "alloc::string::String"|"String" => Some(""), // Note that we'll panic for String if is_ref, as we only have non-owned memory, we // cannot create a &String. - "std::time::Duration" => Some("std::time::Duration::from_secs("), + "std::time::Duration"|"core::time::Duration" => Some("std::time::Duration::from_secs("), "std::time::SystemTime" => Some("(::std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs("), "bech32::u5" => Some(""), @@ -894,6 +928,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { => Some(""), "bitcoin::secp256k1::Signature" if is_ref => Some("&"), "bitcoin::secp256k1::Signature" => Some(""), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some(""), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if is_ref => Some("&::bitcoin::secp256k1::key::SecretKey::from_slice(&unsafe { *"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -943,10 +978,10 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "[u8]" if is_ref => Some(".to_slice()"), "[usize]" if is_ref => Some(".to_slice()"), - "str" if is_ref => Some(".into()"), - "String" if !is_ref => Some(".into_rust()).unwrap()"), + "str" if is_ref => Some(".into_str()"), + "alloc::string::String"|"String" => Some(".into_string()"), - "std::time::Duration" => Some(")"), + "std::time::Duration"|"core::time::Duration" => Some(")"), "std::time::SystemTime" => Some("))"), "bech32::u5" => Some(".into()"), @@ -954,6 +989,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some(".into_rust()"), "bitcoin::secp256k1::Signature" => Some(".into_rust()"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some(".into_rust()"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if !is_ref => Some(".into_rust()"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -1022,9 +1058,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "[usize]" if is_ref => Some("local_"), "str" if is_ref => Some(""), - "String" => Some(""), + "alloc::string::String"|"String" => Some(""), - "std::time::Duration" => Some(""), + "std::time::Duration"|"core::time::Duration" => Some(""), "std::time::SystemTime" => Some(""), "std::io::Error" if !is_ref => Some("crate::c_types::IOError::from_rust("), @@ -1033,6 +1069,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some("crate::c_types::PublicKey::from_rust(&"), "bitcoin::secp256k1::Signature" => Some("crate::c_types::Signature::from_rust(&"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some("crate::c_types::RecoverableSignature::from_rust(&"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if is_ref => Some(""), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -1061,7 +1098,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "lightning::ln::PaymentHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), "lightning::ln::PaymentPreimage" if is_ref => Some("&"), "lightning::ln::PaymentPreimage" => Some("crate::c_types::ThirtyTwoBytes { data: "), - "lightning::ln::PaymentSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), + "lightning::ln::PaymentSecret" => Some("crate::c_types::ThirtyTwoBytes { data: "), // Override the default since Records contain an fmt with a lifetime: "lightning::util::logger::Record" => Some("local_"), @@ -1090,10 +1127,10 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "[usize]" if is_ref => Some(""), "str" if is_ref => Some(".into()"), - "String" if !is_ref => Some(".into_bytes().into()"), - "String" if is_ref => Some(".as_str().into()"), + "alloc::string::String"|"String" if is_ref => Some(".as_str().into()"), + "alloc::string::String"|"String" => Some(".into()"), - "std::time::Duration" => Some(".as_secs()"), + "std::time::Duration"|"core::time::Duration" => Some(".as_secs()"), "std::time::SystemTime" => Some(".duration_since(::std::time::SystemTime::UNIX_EPOCH).expect(\"Times must be post-1970\").as_secs()"), "std::io::Error" if !is_ref => Some(")"), @@ -1102,6 +1139,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some(")"), "bitcoin::secp256k1::Signature" => Some(")"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some(")"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if !is_ref => Some(")"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -1129,7 +1167,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "lightning::ln::PaymentHash" => Some(".0 }"), "lightning::ln::PaymentPreimage" if is_ref => Some(".0"), "lightning::ln::PaymentPreimage" => Some(".0 }"), - "lightning::ln::PaymentSecret" if !is_ref => Some(".0 }"), + "lightning::ln::PaymentSecret" => Some(".0 }"), // Override the default since Records contain an fmt with a lifetime: "lightning::util::logger::Record" => Some(".as_ptr()"), @@ -1221,17 +1259,25 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { Some(("Vec::new(); for item in ", vec![(format!(".iter() {{ local_{}.push(", var_name), "*item".to_string())], "); }", ContainerPrefixLocation::PerConv)) }, "Option" => { - if let Some(syn::Type::Path(p)) = single_contained { - let inner_path = self.resolve_path(&p.path, generics); + let contained_struct = if let Some(syn::Type::Path(p)) = single_contained { + Some(self.resolve_path(&p.path, generics)) + } else if let Some(syn::Type::Reference(r)) = single_contained { + if let syn::Type::Path(p) = &*r.elem { + Some(self.resolve_path(&p.path, generics)) + } else { None } + } else { None }; + if let Some(inner_path) = contained_struct { if self.is_primitive(&inner_path) { return Some(("if ", vec![ (format!(".is_none() {{ {}::COption_{}Z::None }} else {{ ", Self::generated_container_path(), inner_path), format!("{}::COption_{}Z::Some({}.unwrap())", Self::generated_container_path(), inner_path, var_access)) ], " }", ContainerPrefixLocation::NoPrefix)); } else if self.c_type_has_inner_from_path(&inner_path) { + let is_inner_ref = if let Some(syn::Type::Reference(_)) = single_contained { true } else { false }; if is_ref { return Some(("if ", vec![ - (".is_none() { std::ptr::null() } else { ".to_owned(), format!("({}.as_ref().unwrap())", var_access)) + (".is_none() { std::ptr::null() } else { ".to_owned(), + format!("({}{}.unwrap())", var_access, if is_inner_ref { "" } else { ".as_ref()" })) ], " }", ContainerPrefixLocation::OutsideConv)); } else { return Some(("if ", vec![ @@ -1340,6 +1386,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { let full_path = self.resolve_path(&p.path, None); self.c_type_has_inner_from_path(&full_path) }, + syn::Type::Reference(r) => { + self.c_type_has_inner(&*r.elem) + }, _ => false, } } @@ -1492,6 +1541,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { /// unint'd memory). pub fn write_empty_rust_val(&self, generics: Option<&GenericTypes>, w: &mut W, t: &syn::Type) { match t { + syn::Type::Reference(r) => { + self.write_empty_rust_val(generics, w, &*r.elem) + }, syn::Type::Path(p) => { let resolved = self.resolve_path(&p.path, generics); if self.crate_types.opaques.get(&resolved).is_some() { @@ -1537,6 +1589,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { /// See EmptyValExpectedTy for information on return types. fn write_empty_rust_val_check_suffix(&self, generics: Option<&GenericTypes>, w: &mut W, t: &syn::Type) -> EmptyValExpectedTy { match t { + syn::Type::Reference(r) => { + return self.write_empty_rust_val_check_suffix(generics, w, &*r.elem); + }, syn::Type::Path(p) => { let resolved = self.resolve_path(&p.path, generics); if let Some(arr_ty) = self.is_real_type_array(&resolved) { @@ -1578,6 +1633,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { /// Prints a suffix to determine if a variable is empty (ie was set by write_empty_rust_val). pub fn write_empty_rust_val_check(&self, generics: Option<&GenericTypes>, w: &mut W, t: &syn::Type, var_access: &str) { match t { + syn::Type::Reference(r) => { + self.write_empty_rust_val_check(generics, w, &*r.elem, var_access); + }, syn::Type::Path(_) => { write!(w, "{}", var_access).unwrap(); self.write_empty_rust_val_check_suffix(generics, w, t); @@ -1638,7 +1696,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { LP: Fn(&str, bool, bool) -> Option, DL: Fn(&mut W, &DeclType, &str, bool, bool), SC: Fn(bool, Option<&str>) -> String> (&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, is_mut: bool, ptr_for_ref: bool, tupleconv: &str, prefix: bool, sliceconv: SC, path_lookup: LP, decl_lookup: DL) { - match t { + match generics.resolve_type(t) { syn::Type::Reference(r) => { self.write_conversion_inline_intern(w, &*r.elem, generics, true, r.mutability.is_some(), ptr_for_ref, tupleconv, prefix, sliceconv, path_lookup, decl_lookup); @@ -1736,7 +1794,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } fn write_to_c_conversion_inline_prefix_inner(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, ptr_for_ref: bool, from_ptr: bool) { - self.write_conversion_inline_intern(w, t, generics, is_ref, false, ptr_for_ref, "0u8 /*", true, |_, _| "local_".to_owned(), + self.write_conversion_inline_intern(w, t, generics, is_ref, false, ptr_for_ref, "() /*", true, |_, _| "local_".to_owned(), |a, b, c| self.to_c_conversion_inline_prefix_from_path(a, b, c), |w, decl_type, decl_path, is_ref, _is_mut| { match decl_type { @@ -1895,13 +1953,15 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // pretty manual here and most of the below special-cases are for Options. let mut needs_ref_map = false; let mut only_contained_type = None; + let mut only_contained_type_nonref = None; let mut only_contained_has_inner = false; let mut contains_slice = false; if $args_len == 1 { only_contained_has_inner = ty_has_inner; let arg = $args_iter().next().unwrap(); if let syn::Type::Reference(t) = arg { - only_contained_type = Some(&*t.elem); + only_contained_type = Some(arg); + only_contained_type_nonref = Some(&*t.elem); if let syn::Type::Path(_) = &*t.elem { is_ref = true; } else if let syn::Type::Slice(_) = &*t.elem { @@ -1912,7 +1972,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // do an extra mapping step. needs_ref_map = !only_contained_has_inner; } else { - only_contained_type = Some(&arg); + only_contained_type = Some(arg); + only_contained_type_nonref = Some(arg); } } @@ -1929,7 +1990,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { write!(&mut var, "{}", var_name).unwrap(); let var_access = String::from_utf8(var.into_inner()).unwrap(); - let conv_ty = if needs_ref_map { only_contained_type.as_ref().unwrap() } else { ty }; + let conv_ty = if needs_ref_map { only_contained_type_nonref.as_ref().unwrap() } else { ty }; write!(w, "{} {{ ", pfx).unwrap(); let new_var_name = format!("{}_{}", ident, idx); @@ -1968,7 +2029,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } } } - match t { + match generics.resolve_type(t) { syn::Type::Reference(r) => { if let syn::Type::Slice(_) = &*r.elem { self.write_conversion_new_var_intern(w, ident, var, &*r.elem, generics, is_ref, ptr_for_ref, to_c, path_lookup, container_lookup, var_prefix, var_suffix) @@ -2412,7 +2473,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } } fn write_c_type_intern(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, is_mut: bool, ptr_for_ref: bool) -> bool { - match t { + match generics.resolve_type(t) { syn::Type::Path(p) => { if p.qself.is_some() { return false;