X-Git-Url: http://git.bitcoin.ninja/index.cgi?p=ldk-c-bindings;a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Ftypes.rs;h=d945431199eab2ba51a9fffac3498f0bd3d5582c;hp=c8b71d6b71b93cd99a302db51496b2a247f0c9c5;hb=1926a7a71ae0f37ebd6562996769334e0af0cf1b;hpb=29298fd16d3c535cb9d3bfb64fb9854e50998901 diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index c8b71d6..d945431 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -164,19 +164,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, (&'a 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. @@ -207,6 +209,10 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { } else { return false; } } } + if let Some(default) = type_param.default.as_ref() { + assert!(type_param.bounds.is_empty()); + self.default_generics.insert(&type_param.ident, (default, parse_quote!(&#default))); + } }, _ => {}, } @@ -281,6 +287,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); } @@ -290,10 +301,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); } @@ -316,6 +333,34 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { } } +trait ResolveType<'a> { fn resolve_type(&'a self, ty: &'a syn::Type) -> &'a syn::Type; } +impl<'a, 'b, 'c: 'a + 'b> ResolveType<'c> for Option<&GenericTypes<'a, 'b>> { + fn resolve_type(&'c self, ty: &'c syn::Type) -> &'c syn::Type { + if let Some(us) = self { + match ty { + syn::Type::Path(p) => { + if let Some(ident) = p.path.get_ident() { + if let Some((ty, _)) = us.default_generics.get(ident) { + return ty; + } + } + }, + syn::Type::Reference(syn::TypeReference { elem, .. }) => { + if let syn::Type::Path(p) = &**elem { + if let Some(ident) = p.path.get_ident() { + if let Some((_, refty)) = us.default_generics.get(ident) { + return refty; + } + } + } + } + _ => {}, + } + } + ty + } +} + #[derive(Clone, PartialEq)] // The type of declaration and the object itself pub enum DeclType<'a> { @@ -335,13 +380,22 @@ pub struct ImportResolver<'mod_lifetime, 'crate_lft: 'mod_lifetime> { priv_modules: HashSet, } impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'crate_lft> { - fn process_use_intern(crate_name: &str, dependencies: &HashSet, imports: &mut HashMap, + 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 == "" && !dependencies.contains(&$ident) { + 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)); @@ -355,7 +409,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr match u { syn::UseTree::Path(p) => { push_path!(p.ident, "::"); - Self::process_use_intern(crate_name, dependencies, imports, &p.tree, &new_path, path); + Self::process_use_intern(crate_name, module_path, dependencies, imports, &p.tree, &new_path, path); }, syn::UseTree::Name(n) => { push_path!(n.ident, ""); @@ -363,7 +417,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr }, syn::UseTree::Group(g) => { for i in g.items.iter() { - Self::process_use_intern(crate_name, dependencies, 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) => { @@ -376,14 +430,14 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr } } - fn process_use(crate_name: &str, dependencies: &HashSet, 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(crate_name, dependencies, 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) { @@ -393,6 +447,9 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr } 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"); @@ -415,7 +472,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(crate_name, dependencies, &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) { @@ -517,9 +574,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr format!("::{}", seg.ident) }).collect(); 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 let Some((imp, _)) = self.imports.get(&first_seg.ident) { if remaining != "" { Some(imp.clone() + &remaining) } else { @@ -527,6 +582,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 } } } @@ -535,7 +592,6 @@ 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) => { -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 { @@ -627,6 +683,13 @@ impl FullLibraryAST { } } +/// 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 +} + /// 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 @@ -662,7 +725,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, } } @@ -752,6 +815,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { match ty { "()" => true, "crate::c_types::Signature" => true, + "crate::c_types::RecoverableSignature" => true, "crate::c_types::TxOut" => true, _ => false, } @@ -771,26 +835,31 @@ 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"), + "String" => Some("crate::c_types::Str"), "std::time::Duration" => Some("u64"), + "std::time::SystemTime" => Some("u64"), "std::io::Error" => Some("crate::c_types::IOError"), - "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::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::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" if !is_ref => Some("crate::c_types::Secp256k1Error"), + "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::lightning::chain::transaction::OutPoint"), @@ -801,17 +870,17 @@ 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"), - "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"), + "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" if is_ref => Some("crate::c_types::ThirtyTwoBytes"), + "lightning::ln::PaymentSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"), // Override the default since Records contain an fmt with a lifetime: "lightning::util::logger::Record" => Some("*const std::os::raw::c_char"), @@ -835,6 +904,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(""), @@ -844,18 +914,22 @@ 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("), + "String" => Some(""), // Note that we'll panic for String if is_ref, as we only have non-owned memory, we // cannot create a &String. "std::time::Duration" => Some("std::time::Duration::from_secs("), + "std::time::SystemTime" => Some("(::std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs("), - "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey" + "bech32::u5" => Some(""), + + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" if is_ref => Some("&"), - "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey" + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some(""), "bitcoin::secp256k1::Signature" if is_ref => Some("&"), "bitcoin::secp256k1::Signature" => Some(""), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some(""), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if is_ref => Some("&::bitcoin::secp256k1::key::SecretKey::from_slice(&unsafe { *"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -873,11 +947,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(&"), - "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("), + "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(""), @@ -896,6 +970,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"), @@ -904,14 +979,18 @@ 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()"), + "String" => Some(".into_string()"), "std::time::Duration" => Some(")"), + "std::time::SystemTime" => Some("))"), - "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey" + "bech32::u5" => Some(".into()"), + + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some(".into_rust()"), "bitcoin::secp256k1::Signature" => Some(".into_rust()"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some(".into_rust()"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if !is_ref => Some(".into_rust()"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -928,11 +1007,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()"), - "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)"), + "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(""), @@ -949,8 +1028,6 @@ 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, @@ -971,11 +1048,12 @@ 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_"), @@ -984,19 +1062,25 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "String" => Some(""), "std::time::Duration" => Some(""), + "std::time::SystemTime" => Some(""), "std::io::Error" if !is_ref => Some("crate::c_types::IOError::from_rust("), - "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey" + "bech32::u5" => Some(""), + + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some("crate::c_types::PublicKey::from_rust(&"), "bitcoin::secp256k1::Signature" => Some("crate::c_types::Signature::from_rust(&"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some("crate::c_types::RecoverableSignature::from_rust(&"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if is_ref => Some(""), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" 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::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("), @@ -1006,15 +1090,16 @@ 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: "), - "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: "), + "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" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), // Override the default since Records contain an fmt with a lifetime: "lightning::util::logger::Record" => Some("local_"), @@ -1033,6 +1118,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(" }"), @@ -1042,20 +1128,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()"), + "String" => Some(".into()"), "std::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"|"bitcoin::secp256k1::PublicKey" + "bech32::u5" => Some(".into()"), + + "bitcoin::secp256k1::key::PublicKey"|"bitcoin::secp256k1::PublicKey"|"secp256k1::key::PublicKey" => Some(")"), "bitcoin::secp256k1::Signature" => Some(")"), + "bitcoin::secp256k1::recovery::RecoverableSignature" => Some(")"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if !is_ref => Some(")"), "bitcoin::secp256k1::key::SecretKey"|"bitcoin::secp256k1::SecretKey" if is_ref => Some(".as_ref()"), - "bitcoin::secp256k1::Error" if !is_ref => Some(")"), + "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(")"), @@ -1068,15 +1159,16 @@ 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() }"), - "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 }"), + "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" if !is_ref => Some(".0 }"), // Override the default since Records contain an fmt with a lifetime: "lightning::util::logger::Record" => Some(".as_ptr()"), @@ -1087,8 +1179,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { fn empty_val_check_suffix_from_path(&self, full_path: &str) -> Option<&str> { match full_path { - "lightning::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 } @@ -1159,8 +1251,13 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "Vec" if !is_ref => { Some(("Vec::new(); for mut item in ", vec![(format!(".drain(..) {{ local_{}.push(", var_name), "item".to_string())], "); }", ContainerPrefixLocation::PerConv)) }, + "Vec" => { + // 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 { @@ -1272,9 +1369,19 @@ 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) + }, + _ => false, + } + } pub fn maybe_resolve_ident(&self, id: &syn::Ident) -> Option { self.types.maybe_resolve_ident(id) @@ -1459,7 +1566,7 @@ 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]; + let len = usize::from_str_radix(&tail_str[..tail_str.len() - 1], 10).unwrap(); Some(parse_quote!([u8; #len])) } else { None } } else { None } @@ -1567,10 +1674,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); @@ -1583,6 +1690,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() { @@ -1615,12 +1726,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() { @@ -1629,19 +1740,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!(); } @@ -1660,24 +1775,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), } @@ -1687,7 +1802,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(), @@ -1716,7 +1831,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(), @@ -1734,9 +1849,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 { @@ -1755,7 +1872,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)) @@ -1768,9 +1885,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 { @@ -1888,7 +2007,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) @@ -2287,6 +2406,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 *** @@ -2325,7 +2451,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;