X-Git-Url: http://git.bitcoin.ninja/index.cgi?p=ldk-c-bindings;a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Ftypes.rs;h=80ad2af4247c2657aec06b8dbf17d7a3075d71c6;hp=0b8e10d6ee02b7330573e6034edc8e3512ed3077;hb=99d22ba053fc347d8116572f20ef1431fc05dee9;hpb=ad7f77cab2212da7216591c7f3936cd6893dfff0 diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index 0b8e10d..80ad2af 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -6,6 +6,7 @@ // You may not use this file except in accordance with one or both of these // licenses. +use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::Write; @@ -82,12 +83,21 @@ pub fn export_status(attrs: &[syn::Attribute]) -> ExportStatus { if i == "any" { // #[cfg(any(test, feature = ""))] if let TokenTree::Group(g) = iter.next().unwrap() { - if let TokenTree::Ident(i) = g.stream().into_iter().next().unwrap() { - if i == "test" || i == "feature" { - // If its cfg(feature(...)) we assume its test-only - return ExportStatus::TestOnly; + let mut all_test = true; + for token in g.stream().into_iter() { + if let TokenTree::Ident(i) = token { + match format!("{}", i).as_str() { + "test" => {}, + "feature" => {}, + _ => all_test = false, + } + } else if let TokenTree::Literal(lit) = token { + if format!("{}", lit) != "fuzztarget" { + all_test = false; + } } } + if all_test { return ExportStatus::TestOnly; } } } else if i == "test" || i == "feature" { // If its cfg(feature(...)) we assume its test-only @@ -150,23 +160,21 @@ pub fn is_enum_opaque(e: &syn::ItemEnum) -> bool { /// It maps both direct types as well as Deref, mapping them via the provided /// TypeResolver's resolve_path function (ie traits map to the concrete jump table, structs to the /// concrete C container struct, etc). -pub struct GenericTypes<'a> { - typed_generics: Vec)>>, +#[must_use] +pub struct GenericTypes<'a, 'b> { + parent: Option<&'b GenericTypes<'b, 'b>>, + typed_generics: HashMap<&'a syn::Ident, (String, Option<&'a syn::Path>)>, } -impl<'a> GenericTypes<'a> { +impl<'a, 'p: 'a> GenericTypes<'a, 'p> { pub fn new() -> Self { - Self { typed_generics: vec![HashMap::new()], } + Self { parent: None, typed_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(&mut self) { - self.typed_generics.push(HashMap::new()); - } - /// pop the latest context off the stack. - pub fn pop_ctx(&mut self) { - self.typed_generics.pop(); + pub fn push_ctx<'c>(&'c self) -> GenericTypes<'a, 'c> { + GenericTypes { parent: Some(self), typed_generics: HashMap::new(), } } /// Learn the generics in generics in the current context, given a TypeResolver. @@ -186,13 +194,14 @@ impl<'a> GenericTypes<'a> { 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" { path = "crate::".to_string() + &path; Some(&trait_bound.path) } else { None }; - self.typed_generics.last_mut().unwrap().insert(&type_param.ident, (path, new_ident)); + self.typed_generics.insert(&type_param.ident, (path, new_ident)); } else { return false; } } } @@ -208,13 +217,16 @@ impl<'a> GenericTypes<'a> { if p.qself.is_some() { return false; } if p.path.leading_colon.is_some() { return false; } let mut p_iter = p.path.segments.iter(); - if let Some(gen) = self.typed_generics.last_mut().unwrap().get_mut(&p_iter.next().unwrap().ident) { + if let Some(gen) = self.typed_generics.get_mut(&p_iter.next().unwrap().ident) { if gen.0 != "std::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); @@ -227,7 +239,7 @@ impl<'a> GenericTypes<'a> { } } } - for (_, (_, ident)) in self.typed_generics.last().unwrap().iter() { + for (_, (_, ident)) in self.typed_generics.iter() { if ident.is_none() { return false; } } true @@ -253,7 +265,7 @@ impl<'a> GenericTypes<'a> { path = "crate::".to_string() + &path; Some(&tr.path) } else { None }; - self.typed_generics.last_mut().unwrap().insert(&t.ident, (path, new_ident)); + self.typed_generics.insert(&t.ident, (path, new_ident)); } else { unimplemented!(); } }, _ => unimplemented!(), @@ -267,21 +279,21 @@ impl<'a> GenericTypes<'a> { /// 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> { - for gen in self.typed_generics.iter().rev() { - if let Some(res) = gen.get(ident).map(|(a, _)| a) { - return Some(res); - } + if let Some(res) = self.typed_generics.get(ident).map(|(a, _)| a) { + return Some(res); + } + if let Some(parent) = self.parent { + parent.maybe_resolve_ident(ident) + } else { + None } - 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() { - for gen in self.typed_generics.iter().rev() { - if let Some(res) = gen.get(ident).map(|(a, b)| (a, b.unwrap())) { - return Some(res); - } + if let Some(res) = self.typed_generics.get(ident).map(|(a, b)| (a, b.unwrap())) { + return Some(res); } } else { // Associated types are usually specified as "Self::Generic", so we check for that @@ -289,14 +301,16 @@ impl<'a> GenericTypes<'a> { let mut it = path.segments.iter(); if path.segments.len() == 2 && format!("{}", it.next().unwrap().ident) == "Self" { let ident = &it.next().unwrap().ident; - for gen in self.typed_generics.iter().rev() { - if let Some(res) = gen.get(ident).map(|(a, b)| (a, b.unwrap())) { - return Some(res); - } + if let Some(res) = self.typed_generics.get(ident).map(|(a, b)| (a, b.unwrap())) { + return Some(res); } } } - None + if let Some(parent) = self.parent { + parent.maybe_resolve_path(path) + } else { + None + } } } @@ -311,33 +325,46 @@ 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, 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 == "" && !dependencies.contains(&$ident) { + new_path = format!("{}::{}{}", crate_name, $ident, $path_suffix); + path.push(syn::PathSegment { ident: syn::Ident::new(crate_name, Span::call_site()), arguments: syn::PathArguments::None }); + } else { + new_path = format!("{}{}{}", partial_path, $ident, $path_suffix); + } + path.push(syn::PathSegment { ident: $ident.clone(), arguments: syn::PathArguments::None }); + } + } 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, 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, 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); @@ -345,24 +372,24 @@ 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, 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, 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 })); + imports.insert(ident, (id.to_owned(), syn::Path { leading_colon: None, segments: 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 { let mut imports = HashMap::new(); // Add primitives to the "imports" list: Self::insert_primitive(&mut imports, "bool"); @@ -385,7 +412,7 @@ 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, dependencies, &mut imports, &u), syn::Item::Struct(s) => { if let syn::Visibility::Public(_) = s.vis { match export_status(&s.attrs) { @@ -403,10 +430,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr else { process_alias = false; } } if process_alias { - match &*t.ty { - syn::Type::Path(_) => { declared.insert(t.ident.clone(), DeclType::StructImported); }, - _ => {}, - } + declared.insert(t.ident.clone(), DeclType::StructImported); } } }, @@ -431,7 +455,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>> { @@ -469,9 +493,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 { @@ -484,7 +513,10 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr let remaining: String = seg_iter.map(|seg| { format!("::{}", seg.ident) }).collect(); - if let Some((imp, _)) = self.imports.get(&first_seg.ident) { + let first_seg_str = format!("{}", first_seg.ident); + if first_seg_str == "std" { + Some(first_seg_str + &remaining) + } else if let Some((imp, _)) = self.imports.get(&first_seg.ident) { if remaining != "" { Some(imp.clone() + &remaining) } else { @@ -500,11 +532,20 @@ 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(); +eprintln!("rir {:?}", p); + 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())); @@ -530,6 +571,59 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr #[allow(deprecated)] pub type NonRandomHash = hash::BuildHasherDefault; +/// A public module +pub struct ASTModule { + pub attrs: Vec, + pub items: Vec, + pub submods: Vec, +} +/// 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) { + let mut non_mod_items = Vec::with_capacity(items.len()); + let mut submods = Vec::with_capacity(items.len()); + for item in items.drain(..) { + match item { + syn::Item::Mod(m) if m.content.is_some() => { + if export_status(&m.attrs) == ExportStatus::Export { + if let syn::Visibility::Public(_) = m.vis { + let modident = format!("{}", m.ident); + let modname = if module != "" { + module.clone() + "::" + &modident + } else { + modident.clone() + }; + self.load_module(modname, m.attrs, m.content.unwrap().1); + submods.push(modident); + } else { + non_mod_items.push(syn::Item::Mod(m)); + } + } + }, + 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); } + } + } + self.modules.insert(module, ASTModule { attrs, items: non_mod_items, submods }); + } + + pub fn load_lib(lib: syn::File) -> Self { + assert_eq!(export_status(&lib.attrs), ExportStatus::Export); + let mut res = Self { modules: HashMap::default(), dependencies: HashSet::new() }; + res.load_module("".to_owned(), lib.attrs, lib.items); + 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 @@ -547,22 +641,45 @@ pub struct CrateTypes<'a> { /// exists. /// /// This is used at the end of processing to make C++ wrapper classes - pub templates_defined: HashMap, + pub templates_defined: RefCell>, /// The output file for any created template container types, written to as we find new /// template containers which need to be defined. - pub template_file: &'a mut File, + template_file: RefCell<&'a mut File>, /// Set of containers which are clonable - pub clonable_types: HashSet, + clonable_types: RefCell>, /// Key impls Value pub trait_impls: HashMap>, + /// The full set of modules in the crate(s) + pub lib_ast: &'a FullLibraryAST, +} + +impl<'a> CrateTypes<'a> { + pub fn new(template_file: &'a mut File, libast: &'a FullLibraryAST) -> Self { + CrateTypes { + 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(), + template_file: RefCell::new(template_file), lib_ast: &libast, + } + } + pub fn set_clonable(&self, object: String) { + self.clonable_types.borrow_mut().insert(object); + } + pub fn is_clonable(&self, object: &str) -> bool { + self.clonable_types.borrow().contains(object) + } + pub fn write_new_template(&self, mangled_container: String, has_destructor: bool, created_container: &[u8]) { + self.template_file.borrow_mut().write(created_container).unwrap(); + self.templates_defined.borrow_mut().insert(mangled_container, has_destructor); + } } /// 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 mut CrateTypes<'crate_lft>, + pub crate_types: &'mod_lifetime CrateTypes<'crate_lft>, types: ImportResolver<'mod_lifetime, 'crate_lft>, } @@ -592,8 +709,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 mut 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 } } // ************************************************* @@ -627,7 +744,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } } pub fn is_clonable(&self, ty: &str) -> bool { - if self.crate_types.clonable_types.contains(ty) { return true; } + if self.crate_types.is_clonable(ty) { return true; } if self.is_primitive(ty) { return true; } match ty { "()" => true, @@ -661,15 +778,19 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "String" if is_ref => Some("crate::c_types::Str"), "std::time::Duration" => Some("u64"), + "std::io::Error" => Some("crate::c_types::IOError"), - "bitcoin::secp256k1::key::PublicKey" => Some("crate::c_types::PublicKey"), + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::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::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" 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"), @@ -682,15 +803,15 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::hash_types::BlockHash" if is_ref => Some("*const [u8; 32]"), "bitcoin::hash_types::BlockHash" 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::channelmanager::PaymentHash" if is_ref => Some("*const [u8; 32]"), + "lightning::ln::channelmanager::PaymentHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), + "lightning::ln::channelmanager::PaymentPreimage" if is_ref => Some("*const [u8; 32]"), + "lightning::ln::channelmanager::PaymentPreimage" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), + "lightning::ln::channelmanager::PaymentSecret" if is_ref => Some("crate::c_types::ThirtyTwoBytes"), + "lightning::ln::channelmanager::PaymentSecret" if !is_ref => 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, } @@ -726,12 +847,16 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "std::time::Duration" => Some("std::time::Duration::from_secs("), - "bitcoin::secp256k1::key::PublicKey" if is_ref => Some("&"), - "bitcoin::secp256k1::key::PublicKey" => Some(""), + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey" + if is_ref => Some("&"), + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::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::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("&"), @@ -745,11 +870,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::channelmanager::PaymentHash" if !is_ref => Some("::lightning::ln::channelmanager::PaymentHash("), + "lightning::ln::channelmanager::PaymentHash" if is_ref => Some("&::lightning::ln::channelmanager::PaymentHash(unsafe { *"), + "lightning::ln::channelmanager::PaymentPreimage" if !is_ref => Some("::lightning::ln::channelmanager::PaymentPreimage("), + "lightning::ln::channelmanager::PaymentPreimage" if is_ref => Some("&::lightning::ln::channelmanager::PaymentPreimage(unsafe { *"), + "lightning::ln::channelmanager::PaymentSecret" => Some("::lightning::ln::channelmanager::PaymentSecret("), // List of traits we map (possibly during processing of other files): "crate::util::logger::Logger" => Some(""), @@ -781,10 +906,13 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "std::time::Duration" => Some(")"), - "bitcoin::secp256k1::key::PublicKey" => Some(".into_rust()"), + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::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::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()"), @@ -797,11 +925,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::channelmanager::PaymentHash" if !is_ref => Some(".data)"), + "lightning::ln::channelmanager::PaymentHash" if is_ref => Some(" })"), + "lightning::ln::channelmanager::PaymentPreimage" if !is_ref => Some(".data)"), + "lightning::ln::channelmanager::PaymentPreimage" if is_ref => Some(" })"), + "lightning::ln::channelmanager::PaymentSecret" => Some(".data)"), // List of traits we map (possibly during processing of other files): "crate::util::logger::Logger" => Some(""), @@ -826,7 +954,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // 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()) } @@ -853,11 +981,15 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "String" => Some(""), "std::time::Duration" => Some(""), + "std::io::Error" if !is_ref => Some("crate::c_types::IOError::from_rust("), - "bitcoin::secp256k1::key::PublicKey" => Some("crate::c_types::PublicKey::from_rust(&"), + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::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::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" 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(""), @@ -875,14 +1007,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::hash_types::BlockHash" if is_ref => Some(""), "bitcoin::hash_types::BlockHash" => 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::channelmanager::PaymentHash" if is_ref => Some("&"), + "lightning::ln::channelmanager::PaymentHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), + "lightning::ln::channelmanager::PaymentPreimage" if is_ref => Some("&"), + "lightning::ln::channelmanager::PaymentPreimage" => Some("crate::c_types::ThirtyTwoBytes { data: "), + "lightning::ln::channelmanager::PaymentSecret" if !is_ref => 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()) @@ -911,11 +1043,15 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "String" if is_ref => Some(".as_str().into()"), "std::time::Duration" => Some(".as_secs()"), + "std::io::Error" if !is_ref => Some(")"), - "bitcoin::secp256k1::key::PublicKey" => Some(")"), + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::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::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" if !is_ref => Some(")"), "bitcoin::blockdata::script::Script" if is_ref => Some("[..])"), "bitcoin::blockdata::script::Script" if !is_ref => Some(".into_bytes().into()"), @@ -933,14 +1069,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "bitcoin::hash_types::BlockHash" if is_ref => Some(".as_inner()"), "bitcoin::hash_types::BlockHash" => 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::channelmanager::PaymentHash" if is_ref => Some(".0"), + "lightning::ln::channelmanager::PaymentHash" => Some(".0 }"), + "lightning::ln::channelmanager::PaymentPreimage" if is_ref => Some(".0"), + "lightning::ln::channelmanager::PaymentPreimage" => Some(".0 }"), + "lightning::ln::channelmanager::PaymentSecret" if !is_ref => 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()) @@ -948,7 +1084,7 @@ 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]"), + "lightning::ln::channelmanager::PaymentSecret" => Some(".data == [0; 32]"), "bitcoin::secp256k1::key::PublicKey" => Some(".is_null()"), "bitcoin::secp256k1::Signature" => Some(".is_null()"), _ => None @@ -1177,7 +1313,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(); } @@ -1923,7 +2059,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // *** C Container Type Equivalent and alias Printing *** // ****************************************************** - fn write_template_generics<'b, W: std::io::Write>(&mut self, w: &mut W, args: &mut dyn Iterator, generics: Option<&GenericTypes>, is_ref: bool) -> bool { + fn write_template_generics<'b, W: std::io::Write>(&self, w: &mut W, args: &mut dyn Iterator, generics: Option<&GenericTypes>, is_ref: bool) -> bool { for (idx, t) in args.enumerate() { if idx != 0 { write!(w, ", ").unwrap(); @@ -1957,8 +2093,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } true } - fn check_create_container(&mut self, mangled_container: String, container_type: &str, args: Vec<&syn::Type>, generics: Option<&GenericTypes>, is_ref: bool) -> bool { - if !self.crate_types.templates_defined.get(&mangled_container).is_some() { + fn check_create_container(&self, mangled_container: String, container_type: &str, args: Vec<&syn::Type>, generics: Option<&GenericTypes>, is_ref: bool) -> bool { + if !self.crate_types.templates_defined.borrow().get(&mangled_container).is_some() { let mut created_container: Vec = Vec::new(); if container_type == "Result" { @@ -1989,7 +2125,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { let is_clonable = self.is_clonable(&ok_str) && self.is_clonable(&err_str); write_result_block(&mut created_container, &mangled_container, &ok_str, &err_str, is_clonable); if is_clonable { - self.crate_types.clonable_types.insert(Self::generated_container_path().to_owned() + "::" + &mangled_container); + self.crate_types.set_clonable(Self::generated_container_path().to_owned() + "::" + &mangled_container); } } else if container_type == "Vec" { let mut a_ty: Vec = Vec::new(); @@ -1998,7 +2134,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { let is_clonable = self.is_clonable(&ty); write_vec_block(&mut created_container, &mangled_container, &ty, is_clonable); if is_clonable { - self.crate_types.clonable_types.insert(Self::generated_container_path().to_owned() + "::" + &mangled_container); + self.crate_types.set_clonable(Self::generated_container_path().to_owned() + "::" + &mangled_container); } } else if container_type.ends_with("Tuple") { let mut tuple_args = Vec::new(); @@ -2014,7 +2150,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } write_tuple_block(&mut created_container, &mangled_container, &tuple_args, is_clonable); if is_clonable { - self.crate_types.clonable_types.insert(Self::generated_container_path().to_owned() + "::" + &mangled_container); + self.crate_types.set_clonable(Self::generated_container_path().to_owned() + "::" + &mangled_container); } } else if container_type == "Option" { let mut a_ty: Vec = Vec::new(); @@ -2023,14 +2159,12 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { let is_clonable = self.is_clonable(&ty); write_option_block(&mut created_container, &mangled_container, &ty, is_clonable); if is_clonable { - self.crate_types.clonable_types.insert(Self::generated_container_path().to_owned() + "::" + &mangled_container); + self.crate_types.set_clonable(Self::generated_container_path().to_owned() + "::" + &mangled_container); } } else { unreachable!(); } - self.crate_types.templates_defined.insert(mangled_container.clone(), true); - - self.crate_types.template_file.write(&created_container).unwrap(); + self.crate_types.write_new_template(mangled_container.clone(), true, &created_container); } true } @@ -2040,7 +2174,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } else { unimplemented!(); } } fn write_c_mangled_container_path_intern - (&mut self, w: &mut W, args: Vec<&syn::Type>, generics: Option<&GenericTypes>, ident: &str, is_ref: bool, is_mut: bool, ptr_for_ref: bool, in_type: bool) -> bool { + (&self, w: &mut W, args: Vec<&syn::Type>, generics: Option<&GenericTypes>, ident: &str, is_ref: bool, is_mut: bool, ptr_for_ref: bool, in_type: bool) -> bool { let mut mangled_type: Vec = Vec::new(); if !self.is_transparent_container(ident, is_ref, args.iter().map(|a| *a)) { write!(w, "C{}_", ident).unwrap(); @@ -2152,7 +2286,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // Make sure the type is actually defined: self.check_create_container(String::from_utf8(mangled_type).unwrap(), ident, args, generics, is_ref) } - fn write_c_mangled_container_path(&mut self, w: &mut W, args: Vec<&syn::Type>, generics: Option<&GenericTypes>, ident: &str, is_ref: bool, is_mut: bool, ptr_for_ref: bool) -> bool { + fn write_c_mangled_container_path(&self, w: &mut W, args: Vec<&syn::Type>, generics: Option<&GenericTypes>, ident: &str, is_ref: bool, is_mut: bool, ptr_for_ref: bool) -> bool { if !self.is_transparent_container(ident, is_ref, args.iter().map(|a| *a)) { write!(w, "{}::", Self::generated_container_path()).unwrap(); } @@ -2195,7 +2329,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { false } } - fn write_c_type_intern(&mut self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, is_mut: bool, ptr_for_ref: bool) -> bool { + 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 { syn::Type::Path(p) => { if p.qself.is_some() { @@ -2286,14 +2420,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { _ => false, } } - pub fn write_c_type(&mut self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, ptr_for_ref: bool) { + pub fn write_c_type(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, ptr_for_ref: bool) { assert!(self.write_c_type_intern(w, t, generics, false, false, ptr_for_ref)); } - pub fn understood_c_path(&mut self, p: &syn::Path) -> bool { + pub fn understood_c_path(&self, p: &syn::Path) -> bool { if p.leading_colon.is_some() { return false; } self.write_c_path_intern(&mut std::io::sink(), p, None, false, false, false) } - pub fn understood_c_type(&mut self, t: &syn::Type, generics: Option<&GenericTypes>) -> bool { + pub fn understood_c_type(&self, t: &syn::Type, generics: Option<&GenericTypes>) -> bool { self.write_c_type_intern(&mut std::io::sink(), t, generics, false, false, false) } }