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=b0a410e208f01e9ff6f941234df862bbb4645c90;hb=a82e075188fc15a103234832686915c196bfe240;hpb=c35ef17b94a8f4e9e019a2b63e0ed22110671b9c diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index b0a410e..13c3b0e 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -66,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 { @@ -117,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!(), @@ -138,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, } } @@ -145,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, } } @@ -164,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. @@ -186,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, _ => {} } @@ -199,14 +210,38 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { if path == "Sized" { continue; } if non_lifetimes_processed { return false; } non_lifetimes_processed = true; - let new_ident = if path != "std::ops::Deref" { + let new_ident = if path != "std::ops::Deref" && path != "core::ops::Deref" { path = "crate::".to_string() + &path; Some(&trait_bound.path) + } else 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))); + } }, _ => {}, } @@ -220,7 +255,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { if p.path.leading_colon.is_some() { return false; } let mut p_iter = p.path.segments.iter(); if let Some(gen) = self.typed_generics.get_mut(&p_iter.next().unwrap().ident) { - if gen.0 != "std::ops::Deref" { return false; } + if gen.0 != "std::ops::Deref" && gen.0 != "core::ops::Deref" { return false; } if &format!("{}", p_iter.next().unwrap().ident) != "Target" { return false; } let mut non_lifetimes_processed = false; @@ -263,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 }; @@ -281,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); } @@ -290,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); } @@ -316,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> { @@ -335,13 +409,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 +438,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 +446,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 +459,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 +476,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,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(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) { 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!"), } } }, @@ -442,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) => { @@ -517,9 +610,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 +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 } } } @@ -535,7 +628,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 +719,21 @@ 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.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 @@ -662,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, } } @@ -751,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, } } @@ -771,26 +876,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"), + "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"|"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 +911,16 @@ 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" => 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 +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(""), @@ -844,18 +954,23 @@ 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("), - "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 +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(&"), - "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 +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"), @@ -904,14 +1020,19 @@ 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"|"bitcoin::secp256k1::PublicKey" + "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 +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()"), - "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(""), @@ -970,6 +1091,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "[u8; 32]" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "), "[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: "), @@ -979,19 +1101,24 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "[usize]" if is_ref => Some("local_"), "str" if is_ref => Some(""), - "String" => Some(""), + "alloc::string::String"|"String" => Some(""), - "std::time::Duration" => Some(""), + "std::time::Duration"|"core::time::Duration" => Some(""), + "std::time::SystemTime" => Some(""), "std::io::Error" if !is_ref => Some("crate::c_types::IOError::from_rust("), - "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" if is_ref => Some("crate::c_types::Transaction::from_bitcoin("), @@ -1005,15 +1132,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" => Some("crate::c_types::ThirtyTwoBytes { data: "), // Override the default since Records contain an fmt with a lifetime: "lightning::util::logger::Record" => Some("local_"), @@ -1032,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(" }"), @@ -1041,20 +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"|"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(")"), @@ -1067,15 +1201,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" => Some(".0 }"), // Override the default since Records contain an fmt with a lifetime: "lightning::util::logger::Record" => Some(".as_ptr()"), @@ -1086,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 { - "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 } @@ -1128,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| { @@ -1155,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![ @@ -1271,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) @@ -1423,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() { @@ -1468,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) { @@ -1509,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); @@ -1569,7 +1738,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { LP: Fn(&str, bool, bool) -> Option, DL: Fn(&mut W, &DeclType, &str, bool, bool), SC: Fn(bool, Option<&str>) -> String> (&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, is_mut: bool, ptr_for_ref: bool, tupleconv: &str, prefix: bool, sliceconv: SC, path_lookup: LP, decl_lookup: DL) { - match t { + match generics.resolve_type(t) { syn::Type::Reference(r) => { self.write_conversion_inline_intern(w, &*r.elem, generics, true, r.mutability.is_some(), ptr_for_ref, tupleconv, prefix, sliceconv, path_lookup, decl_lookup); @@ -1667,7 +1836,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } fn write_to_c_conversion_inline_prefix_inner(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, ptr_for_ref: bool, from_ptr: bool) { - self.write_conversion_inline_intern(w, t, generics, is_ref, false, ptr_for_ref, "0u8 /*", true, |_, _| "local_".to_owned(), + self.write_conversion_inline_intern(w, t, generics, is_ref, false, ptr_for_ref, "() /*", true, |_, _| "local_".to_owned(), |a, b, c| self.to_c_conversion_inline_prefix_from_path(a, b, c), |w, decl_type, decl_path, is_ref, _is_mut| { match decl_type { @@ -1826,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 { @@ -1843,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); } } @@ -1860,7 +2032,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { write!(&mut var, "{}", var_name).unwrap(); let var_access = String::from_utf8(var.into_inner()).unwrap(); - let conv_ty = if needs_ref_map { only_contained_type.as_ref().unwrap() } else { ty }; + let conv_ty = if needs_ref_map { only_contained_type_nonref.as_ref().unwrap() } else { ty }; write!(w, "{} {{ ", pfx).unwrap(); let new_var_name = format!("{}_{}", ident, idx); @@ -1899,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) @@ -2298,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 *** @@ -2336,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;