X-Git-Url: http://git.bitcoin.ninja/index.cgi?p=ldk-c-bindings;a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Ftypes.rs;h=13c3b0ed0c2b7b3b00b4af8e58728a117614d6cb;hp=16f3ff56663300631a80467f0fade67cd66dd0c6;hb=a82e075188fc15a103234832686915c196bfe240;hpb=b5cc72e8ce49dc692e5c1eea3b6db963e6b677d2 diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index 16f3ff5..13c3b0e 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -15,6 +15,8 @@ use std::hash; use crate::blocks::*; use proc_macro2::{TokenTree, Span}; +use quote::format_ident; +use syn::parse_quote; // The following utils are used purely to build our known types maps - they break down all the // types we need to resolve to include the given object, and no more. @@ -64,6 +66,11 @@ pub enum ExportStatus { Export, NoExport, TestOnly, + /// This is used only for traits to indicate that users should not be able to implement their + /// own version of a trait, but we should export Rust implementations of the trait (and the + /// trait itself). + /// Concretly, this means that we do not implement the Rust trait for the C trait struct. + NotImplementable, } /// Gets the ExportStatus of an object (struct, fn, etc) given its attributes. pub fn export_status(attrs: &[syn::Attribute]) -> ExportStatus { @@ -115,6 +122,8 @@ pub fn export_status(attrs: &[syn::Attribute]) -> ExportStatus { let line = format!("{}", lit); if line.contains("(C-not exported)") { return ExportStatus::NoExport; + } else if line.contains("(C-not implementable)") { + return ExportStatus::NotImplementable; } }, _ => unimplemented!(), @@ -136,6 +145,7 @@ pub fn is_enum_opaque(e: &syn::ItemEnum) -> bool { for field in fields.named.iter() { match export_status(&field.attrs) { ExportStatus::Export|ExportStatus::TestOnly => {}, + ExportStatus::NotImplementable => panic!("(C-not implementable) should only appear on traits!"), ExportStatus::NoExport => return true, } } @@ -143,6 +153,7 @@ pub fn is_enum_opaque(e: &syn::ItemEnum) -> bool { for field in fields.unnamed.iter() { match export_status(&field.attrs) { ExportStatus::Export|ExportStatus::TestOnly => {}, + ExportStatus::NotImplementable => panic!("(C-not implementable) should only appear on traits!"), ExportStatus::NoExport => return true, } } @@ -162,19 +173,21 @@ pub fn is_enum_opaque(e: &syn::ItemEnum) -> bool { /// concrete C container struct, etc). #[must_use] 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, (syn::Type, syn::Type)>, } impl<'a, 'p: 'a> GenericTypes<'a, 'p> { - pub fn new() -> Self { - Self { parent: None, typed_generics: HashMap::new(), } + pub fn new(self_ty: Option<(String, &'a syn::Path)>) -> Self { + 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 { 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. @@ -184,7 +197,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { match generic { syn::GenericParam::Type(type_param) => { let mut non_lifetimes_processed = false; - for bound in type_param.bounds.iter() { + 'bound_loop: for bound in type_param.bounds.iter() { if let syn::TypeParamBound::Trait(trait_bound) = bound { if let Some(ident) = single_ident_generic_path_to_ident(&trait_bound.path) { match &format!("{}", ident) as &str { "Send" => continue, "Sync" => continue, _ => {} } @@ -194,16 +207,41 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { assert_simple_bound(&trait_bound); if let Some(mut path) = types.maybe_resolve_path(&trait_bound.path, None) { if types.skip_path(&path) { continue; } + 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 if trait_bound.path.segments.len() == 1 { + // If we're templated on Deref, store + // the reference type in `default_generics` which handles full + // types and not just paths. + if let syn::PathArguments::AngleBracketed(ref args) = + trait_bound.path.segments[0].arguments { + for subargument in args.args.iter() { + match subargument { + syn::GenericArgument::Lifetime(_) => {}, + syn::GenericArgument::Binding(ref b) => { + if &format!("{}", b.ident) != "Target" { return false; } + let default = &b.ty; + self.default_generics.insert(&type_param.ident, (parse_quote!(&#default), parse_quote!(&#default))); + break 'bound_loop; + }, + _ => unimplemented!(), + } + } + None + } else { None } } else { None }; self.typed_generics.insert(&type_param.ident, (path, new_ident)); } 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.clone(), parse_quote!(&#default))); + } }, _ => {}, } @@ -217,12 +255,15 @@ 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; for bound in t.bounds.iter() { if let syn::TypeParamBound::Trait(trait_bound) = bound { + if let Some(id) = trait_bound.path.get_ident() { + if format!("{}", id) == "Sized" { continue; } + } if non_lifetimes_processed { return false; } non_lifetimes_processed = true; assert_simple_bound(&trait_bound); @@ -257,7 +298,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 }; @@ -275,6 +316,11 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { /// Attempt to resolve an Ident as a generic parameter and return the full path. pub fn maybe_resolve_ident<'b>(&'b self, ident: &syn::Ident) -> Option<&'b String> { + if let Some(ty) = &self.self_ty { + if format!("{}", ident) == "Self" { + return Some(&ty.0); + } + } if let Some(res) = self.typed_generics.get(ident).map(|(a, _)| a) { return Some(res); } @@ -284,10 +330,16 @@ 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)> { if let Some(ident) = path.get_ident() { + if let Some(ty) = &self.self_ty { + if format!("{}", ident) == "Self" { + return Some((&ty.0, ty.1)); + } + } if let Some(res) = self.typed_generics.get(ident).map(|(a, b)| (a, b.unwrap())) { return Some(res); } @@ -310,6 +362,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> { @@ -321,33 +401,57 @@ pub enum DeclType<'a> { } pub struct ImportResolver<'mod_lifetime, 'crate_lft: 'mod_lifetime> { + crate_name: &'mod_lifetime str, + dependencies: &'mod_lifetime HashSet, module_path: &'mod_lifetime str, imports: HashMap, declared: HashMap>, priv_modules: HashSet, } impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'crate_lft> { - fn process_use_intern(imports: &mut HashMap, u: &syn::UseTree, partial_path: &str, mut path: syn::punctuated::Punctuated) { + fn process_use_intern(crate_name: &str, module_path: &str, dependencies: &HashSet, imports: &mut HashMap, + u: &syn::UseTree, partial_path: &str, mut path: syn::punctuated::Punctuated) { + + let new_path; + macro_rules! push_path { + ($ident: expr, $path_suffix: expr) => { + if partial_path == "" && format!("{}", $ident) == "super" { + let mut mod_iter = module_path.rsplitn(2, "::"); + mod_iter.next().unwrap(); + let super_mod = mod_iter.next().unwrap(); + new_path = format!("{}{}", super_mod, $path_suffix); + assert_eq!(path.len(), 0); + for module in super_mod.split("::") { + path.push(syn::PathSegment { ident: syn::Ident::new(module, Span::call_site()), arguments: syn::PathArguments::None }); + } + } else if partial_path == "" && !dependencies.contains(&$ident) { + new_path = format!("{}::{}{}", crate_name, $ident, $path_suffix); + let crate_name_ident = format_ident!("{}", crate_name); + path.push(parse_quote!(#crate_name_ident)); + } else { + new_path = format!("{}{}{}", partial_path, $ident, $path_suffix); + } + let ident = &$ident; + path.push(parse_quote!(#ident)); + } + } match u { syn::UseTree::Path(p) => { - let new_path = format!("{}{}::", partial_path, p.ident); - path.push(syn::PathSegment { ident: p.ident.clone(), arguments: syn::PathArguments::None }); - Self::process_use_intern(imports, &p.tree, &new_path, path); + push_path!(p.ident, "::"); + Self::process_use_intern(crate_name, module_path, dependencies, imports, &p.tree, &new_path, path); }, syn::UseTree::Name(n) => { - let full_path = format!("{}{}", partial_path, n.ident); - path.push(syn::PathSegment { ident: n.ident.clone(), arguments: syn::PathArguments::None }); - imports.insert(n.ident.clone(), (full_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path })); + push_path!(n.ident, ""); + imports.insert(n.ident.clone(), (new_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path })); }, syn::UseTree::Group(g) => { for i in g.items.iter() { - Self::process_use_intern(imports, i, partial_path, path.clone()); + Self::process_use_intern(crate_name, module_path, dependencies, imports, i, partial_path, path.clone()); } }, syn::UseTree::Rename(r) => { - let full_path = format!("{}{}", partial_path, r.ident); - path.push(syn::PathSegment { ident: r.ident.clone(), arguments: syn::PathArguments::None }); - imports.insert(r.rename.clone(), (full_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path })); + push_path!(r.ident, ""); + imports.insert(r.rename.clone(), (new_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path })); }, syn::UseTree::Glob(_) => { eprintln!("Ignoring * use for {} - this may result in resolution failures", partial_path); @@ -355,24 +459,26 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr } } - fn process_use(imports: &mut HashMap, u: &syn::ItemUse) { + fn process_use(crate_name: &str, module_path: &str, dependencies: &HashSet, imports: &mut HashMap, u: &syn::ItemUse) { if let syn::Visibility::Public(_) = u.vis { // We actually only use these for #[cfg(fuzztarget)] eprintln!("Ignoring pub(use) tree!"); return; } if u.leading_colon.is_some() { eprintln!("Ignoring leading-colon use!"); return; } - Self::process_use_intern(imports, &u.tree, "", syn::punctuated::Punctuated::new()); + Self::process_use_intern(crate_name, module_path, dependencies, imports, &u.tree, "", syn::punctuated::Punctuated::new()); } fn insert_primitive(imports: &mut HashMap, id: &str) { - let ident = syn::Ident::new(id, Span::call_site()); - let mut path = syn::punctuated::Punctuated::new(); - path.push(syn::PathSegment { ident: ident.clone(), arguments: syn::PathArguments::None }); - imports.insert(ident, (id.to_owned(), syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path })); + let ident = format_ident!("{}", id); + let path = parse_quote!(#ident); + imports.insert(ident, (id.to_owned(), path)); } - pub fn new(module_path: &'mod_lifetime str, contents: &'crate_lft [syn::Item]) -> Self { + pub fn new(crate_name: &'mod_lifetime str, dependencies: &'mod_lifetime HashSet, module_path: &'mod_lifetime str, contents: &'crate_lft [syn::Item]) -> Self { + Self::from_borrowed_items(crate_name, dependencies, module_path, &contents.iter().map(|a| a).collect::>()) + } + pub fn from_borrowed_items(crate_name: &'mod_lifetime str, dependencies: &'mod_lifetime HashSet, module_path: &'mod_lifetime str, contents: &[&'crate_lft syn::Item]) -> Self { let mut imports = HashMap::new(); // Add primitives to the "imports" list: Self::insert_primitive(&mut imports, "bool"); @@ -395,13 +501,14 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr for item in contents.iter() { match item { - syn::Item::Use(u) => Self::process_use(&mut imports, &u), + syn::Item::Use(u) => Self::process_use(crate_name, module_path, dependencies, &mut imports, &u), syn::Item::Struct(s) => { if let syn::Visibility::Public(_) = s.vis { match export_status(&s.attrs) { ExportStatus::Export => { declared.insert(s.ident.clone(), DeclType::StructImported); }, ExportStatus::NoExport => { declared.insert(s.ident.clone(), DeclType::StructIgnored); }, ExportStatus::TestOnly => continue, + ExportStatus::NotImplementable => panic!("(C-not implementable) should only appear on traits!"), } } }, @@ -422,13 +529,19 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr match export_status(&e.attrs) { ExportStatus::Export if is_enum_opaque(e) => { declared.insert(e.ident.clone(), DeclType::EnumIgnored); }, ExportStatus::Export => { declared.insert(e.ident.clone(), DeclType::MirroredEnum); }, + ExportStatus::NotImplementable => panic!("(C-not implementable) should only appear on traits!"), _ => continue, } } }, - syn::Item::Trait(t) if export_status(&t.attrs) == ExportStatus::Export => { - if let syn::Visibility::Public(_) = t.vis { - declared.insert(t.ident.clone(), DeclType::Trait(t)); + syn::Item::Trait(t) => { + match export_status(&t.attrs) { + ExportStatus::Export|ExportStatus::NotImplementable => { + if let syn::Visibility::Public(_) = t.vis { + declared.insert(t.ident.clone(), DeclType::Trait(t)); + } + }, + _ => continue, } }, syn::Item::Mod(m) => { @@ -438,7 +551,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr } } - Self { module_path, imports, declared, priv_modules } + Self { crate_name, dependencies, module_path, imports, declared, priv_modules } } pub fn get_declared_type(&self, ident: &syn::Ident) -> Option<&DeclType<'crate_lft>> { @@ -476,9 +589,14 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr } else { p_arg }; if p.leading_colon.is_some() { - Some(p.segments.iter().enumerate().map(|(idx, seg)| { + let mut res: String = p.segments.iter().enumerate().map(|(idx, seg)| { format!("{}{}", if idx == 0 { "" } else { "::" }, seg.ident) - }).collect()) + }).collect(); + let firstseg = p.segments.iter().next().unwrap(); + if !self.dependencies.contains(&firstseg.ident) { + res = self.crate_name.to_owned() + "::" + &res; + } + Some(res) } else if let Some(id) = p.get_ident() { self.maybe_resolve_ident(id) } else { @@ -491,6 +609,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr let remaining: String = seg_iter.map(|seg| { format!("::{}", seg.ident) }).collect(); + let first_seg_str = format!("{}", first_seg.ident); if let Some((imp, _)) = self.imports.get(&first_seg.ident) { if remaining != "" { Some(imp.clone() + &remaining) @@ -499,6 +618,8 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr } } else if let Some(_) = self.priv_modules.get(&first_seg.ident) { Some(format!("{}::{}{}", self.module_path, first_seg.ident, remaining)) + } else if first_seg_str == "std" || first_seg_str == "core" || self.dependencies.contains(&first_seg.ident) { + Some(first_seg_str + &remaining) } else { None } } } @@ -507,11 +628,19 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr pub fn resolve_imported_refs(&self, mut ty: syn::Type) -> syn::Type { match &mut ty { syn::Type::Path(p) => { - if let Some(ident) = p.path.get_ident() { - if let Some((_, newpath)) = self.imports.get(ident) { - p.path = newpath.clone(); + if p.path.segments.len() != 1 { unimplemented!(); } + let mut args = p.path.segments[0].arguments.clone(); + if let syn::PathArguments::AngleBracketed(ref mut generics) = &mut args { + for arg in generics.args.iter_mut() { + if let syn::GenericArgument::Type(ref mut t) = arg { + *t = self.resolve_imported_refs(t.clone()); + } } - } else { unimplemented!(); } + } + if let Some((_, newpath)) = self.imports.get(single_ident_generic_path_to_ident(&p.path).unwrap()) { + p.path = newpath.clone(); + } + p.path.segments[0].arguments = args; }, syn::Type::Reference(r) => { r.elem = Box::new(self.resolve_imported_refs((*r.elem).clone())); @@ -546,6 +675,7 @@ pub struct ASTModule { /// A struct containing the syn::File AST for each file in the crate. pub struct FullLibraryAST { pub modules: HashMap, + pub dependencies: HashSet, } impl FullLibraryAST { fn load_module(&mut self, module: String, attrs: Vec, mut items: Vec) { @@ -570,6 +700,11 @@ impl FullLibraryAST { } }, syn::Item::Mod(_) => panic!("--pretty=expanded output should never have non-body modules"), + syn::Item::ExternCrate(c) => { + if export_status(&c.attrs) == ExportStatus::Export { + self.dependencies.insert(c.ident); + } + }, _ => { non_mod_items.push(item); } } } @@ -578,12 +713,27 @@ impl FullLibraryAST { pub fn load_lib(lib: syn::File) -> Self { assert_eq!(export_status(&lib.attrs), ExportStatus::Export); - let mut res = Self { modules: HashMap::default() }; + let mut res = Self { modules: HashMap::default(), dependencies: HashSet::new() }; res.load_module("".to_owned(), lib.attrs, lib.items); res } } +/// List of manually-generated types which are clonable +fn initial_clonable_types() -> HashSet { + let mut res = HashSet::new(); + res.insert("crate::c_types::u5".to_owned()); + res.insert("crate::c_types::ThirtyTwoBytes".to_owned()); + res.insert("crate::c_types::PublicKey".to_owned()); + res.insert("crate::c_types::Transaction".to_owned()); + res.insert("crate::c_types::TxOut".to_owned()); + res.insert("crate::c_types::Signature".to_owned()); + res.insert("crate::c_types::RecoverableSignature".to_owned()); + res.insert("crate::c_types::Secp256k1Error".to_owned()); + res.insert("crate::c_types::IOError".to_owned()); + res +} + /// Top-level struct tracking everything which has been defined while walking the crate. pub struct CrateTypes<'a> { /// This may contain structs or enums, but only when either is mapped as @@ -619,7 +769,7 @@ impl<'a> CrateTypes<'a> { opaques: HashMap::new(), mirrored_enums: HashMap::new(), traits: HashMap::new(), type_aliases: HashMap::new(), reverse_alias_map: HashMap::new(), templates_defined: RefCell::new(HashMap::default()), - clonable_types: RefCell::new(HashSet::new()), trait_impls: HashMap::new(), + clonable_types: RefCell::new(initial_clonable_types()), trait_impls: HashMap::new(), template_file: RefCell::new(template_file), lib_ast: &libast, } } @@ -638,7 +788,6 @@ impl<'a> CrateTypes<'a> { /// A struct which tracks resolving rust types into C-mapped equivalents, exists for one specific /// module but contains a reference to the overall CrateTypes tracking. pub struct TypeResolver<'mod_lifetime, 'crate_lft: 'mod_lifetime> { - pub orig_crate: &'mod_lifetime str, pub module_path: &'mod_lifetime str, pub crate_types: &'mod_lifetime CrateTypes<'crate_lft>, types: ImportResolver<'mod_lifetime, 'crate_lft>, @@ -670,8 +819,8 @@ enum ContainerPrefixLocation { } impl<'a, 'c: 'a> TypeResolver<'a, 'c> { - pub fn new(orig_crate: &'a str, module_path: &'a str, types: ImportResolver<'a, 'c>, crate_types: &'a CrateTypes<'c>) -> Self { - Self { orig_crate, module_path, types, crate_types } + pub fn new(module_path: &'a str, types: ImportResolver<'a, 'c>, crate_types: &'a CrateTypes<'c>) -> Self { + Self { module_path, types, crate_types } } // ************************************************* @@ -709,8 +858,6 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { if self.is_primitive(ty) { return true; } match ty { "()" => true, - "crate::c_types::Signature" => true, - "crate::c_types::TxOut" => true, _ => false, } } @@ -729,25 +876,34 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // for arrays are different (https://github.com/eqrion/cbindgen/issues/528) "[u8; 32]" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), + "[u8; 20]" if !is_ref => Some("crate::c_types::TwentyBytes"), "[u8; 16]" if !is_ref => Some("crate::c_types::SixteenBytes"), "[u8; 10]" if !is_ref => Some("crate::c_types::TenBytes"), "[u8; 4]" if !is_ref => Some("crate::c_types::FourBytes"), "[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"), - "bitcoin::secp256k1::key::PublicKey" => Some("crate::c_types::PublicKey"), + "bech32::u5" => Some("crate::c_types::u5"), + + "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::key::SecretKey" if is_ref => Some("*const [u8; 32]"), - "bitcoin::secp256k1::key::SecretKey" if !is_ref => Some("crate::c_types::SecretKey"), - "bitcoin::secp256k1::Error" if !is_ref => Some("crate::c_types::Secp256k1Error"), + "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" + if !is_ref => Some("crate::c_types::SecretKey"), + "bitcoin::secp256k1::Error"|"secp256k1::Error" + if !is_ref => Some("crate::c_types::Secp256k1Error"), "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::chain::transaction::OutPoint"), + "bitcoin::blockdata::transaction::OutPoint" => Some("crate::lightning::chain::transaction::OutPoint"), "bitcoin::blockdata::transaction::Transaction" => Some("crate::c_types::Transaction"), "bitcoin::blockdata::transaction::TxOut" if !is_ref => Some("crate::c_types::TxOut"), "bitcoin::network::constants::Network" => Some("crate::bitcoin::network::Network"), @@ -755,20 +911,19 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::blockdata::block::Block" if is_ref => Some("crate::c_types::u8slice"), // Newtypes that we just expose in their original form. - "bitcoin::hash_types::Txid" if is_ref => Some("*const [u8; 32]"), - "bitcoin::hash_types::Txid" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), - "bitcoin::hash_types::BlockHash" if is_ref => Some("*const [u8; 32]"), - "bitcoin::hash_types::BlockHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), + "bitcoin::hash_types::Txid"|"bitcoin::hash_types::BlockHash"|"bitcoin_hashes::sha256::Hash" + if is_ref => Some("*const [u8; 32]"), + "bitcoin::hash_types::Txid"|"bitcoin::hash_types::BlockHash"|"bitcoin_hashes::sha256::Hash" + if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), "bitcoin::secp256k1::Message" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), - "ln::channelmanager::PaymentHash" if is_ref => Some("*const [u8; 32]"), - "ln::channelmanager::PaymentHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), - "ln::channelmanager::PaymentPreimage" if is_ref => Some("*const [u8; 32]"), - "ln::channelmanager::PaymentPreimage" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), - "ln::channelmanager::PaymentSecret" if is_ref => Some("crate::c_types::ThirtyTwoBytes"), - "ln::channelmanager::PaymentSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), + "lightning::ln::PaymentHash" if is_ref => Some("*const [u8; 32]"), + "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" => Some("crate::c_types::ThirtyTwoBytes"), // Override the default since Records contain an fmt with a lifetime: - "util::logger::Record" => Some("*const std::os::raw::c_char"), + "lightning::util::logger::Record" => Some("*const std::os::raw::c_char"), _ => None, } @@ -789,6 +944,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "[u8; 32]" if is_ref => Some("unsafe { &*"), "[u8; 32]" if !is_ref => Some(""), + "[u8; 20]" if !is_ref => Some(""), "[u8; 16]" if !is_ref => Some(""), "[u8; 10]" if !is_ref => Some(""), "[u8; 4]" if !is_ref => Some(""), @@ -798,18 +954,27 @@ 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(""), + "std::io::Error" if !is_ref => 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(""), - "bitcoin::secp256k1::key::PublicKey" if is_ref => Some("&"), - "bitcoin::secp256k1::key::PublicKey" => Some(""), + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" + if is_ref => Some("&"), + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" + => Some(""), "bitcoin::secp256k1::Signature" if is_ref => Some("&"), "bitcoin::secp256k1::Signature" => Some(""), - "bitcoin::secp256k1::key::SecretKey" if is_ref => Some("&::bitcoin::secp256k1::key::SecretKey::from_slice(&unsafe { *"), - "bitcoin::secp256k1::key::SecretKey" if !is_ref => 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" + if !is_ref => Some(""), "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" if is_ref => Some("&"), @@ -823,11 +988,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::hash_types::Txid" if is_ref => Some("&::bitcoin::hash_types::Txid::from_slice(&unsafe { &*"), "bitcoin::hash_types::Txid" if !is_ref => Some("::bitcoin::hash_types::Txid::from_slice(&"), "bitcoin::hash_types::BlockHash" => Some("::bitcoin::hash_types::BlockHash::from_slice(&"), - "ln::channelmanager::PaymentHash" if !is_ref => Some("::lightning::ln::channelmanager::PaymentHash("), - "ln::channelmanager::PaymentHash" if is_ref => Some("&::lightning::ln::channelmanager::PaymentHash(unsafe { *"), - "ln::channelmanager::PaymentPreimage" if !is_ref => Some("::lightning::ln::channelmanager::PaymentPreimage("), - "ln::channelmanager::PaymentPreimage" if is_ref => Some("&::lightning::ln::channelmanager::PaymentPreimage(unsafe { *"), - "ln::channelmanager::PaymentSecret" => Some("::lightning::ln::channelmanager::PaymentSecret("), + "lightning::ln::PaymentHash" if !is_ref => Some("::lightning::ln::PaymentHash("), + "lightning::ln::PaymentHash" if is_ref => Some("&::lightning::ln::PaymentHash(unsafe { *"), + "lightning::ln::PaymentPreimage" if !is_ref => Some("::lightning::ln::PaymentPreimage("), + "lightning::ln::PaymentPreimage" if is_ref => Some("&::lightning::ln::PaymentPreimage(unsafe { *"), + "lightning::ln::PaymentSecret" => Some("::lightning::ln::PaymentSecret("), // List of traits we map (possibly during processing of other files): "crate::util::logger::Logger" => Some(""), @@ -846,6 +1011,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "[u8; 32]" if is_ref => Some("}"), "[u8; 32]" if !is_ref => Some(".data"), + "[u8; 20]" if !is_ref => Some(".data"), "[u8; 16]" if !is_ref => Some(".data"), "[u8; 10]" if !is_ref => Some(".data"), "[u8; 4]" if !is_ref => Some(".data"), @@ -854,15 +1020,23 @@ 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::io::Error" if !is_ref => Some(".to_rust()"), + + "std::time::Duration"|"core::time::Duration" => Some(")"), + "std::time::SystemTime" => Some("))"), - "std::time::Duration" => Some(")"), + "bech32::u5" => Some(".into()"), - "bitcoin::secp256k1::key::PublicKey" => Some(".into_rust()"), + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" + => Some(".into_rust()"), "bitcoin::secp256k1::Signature" => Some(".into_rust()"), - "bitcoin::secp256k1::key::SecretKey" if !is_ref => Some(".into_rust()"), - "bitcoin::secp256k1::key::SecretKey" if is_ref => Some("}[..]).unwrap()"), + "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" + if is_ref => Some("}[..]).unwrap()"), "bitcoin::blockdata::script::Script" if is_ref => Some(".to_slice()))"), "bitcoin::blockdata::script::Script" if !is_ref => Some(".into_rust())"), "bitcoin::blockdata::transaction::Transaction" => Some(".into_bitcoin()"), @@ -875,11 +1049,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::hash_types::Txid" if is_ref => Some(" }[..]).unwrap()"), "bitcoin::hash_types::Txid" => Some(".data[..]).unwrap()"), "bitcoin::hash_types::BlockHash" if !is_ref => Some(".data[..]).unwrap()"), - "ln::channelmanager::PaymentHash" if !is_ref => Some(".data)"), - "ln::channelmanager::PaymentHash" if is_ref => Some(" })"), - "ln::channelmanager::PaymentPreimage" if !is_ref => Some(".data)"), - "ln::channelmanager::PaymentPreimage" if is_ref => Some(" })"), - "ln::channelmanager::PaymentSecret" => Some(".data)"), + "lightning::ln::PaymentHash" if !is_ref => Some(".data)"), + "lightning::ln::PaymentHash" if is_ref => Some(" })"), + "lightning::ln::PaymentPreimage" if !is_ref => Some(".data)"), + "lightning::ln::PaymentPreimage" if is_ref => Some(" })"), + "lightning::ln::PaymentSecret" => Some(".data)"), // List of traits we map (possibly during processing of other files): "crate::util::logger::Logger" => Some(""), @@ -896,15 +1070,13 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "[u8]" if is_ref => Some(("crate::c_types::u8slice::from_slice(", ")")), "[usize]" if is_ref => Some(("crate::c_types::usizeslice::from_slice(", ")")), - "bitcoin::blockdata::transaction::Transaction" if is_ref => Some(("::bitcoin::consensus::encode::serialize(", ")")), - "bitcoin::blockdata::transaction::Transaction" if !is_ref => Some(("::bitcoin::consensus::encode::serialize(&", ")")), "bitcoin::blockdata::block::BlockHeader" if is_ref => Some(("{ let mut s = [0u8; 80]; s[..].copy_from_slice(&::bitcoin::consensus::encode::serialize(", ")); s }")), "bitcoin::blockdata::block::Block" if is_ref => Some(("::bitcoin::consensus::encode::serialize(", ")")), "bitcoin::hash_types::Txid" => None, // Override the default since Records contain an fmt with a lifetime: // TODO: We should include the other record fields - "util::logger::Record" => Some(("std::ffi::CString::new(format!(\"{}\", ", ".args)).unwrap()")), + "lightning::util::logger::Record" => Some(("std::ffi::CString::new(format!(\"{}\", ", ".args)).unwrap()")), _ => None, }.map(|s| s.to_owned()) } @@ -918,28 +1090,39 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "Option" => Some("local_"), "[u8; 32]" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), - "[u8; 32]" if is_ref => Some("&"), + "[u8; 32]" if is_ref => Some(""), + "[u8; 20]" if !is_ref => Some("crate::c_types::TwentyBytes { data: "), "[u8; 16]" if !is_ref => Some("crate::c_types::SixteenBytes { data: "), "[u8; 10]" if !is_ref => Some("crate::c_types::TenBytes { data: "), "[u8; 4]" if !is_ref => Some("crate::c_types::FourBytes { data: "), - "[u8; 3]" if is_ref => Some("&"), + "[u8; 3]" if is_ref => Some(""), "[u8]" if is_ref => Some("local_"), "[usize]" if is_ref => Some("local_"), "str" if is_ref => Some(""), - "String" => Some(""), + "alloc::string::String"|"String" => 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("), - "std::time::Duration" => Some(""), + "bech32::u5" => Some(""), - "bitcoin::secp256k1::key::PublicKey" => Some("crate::c_types::PublicKey::from_rust(&"), + "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::key::SecretKey" if is_ref => Some(""), - "bitcoin::secp256k1::key::SecretKey" if !is_ref => Some("crate::c_types::SecretKey::from_rust("), - "bitcoin::secp256k1::Error" if !is_ref => Some("crate::c_types::Secp256k1Error::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" + if !is_ref => Some("crate::c_types::SecretKey::from_rust("), + "bitcoin::secp256k1::Error"|"secp256k1::Error" + if !is_ref => Some("crate::c_types::Secp256k1Error::from_rust("), "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" => Some("crate::c_types::Transaction::from_vec(local_"), + "bitcoin::blockdata::transaction::Transaction" if is_ref => Some("crate::c_types::Transaction::from_bitcoin("), + "bitcoin::blockdata::transaction::Transaction" => Some("crate::c_types::Transaction::from_bitcoin(&"), "bitcoin::blockdata::transaction::OutPoint" => Some("crate::c_types::bitcoin_to_C_outpoint("), "bitcoin::blockdata::transaction::TxOut" if !is_ref => Some("crate::c_types::TxOut::from_rust("), "bitcoin::network::constants::Network" => Some("crate::bitcoin::network::Network::from_bitcoin("), @@ -949,18 +1132,19 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::hash_types::Txid" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), // Newtypes that we just expose in their original form. - "bitcoin::hash_types::Txid" if is_ref => Some(""), - "bitcoin::hash_types::BlockHash" if is_ref => Some(""), - "bitcoin::hash_types::BlockHash" => Some("crate::c_types::ThirtyTwoBytes { data: "), + "bitcoin::hash_types::Txid"|"bitcoin::hash_types::BlockHash"|"bitcoin_hashes::sha256::Hash" + if is_ref => Some(""), + "bitcoin::hash_types::Txid"|"bitcoin::hash_types::BlockHash"|"bitcoin_hashes::sha256::Hash" + if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), "bitcoin::secp256k1::Message" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), - "ln::channelmanager::PaymentHash" if is_ref => Some("&"), - "ln::channelmanager::PaymentHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), - "ln::channelmanager::PaymentPreimage" if is_ref => Some("&"), - "ln::channelmanager::PaymentPreimage" => Some("crate::c_types::ThirtyTwoBytes { data: "), - "ln::channelmanager::PaymentSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), + "lightning::ln::PaymentHash" if is_ref => Some("&"), + "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" => Some("crate::c_types::ThirtyTwoBytes { data: "), // Override the default since Records contain an fmt with a lifetime: - "util::logger::Record" => Some("local_"), + "lightning::util::logger::Record" => Some("local_"), _ => None, }.map(|s| s.to_owned()) @@ -976,6 +1160,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "[u8; 32]" if !is_ref => Some(" }"), "[u8; 32]" if is_ref => Some(""), + "[u8; 20]" if !is_ref => Some(" }"), "[u8; 16]" if !is_ref => Some(" }"), "[u8; 10]" if !is_ref => Some(" }"), "[u8; 4]" if !is_ref => Some(" }"), @@ -985,16 +1170,25 @@ 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(")"), - "bitcoin::secp256k1::key::PublicKey" => Some(")"), + "bech32::u5" => Some(".into()"), + + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" + => Some(")"), "bitcoin::secp256k1::Signature" => Some(")"), - "bitcoin::secp256k1::key::SecretKey" if !is_ref => Some(")"), - "bitcoin::secp256k1::key::SecretKey" if is_ref => Some(".as_ref()"), - "bitcoin::secp256k1::Error" if !is_ref => Some(")"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some(")"), + "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" + if !is_ref => Some(")"), + "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" + if is_ref => Some(".as_ref()"), + "bitcoin::secp256k1::Error"|"secp256k1::Error" + if !is_ref => Some(")"), "bitcoin::blockdata::script::Script" if is_ref => Some("[..])"), "bitcoin::blockdata::script::Script" if !is_ref => Some(".into_bytes().into()"), "bitcoin::blockdata::transaction::Transaction" => Some(")"), @@ -1007,18 +1201,19 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::hash_types::Txid" if !is_ref => Some(".into_inner() }"), // Newtypes that we just expose in their original form. - "bitcoin::hash_types::Txid" if is_ref => Some(".as_inner()"), - "bitcoin::hash_types::BlockHash" if is_ref => Some(".as_inner()"), - "bitcoin::hash_types::BlockHash" => Some(".into_inner() }"), + "bitcoin::hash_types::Txid"|"bitcoin::hash_types::BlockHash"|"bitcoin_hashes::sha256::Hash" + if is_ref => Some(".as_inner()"), + "bitcoin::hash_types::Txid"|"bitcoin::hash_types::BlockHash"|"bitcoin_hashes::sha256::Hash" + if !is_ref => Some(".into_inner() }"), "bitcoin::secp256k1::Message" if !is_ref => Some(".as_ref().clone() }"), - "ln::channelmanager::PaymentHash" if is_ref => Some(".0"), - "ln::channelmanager::PaymentHash" => Some(".0 }"), - "ln::channelmanager::PaymentPreimage" if is_ref => Some(".0"), - "ln::channelmanager::PaymentPreimage" => Some(".0 }"), - "ln::channelmanager::PaymentSecret" if !is_ref => Some(".0 }"), + "lightning::ln::PaymentHash" if is_ref => Some(".0"), + "lightning::ln::PaymentHash" => Some(".0 }"), + "lightning::ln::PaymentPreimage" if is_ref => Some(".0"), + "lightning::ln::PaymentPreimage" => Some(".0 }"), + "lightning::ln::PaymentSecret" => Some(".0 }"), // Override the default since Records contain an fmt with a lifetime: - "util::logger::Record" => Some(".as_ptr()"), + "lightning::util::logger::Record" => Some(".as_ptr()"), _ => None, }.map(|s| s.to_owned()) @@ -1026,8 +1221,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { fn empty_val_check_suffix_from_path(&self, full_path: &str) -> Option<&str> { match full_path { - "ln::channelmanager::PaymentSecret" => Some(".data == [0; 32]"), - "bitcoin::secp256k1::key::PublicKey" => Some(".is_null()"), + "lightning::ln::PaymentSecret" => Some(".data == [0; 32]"), + "secp256k1::key::PublicKey"|"bitcoin::secp256k1::key::PublicKey" => Some(".is_null()"), "bitcoin::secp256k1::Signature" => Some(".is_null()"), _ => None } @@ -1068,7 +1263,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } /// Returns true if the path is a "transparent" container, ie an Option or a container which does /// not require a generated continer class. - fn is_path_transparent_container(&self, full_path: &syn::Path, generics: Option<&GenericTypes>, is_ref: bool) -> bool { + pub fn is_path_transparent_container(&self, full_path: &syn::Path, generics: Option<&GenericTypes>, is_ref: bool) -> bool { let inner_iter = match &full_path.segments.last().unwrap().arguments { syn::PathArguments::None => return false, syn::PathArguments::AngleBracketed(args) => args.args.iter().map(|arg| { @@ -1095,24 +1290,36 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { (").into(), Err(mut e) => crate::c_types::CResultTempl::err(".to_string(), "e".to_string())], ").into() }", ContainerPrefixLocation::PerConv)) }, - "Vec" if !is_ref => { + "Vec" => { + if is_ref { + // We should only get here if the single contained has an inner + assert!(self.c_type_has_inner(single_contained.unwrap())); + } Some(("Vec::new(); for mut item in ", vec![(format!(".drain(..) {{ local_{}.push(", var_name), "item".to_string())], "); }", ContainerPrefixLocation::PerConv)) }, "Slice" => { - Some(("Vec::new(); for item in ", vec![(format!(".iter() {{ local_{}.push(", var_name), "**item".to_string())], "); }", ContainerPrefixLocation::PerConv)) + 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![ @@ -1211,9 +1418,22 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { self.types.get_declared_type(ident) } /// Returns true if the object at the given path is mapped as X { inner: *mut origX, .. }. - pub fn c_type_has_inner_from_path(&self, full_path: &str) -> bool{ + 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) + }, + syn::Type::Reference(r) => { + self.c_type_has_inner(&*r.elem) + }, + _ => false, + } + } pub fn maybe_resolve_ident(&self, id: &syn::Ident) -> Option { self.types.maybe_resolve_ident(id) @@ -1255,7 +1475,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // If we're printing a generic argument, it needs to reference the crate, otherwise // the original crate: } else if self.maybe_resolve_path(&path, None).as_ref() == Some(&resolved) { - write!(w, "{}::{}", self.orig_crate, resolved).unwrap(); + write!(w, "{}", resolved).unwrap(); } else { write!(w, "crate::{}", resolved).unwrap(); } @@ -1363,6 +1583,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() { @@ -1398,16 +1621,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { split.next().unwrap(); let tail_str = split.next().unwrap(); assert!(split.next().is_none()); - let len = &tail_str[..tail_str.len() - 1]; - Some(syn::Type::Array(syn::TypeArray { - bracket_token: syn::token::Bracket { span: Span::call_site() }, - elem: Box::new(syn::Type::Path(syn::TypePath { - qself: None, - path: syn::Path::from(syn::PathSegment::from(syn::Ident::new("u8", Span::call_site()))), - })), - semi_token: syn::Token!(;)(Span::call_site()), - len: syn::Expr::Lit(syn::ExprLit { attrs: Vec::new(), lit: syn::Lit::Int(syn::LitInt::new(len, Span::call_site())) }), - })) + let len = usize::from_str_radix(&tail_str[..tail_str.len() - 1], 10).unwrap(); + Some(parse_quote!([u8; #len])) } else { None } } else { None } } @@ -1416,6 +1631,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) { @@ -1457,6 +1675,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); @@ -1514,10 +1735,10 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } fn write_conversion_inline_intern Option, DL: Fn(&mut W, &DeclType, &str, bool, bool), SC: Fn(bool) -> &'static str> + 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); @@ -1530,6 +1751,10 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { let resolved_path = self.resolve_path(&p.path, generics); if let Some(aliased_type) = self.crate_types.type_aliases.get(&resolved_path) { return self.write_conversion_inline_intern(w, aliased_type, None, is_ref, is_mut, ptr_for_ref, tupleconv, prefix, sliceconv, path_lookup, decl_lookup); + } else if self.is_primitive(&resolved_path) { + if is_ref && prefix { + write!(w, "*").unwrap(); + } } else if let Some(c_type) = path_lookup(&resolved_path, is_ref, ptr_for_ref) { write!(w, "{}", c_type).unwrap(); } else if self.crate_types.opaques.get(&resolved_path).is_some() { @@ -1562,12 +1787,12 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { write!(w, "{}", path_lookup("[u8]", is_ref, ptr_for_ref).unwrap()).unwrap(); } 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)))).unwrap(); + write!(w, "{}", sliceconv(self.c_type_has_inner_from_path(&self.resolve_path(&p.path, generics)), None)).unwrap(); } else { unimplemented!(); } } else if let syn::Type::Tuple(t) = &*s.elem { assert!(!t.elems.is_empty()); if prefix { - write!(w, "&local_").unwrap(); + write!(w, "{}", sliceconv(false, None)).unwrap(); } else { let mut needs_map = false; for e in t.elems.iter() { @@ -1576,19 +1801,23 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } } if needs_map { - write!(w, ".iter().map(|(").unwrap(); + let mut map_str = Vec::new(); + write!(&mut map_str, ".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!(&mut map_str, "{}{}", if i != 0 { ", " } else { "" }, ('a' as u8 + i as u8) as char).unwrap(); } - write!(w, ")| (").unwrap(); + write!(&mut map_str, ")| (").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(); + write!(&mut map_str, "{}{}", 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(); + write!(&mut map_str, "{}*{}", if idx != 0 { ", " } else { "" }, (idx as u8 + 'a' as u8) as char).unwrap(); } else { unimplemented!(); } } - write!(w, ")).collect::>()[..]").unwrap(); + write!(&mut map_str, "))").unwrap(); + write!(w, "{}", sliceconv(false, Some(&String::from_utf8(map_str).unwrap()))).unwrap(); + } else { + write!(w, "{}", sliceconv(false, None)).unwrap(); } } } else { unimplemented!(); } @@ -1607,24 +1836,24 @@ 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_", + 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 { - DeclType::MirroredEnum if is_ref && ptr_for_ref => write!(w, "crate::{}::from_native(&", decl_path).unwrap(), - DeclType::MirroredEnum if is_ref => write!(w, "&crate::{}::from_native(&", decl_path).unwrap(), + DeclType::MirroredEnum if is_ref && ptr_for_ref => write!(w, "crate::{}::from_native(", decl_path).unwrap(), + DeclType::MirroredEnum if is_ref => write!(w, "&crate::{}::from_native(", decl_path).unwrap(), DeclType::MirroredEnum => write!(w, "crate::{}::native_into(", decl_path).unwrap(), DeclType::EnumIgnored|DeclType::StructImported if is_ref && ptr_for_ref && from_ptr => write!(w, "crate::{} {{ inner: unsafe {{ (", decl_path).unwrap(), DeclType::EnumIgnored|DeclType::StructImported if is_ref && ptr_for_ref => - write!(w, "crate::{} {{ inner: unsafe {{ ( (&(", decl_path).unwrap(), + write!(w, "crate::{} {{ inner: unsafe {{ ( (&(*", decl_path).unwrap(), DeclType::EnumIgnored|DeclType::StructImported if is_ref => write!(w, "&crate::{} {{ inner: unsafe {{ (", decl_path).unwrap(), DeclType::EnumIgnored|DeclType::StructImported if !is_ref && from_ptr => write!(w, "crate::{} {{ inner: ", decl_path).unwrap(), DeclType::EnumIgnored|DeclType::StructImported if !is_ref => write!(w, "crate::{} {{ inner: Box::into_raw(Box::new(", decl_path).unwrap(), - DeclType::Trait(_) if is_ref => write!(w, "&").unwrap(), + DeclType::Trait(_) if is_ref => write!(w, "").unwrap(), DeclType::Trait(_) if !is_ref => {}, _ => panic!("{:?}", decl_path), } @@ -1634,7 +1863,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { self.write_to_c_conversion_inline_prefix_inner(w, t, generics, false, ptr_for_ref, false); } fn write_to_c_conversion_inline_suffix_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, "*/", false, |_| ".into()", + self.write_conversion_inline_intern(w, t, generics, is_ref, false, ptr_for_ref, "*/", false, |_, _| ".into()".to_owned(), |a, b, c| self.to_c_conversion_inline_suffix_from_path(a, b, c), |w, decl_type, _full_path, is_ref, _is_mut| match decl_type { DeclType::MirroredEnum => write!(w, ")").unwrap(), @@ -1663,7 +1892,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } fn write_from_c_conversion_prefix_inner(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, ptr_for_ref: bool) { - self.write_conversion_inline_intern(w, t, generics, is_ref, false, false, "() /*", true, |_| "&local_", + self.write_conversion_inline_intern(w, t, generics, is_ref, false, false, "() /*", true, |_, _| "&local_".to_owned(), |a, b, _c| self.from_c_conversion_prefix_from_path(a, b), |w, decl_type, _full_path, is_ref, is_mut| match decl_type { DeclType::StructImported if is_ref && ptr_for_ref => write!(w, "unsafe {{ &*(*").unwrap(), @@ -1681,9 +1910,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } fn write_from_c_conversion_suffix_inner(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, ptr_for_ref: bool) { self.write_conversion_inline_intern(w, t, generics, is_ref, false, false, "*/", false, - |has_inner| match has_inner { - false => ".iter().collect::>()[..]", - true => "[..]", + |has_inner, map_str_opt| match (has_inner, map_str_opt) { + (false, Some(map_str)) => format!(".iter(){}.collect::>()[..]", map_str), + (false, None) => ".iter().collect::>()[..]".to_owned(), + (true, None) => "[..]".to_owned(), + (true, Some(_)) => unreachable!(), }, |a, b, _c| self.from_c_conversion_suffix_from_path(a, b), |w, decl_type, _full_path, is_ref, _is_mut| match decl_type { @@ -1702,7 +1933,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // Note that compared to the above conversion functions, the following two are generally // significantly undertested: pub fn write_from_c_conversion_to_ref_prefix(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>) { - self.write_conversion_inline_intern(w, t, generics, false, false, false, "() /*", true, |_| "&local_", + self.write_conversion_inline_intern(w, t, generics, false, false, false, "() /*", true, |_, _| "&local_".to_owned(), |a, b, _c| { if let Some(conv) = self.from_c_conversion_prefix_from_path(a, b) { Some(format!("&{}", conv)) @@ -1715,9 +1946,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } pub fn write_from_c_conversion_to_ref_suffix(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>) { self.write_conversion_inline_intern(w, t, generics, false, false, false, "*/", false, - |has_inner| match has_inner { - false => ".iter().collect::>()[..]", - true => "[..]", + |has_inner, map_str_opt| match (has_inner, map_str_opt) { + (false, Some(map_str)) => format!(".iter(){}.collect::>()[..]", map_str), + (false, None) => ".iter().collect::>()[..]".to_owned(), + (true, None) => "[..]".to_owned(), + (true, Some(_)) => unreachable!(), }, |a, b, _c| self.from_c_conversion_suffix_from_path(a, b), |w, decl_type, _full_path, is_ref, _is_mut| match decl_type { @@ -1762,13 +1995,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 { @@ -1779,7 +2014,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); } } @@ -1796,11 +2032,11 @@ 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); - let new_var = self.write_conversion_new_var_intern(w, &syn::Ident::new(&new_var_name, Span::call_site()), + let new_var = self.write_conversion_new_var_intern(w, &format_ident!("{}", new_var_name), &var_access, conv_ty, generics, contains_slice || (is_ref && ty_has_inner), ptr_for_ref, to_c, path_lookup, container_lookup, var_prefix, var_suffix); if new_var { write!(w, " ").unwrap(); } @@ -1835,7 +2071,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) @@ -1925,7 +2161,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { for (idx, elem) in t.elems.iter().enumerate() { if let syn::Type::Path(p) = elem { let v_name = format!("orig_{}_{}", ident, idx); - let tuple_elem_ident = syn::Ident::new(&v_name, Span::call_site()); + let tuple_elem_ident = format_ident!("{}", &v_name); if self.write_conversion_new_var_intern(w, &tuple_elem_ident, &v_name, elem, generics, false, ptr_for_ref, to_c, path_lookup, container_lookup, var_prefix, var_suffix) { @@ -2234,6 +2470,13 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } self.write_c_mangled_container_path_intern(w, args, generics, ident, is_ref, is_mut, ptr_for_ref, false) } + pub fn get_c_mangled_container_type(&self, args: Vec<&syn::Type>, generics: Option<&GenericTypes>, template_name: &str) -> Option { + let mut out = Vec::new(); + if !self.write_c_mangled_container_path(&mut out, args, generics, template_name, false, false, false) { + return None; + } + Some(String::from_utf8(out).unwrap()) + } // ********************************** // *** C Type Equivalent Printing *** @@ -2272,7 +2515,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; @@ -2339,15 +2582,10 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { self.check_create_container(mangled_container, "Vec", vec![&*r.elem], generics, false) } else { false } } else if let syn::Type::Tuple(_) = &*s.elem { - let mut args = syn::punctuated::Punctuated::new(); + let mut args = syn::punctuated::Punctuated::<_, syn::token::Comma>::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()), - }) - }); + 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) } else { false } },