X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Ftypes.rs;h=835e6c02323a92eff2d2df0f070b04b21e7ebadc;hb=1f9a169c7e376baad24015ecf775e1adcf9d5967;hp=e88133818cca6ae1a8584c3ef417a5c7d90983af;hpb=f1f2ff0c395671d1e4f0c566836ae290d2c85113;p=ldk-c-bindings diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index e881338..835e6c0 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -517,9 +517,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 +525,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" || self.dependencies.contains(&first_seg.ident) { + Some(first_seg_str + &remaining) } else { None } } } @@ -627,6 +627,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 +669,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, } } @@ -771,6 +778,7 @@ 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"), @@ -783,14 +791,17 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "std::time::Duration" => 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::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,10 +812,10 @@ 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"), @@ -835,6 +846,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(""), @@ -850,9 +862,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "std::time::Duration" => Some("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(""), @@ -896,6 +910,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"), @@ -909,7 +924,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "std::time::Duration" => 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::key::SecretKey"|"bitcoin::secp256k1::SecretKey" @@ -970,6 +987,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: "), @@ -984,14 +1002,17 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "std::time::Duration" => 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::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,9 +1026,10 @@ 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: "), @@ -1032,6 +1054,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(" }"), @@ -1047,14 +1070,17 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "std::time::Duration" => Some(".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::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,9 +1093,10 @@ 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 }"), @@ -1087,7 +1114,7 @@ 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()"), + "secp256k1::key::PublicKey"|"bitcoin::secp256k1::key::PublicKey" => Some(".is_null()"), "bitcoin::secp256k1::Signature" => Some(".is_null()"), _ => None } @@ -1158,8 +1185,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 { @@ -1271,9 +1303,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) @@ -1458,7 +1500,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 } @@ -1566,7 +1608,7 @@ 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 { @@ -1618,12 +1660,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() { @@ -1632,19 +1674,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!(); } @@ -1663,7 +1709,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_", + self.write_conversion_inline_intern(w, t, generics, is_ref, false, ptr_for_ref, "0u8 /*", 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 { @@ -1690,7 +1736,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(), @@ -1719,7 +1765,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(), @@ -1737,9 +1783,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 { @@ -1758,7 +1806,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)) @@ -1771,9 +1819,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 {