X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=sidebyside;f=c-bindings-gen%2Fsrc%2Ftypes.rs;h=7f979a5675235b1b54d83e9634dc9f86199ffccc;hb=2462e4306349623c9165ed0d36d7e9cd9115cfcb;hp=628d263bf9a9775939a1c88ca3ec57e96840e362;hpb=e4b516dd8a62166c206e7aa5363a0c07add1d3a9;p=rust-lightning diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index 628d263bf..7f979a567 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -1,8 +1,10 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::Write; use std::hash; +use crate::blocks::*; + use proc_macro2::{TokenTree, Span}; // The following utils are used purely to build our known types maps - they break down all the @@ -39,6 +41,15 @@ pub fn single_ident_generic_path_to_ident(p: &syn::Path) -> Option<&syn::Ident> } else { None } } +pub fn path_matches_nongeneric(p: &syn::Path, exp: &[&str]) -> bool { + if p.segments.len() != exp.len() { return false; } + for (seg, e) in p.segments.iter().zip(exp.iter()) { + if seg.arguments != syn::PathArguments::None { return false; } + if &format!("{}", seg.ident) != *e { return false; } + } + true +} + #[derive(Debug, PartialEq)] pub enum ExportStatus { Export, @@ -139,6 +150,7 @@ impl<'a> GenericTypes<'a> { if let Some(ident) = single_ident_generic_path_to_ident(&trait_bound.path) { match &format!("{}", ident) as &str { "Send" => continue, "Sync" => continue, _ => {} } } + if path_matches_nongeneric(&trait_bound.path, &["core", "clone", "Clone"]) { continue; } assert_simple_bound(&trait_bound); if let Some(mut path) = types.maybe_resolve_path(&trait_bound.path, None) { @@ -272,7 +284,7 @@ pub enum DeclType<'a> { // the sorting is stable across runs. It is deprecated, but the "replacement" doesn't actually // accomplish the same goals, so we just ignore it. #[allow(deprecated)] -type NonRandomHash = hash::BuildHasherDefault; +pub type NonRandomHash = hash::BuildHasherDefault; /// Top-level struct tracking everything which has been defined while walking the crate. pub struct CrateTypes<'a> { @@ -293,6 +305,8 @@ pub struct CrateTypes<'a> { /// The output file for any created template container types, written to as we find new /// template containers which need to be defined. pub template_file: &'a mut File, + /// Set of containers which are clonable + pub clonable_types: HashSet, } /// A struct which tracks resolving rust types into C-mapped equivalents, exists for one specific @@ -368,6 +382,16 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { _ => false, } } + pub fn is_clonable(&self, ty: &str) -> bool { + if self.crate_types.clonable_types.contains(ty) { return true; } + if self.is_primitive(ty) { return true; } + match ty { + "()" => true, + "crate::c_types::Signature" => true, + "crate::c_types::TxOut" => true, + _ => false, + } + } /// Gets the C-mapped type for types which are outside of the crate, or which are manually /// ignored by for some reason need mapping anyway. fn c_type_from_path<'b>(&self, full_path: &'b str, is_ref: bool, ptr_for_ref: bool) -> Option<&'b str> { @@ -428,10 +452,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "ln::features::InitFeatures" if is_ref && ptr_for_ref => Some("crate::ln::features::InitFeatures"), "ln::features::InitFeatures" if is_ref => Some("*const crate::ln::features::InitFeatures"), "ln::features::InitFeatures" => Some("crate::ln::features::InitFeatures"), - _ => { - eprintln!(" Type {} (ref: {}) unresolvable in C", full_path, is_ref); - None - }, + _ => None, } } @@ -496,10 +517,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // List of traits we map (possibly during processing of other files): "crate::util::logger::Logger" => Some(""), - _ => { - eprintln!(" Type {} unconvertable from C", full_path); - None - }, + _ => None, }.map(|s| s.to_owned()) } fn from_c_conversion_suffix_from_path<'b>(&self, full_path: &str, is_ref: bool) -> Option { @@ -555,10 +573,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // List of traits we map (possibly during processing of other files): "crate::util::logger::Logger" => Some(""), - _ => { - eprintln!(" Type {} unconvertable from C", full_path); - None - }, + _ => None, }.map(|s| s.to_owned()) } @@ -640,10 +655,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "ln::features::InitFeatures" if is_ref => Some("Box::into_raw(Box::new(crate::ln::features::InitFeatures { inner: &mut "), "ln::features::InitFeatures" if !is_ref => Some("crate::ln::features::InitFeatures { inner: Box::into_raw(Box::new("), - _ => { - eprintln!(" Type {} (is_ref: {}) unconvertable to C", full_path, is_ref); - None - }, + _ => None, }.map(|s| s.to_owned()) } fn to_c_conversion_inline_suffix_from_path(&self, full_path: &str, is_ref: bool, ptr_for_ref: bool) -> Option { @@ -705,10 +717,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "ln::features::InitFeatures" if is_ref => Some(", is_owned: false }))"), "ln::features::InitFeatures" => Some(")), is_owned: true }"), - _ => { - eprintln!(" Type {} unconvertable to C", full_path); - None - }, + _ => None, }.map(|s| s.to_owned()) } @@ -753,8 +762,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { "Result" if !is_ref => { Some(("match ", vec![(" { Ok(mut o) => crate::c_types::CResultTempl::ok(".to_string(), "o".to_string()), - ("), Err(mut e) => crate::c_types::CResultTempl::err(".to_string(), "e".to_string())], - ") }")) + (").into(), Err(mut e) => crate::c_types::CResultTempl::err(".to_string(), "e".to_string())], + ").into() }")) }, "Vec" if !is_ref => { Some(("Vec::new(); for item in ", vec![(format!(".drain(..) {{ local_{}.push(", var_name), "item".to_string())], "); }")) @@ -877,6 +886,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { eprintln!("Ignoring pub(use) tree!"); return; } + if u.leading_colon.is_some() { eprintln!("Ignoring leading-colon use!"); return; } match &u.tree { syn::UseTree::Path(p) => { let new_path = format!("{}", p.ident); @@ -888,18 +898,15 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { }, _ => unimplemented!(), } - if u.leading_colon.is_some() { unimplemented!() } } pub fn mirrored_enum_declared(&mut self, ident: &syn::Ident) { - eprintln!("{} mirrored", ident); self.declared.insert(ident.clone(), DeclType::MirroredEnum); } pub fn enum_ignored(&mut self, ident: &'c syn::Ident) { self.declared.insert(ident.clone(), DeclType::EnumIgnored); } - pub fn struct_imported(&mut self, ident: &'c syn::Ident, named: String) { - eprintln!("Imported {} as {}", ident, named); + pub fn struct_imported(&mut self, ident: &'c syn::Ident) { self.declared.insert(ident.clone(), DeclType::StructImported); } pub fn struct_ignored(&mut self, ident: &syn::Ident) { @@ -907,7 +914,6 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { self.declared.insert(ident.clone(), DeclType::StructIgnored); } pub fn trait_declared(&mut self, ident: &syn::Ident, t: &'c syn::ItemTrait) { - eprintln!("Trait {} created", ident); self.declared.insert(ident.clone(), DeclType::Trait(t)); } pub fn get_declared_type(&'a self, ident: &syn::Ident) -> Option<&'a DeclType<'c>> { @@ -1720,153 +1726,90 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // *** C Container Type Equivalent and alias Printing *** // ****************************************************** - fn write_template_constructor(&mut self, w: &mut W, container_type: &str, mangled_container: &str, args: &Vec<&syn::Type>, generics: Option<&GenericTypes>, is_ref: bool) -> bool { - if container_type == "Result" { - assert_eq!(args.len(), 2); - macro_rules! write_fn { - ($call: expr) => { { - writeln!(w, "#[no_mangle]\npub extern \"C\" fn {}_{}() -> {} {{", mangled_container, $call, mangled_container).unwrap(); - writeln!(w, "\t{}::CResultTempl::{}(0)\n}}\n", Self::container_templ_path(), $call).unwrap(); - } } - } - macro_rules! write_alias { - ($call: expr, $item: expr) => { { - write!(w, "#[no_mangle]\npub static {}_{}: extern \"C\" fn (", mangled_container, $call).unwrap(); - if let syn::Type::Path(syn::TypePath { path, .. }) = $item { - let resolved = self.resolve_path(path, generics); - if self.is_known_container(&resolved, is_ref) || self.is_transparent_container(&resolved, is_ref) { - self.write_c_mangled_container_path_intern(w, Self::path_to_generic_args(path), generics, - &format!("{}", single_ident_generic_path_to_ident(path).unwrap()), is_ref, false, false, false); - } else { - self.write_template_generics(w, &mut [$item].iter().map(|t| *t), generics, is_ref, true); - } - } else if let syn::Type::Tuple(syn::TypeTuple { elems, .. }) = $item { - self.write_c_mangled_container_path_intern(w, elems.iter().collect(), generics, - &format!("{}Tuple", elems.len()), is_ref, false, false, false); - } else { unimplemented!(); } - write!(w, ") -> {} =\n\t{}::CResultTempl::<", mangled_container, Self::container_templ_path()).unwrap(); - self.write_template_generics(w, &mut args.iter().map(|t| *t), generics, is_ref, true); - writeln!(w, ">::{};\n", $call).unwrap(); - } } - } - match args[0] { - syn::Type::Tuple(t) if t.elems.is_empty() => write_fn!("ok"), - _ => write_alias!("ok", args[0]), - } - match args[1] { - syn::Type::Tuple(t) if t.elems.is_empty() => write_fn!("err"), - _ => write_alias!("err", args[1]), - } - } else if container_type.ends_with("Tuple") { - write!(w, "#[no_mangle]\npub extern \"C\" fn {}_new(", mangled_container).unwrap(); - for (idx, gen) in args.iter().enumerate() { - write!(w, "{}{}: ", if idx != 0 { ", " } else { "" }, ('a' as u8 + idx as u8) as char).unwrap(); - if !self.write_c_type_intern(w, gen, None, false, false, false) { return false; } - } - writeln!(w, ") -> {} {{", mangled_container).unwrap(); - write!(w, "\t{} {{ ", mangled_container).unwrap(); - for idx in 0..args.len() { - write!(w, "{}, ", ('a' as u8 + idx as u8) as char).unwrap(); - } - writeln!(w, "}}\n}}\n").unwrap(); - } else { - writeln!(w, "").unwrap(); - } - true - } - - fn write_template_generics<'b, W: std::io::Write>(&self, w: &mut W, args: &mut dyn Iterator, generics: Option<&GenericTypes>, is_ref: bool, in_crate: bool) { + fn write_template_generics<'b, W: std::io::Write>(&mut self, w: &mut W, args: &mut dyn Iterator, generics: Option<&GenericTypes>, is_ref: bool) -> bool { + assert!(!is_ref); // We don't currently support outer reference types for (idx, t) in args.enumerate() { if idx != 0 { write!(w, ", ").unwrap(); } - if let syn::Type::Tuple(tup) = t { - if tup.elems.is_empty() { - write!(w, "u8").unwrap(); - } else { - write!(w, "{}::C{}TupleTempl<", Self::container_templ_path(), tup.elems.len()).unwrap(); - self.write_template_generics(w, &mut tup.elems.iter(), generics, is_ref, in_crate); - write!(w, ">").unwrap(); - } - } else if let syn::Type::Path(p_arg) = t { - let resolved_generic = self.resolve_path(&p_arg.path, generics); - if self.is_primitive(&resolved_generic) { - write!(w, "{}", resolved_generic).unwrap(); - } else if let Some(c_type) = self.c_type_from_path(&resolved_generic, is_ref, false) { - if self.is_known_container(&resolved_generic, is_ref) { - write!(w, "{}::C{}Templ<", Self::container_templ_path(), single_ident_generic_path_to_ident(&p_arg.path).unwrap()).unwrap(); - assert_eq!(p_arg.path.segments.len(), 1); - if let syn::PathArguments::AngleBracketed(args) = &p_arg.path.segments.iter().next().unwrap().arguments { - self.write_template_generics(w, &mut args.args.iter().map(|gen| - if let syn::GenericArgument::Type(t) = gen { t } else { unimplemented!() }), - generics, is_ref, in_crate); - } else { unimplemented!(); } - write!(w, ">").unwrap(); - } else if resolved_generic == "Option" { - if let syn::PathArguments::AngleBracketed(args) = &p_arg.path.segments.iter().next().unwrap().arguments { - self.write_template_generics(w, &mut args.args.iter().map(|gen| - if let syn::GenericArgument::Type(t) = gen { t } else { unimplemented!() }), - generics, is_ref, in_crate); - } else { unimplemented!(); } - } else if in_crate { - write!(w, "{}", c_type).unwrap(); - } else { - self.write_rust_type(w, generics, &t); - } - } else { - // If we just write out resolved_generic, it may mostly work, however for - // original types which are generic, we need the template args. We could - // figure them out and write them out, too, but its much easier to just - // reference the native{} type alias which exists at least for opaque types. - if in_crate { - write!(w, "crate::{}", resolved_generic).unwrap(); - } else { - let path_name: Vec<&str> = resolved_generic.rsplitn(2, "::").collect(); - if path_name.len() > 1 { - write!(w, "crate::{}::native{}", path_name[1], path_name[0]).unwrap(); - } else { - write!(w, "crate::native{}", path_name[0]).unwrap(); - } - } - } - } else if let syn::Type::Reference(r_arg) = t { + if let syn::Type::Reference(r_arg) = t { + if !self.write_c_type_intern(w, &*r_arg.elem, generics, false, false, false) { return false; } + + // While write_c_type_intern, above is correct, we don't want to blindly convert a + // reference to something stupid, so check that the container is either opaque or a + // predefined type (currently only Transaction). if let syn::Type::Path(p_arg) = &*r_arg.elem { let resolved = self.resolve_path(&p_arg.path, generics); - if self.crate_types.opaques.get(&resolved).is_some() { - write!(w, "crate::{}", resolved).unwrap(); - } else { - let cty = self.c_type_from_path(&resolved, true, true).expect("Template generics should be opaque or have a predefined mapping"); - w.write(cty.as_bytes()).unwrap(); - } + assert!(self.crate_types.opaques.get(&resolved).is_some() || + self.c_type_from_path(&resolved, true, true).is_some(), "Template generics should be opaque or have a predefined mapping"); } else { unimplemented!(); } - } else if let syn::Type::Array(a_arg) = t { - if let syn::Type::Path(p_arg) = &*a_arg.elem { - let resolved = self.resolve_path(&p_arg.path, generics); - assert!(self.is_primitive(&resolved)); - if let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(len), .. }) = &a_arg.len { - write!(w, "{}", - self.c_type_from_path(&format!("[{}; {}]", resolved, len.base10_digits()), is_ref, false).unwrap()).unwrap(); - } - } + } else { + if !self.write_c_type_intern(w, t, generics, false, false, false) { return false; } } } + true } fn check_create_container(&mut self, mangled_container: String, container_type: &str, args: Vec<&syn::Type>, generics: Option<&GenericTypes>, is_ref: bool) -> bool { if !self.crate_types.templates_defined.get(&mangled_container).is_some() { let mut created_container: Vec = Vec::new(); - write!(&mut created_container, "pub type {} = ", mangled_container).unwrap(); - write!(&mut created_container, "{}::C{}Templ<", Self::container_templ_path(), container_type).unwrap(); - self.write_template_generics(&mut created_container, &mut args.iter().map(|t| *t), generics, is_ref, true); - writeln!(&mut created_container, ">;").unwrap(); + if container_type == "Result" { + let mut a_ty: Vec = Vec::new(); + if let syn::Type::Tuple(tup) = args.iter().next().unwrap() { + if tup.elems.is_empty() { + write!(&mut a_ty, "()").unwrap(); + } else { + if !self.write_template_generics(&mut a_ty, &mut args.iter().map(|t| *t).take(1), generics, is_ref) { return false; } + } + } else { + if !self.write_template_generics(&mut a_ty, &mut args.iter().map(|t| *t).take(1), generics, is_ref) { return false; } + } - write!(&mut created_container, "#[no_mangle]\npub static {}_free: extern \"C\" fn({}) = ", mangled_container, mangled_container).unwrap(); - write!(&mut created_container, "{}::C{}Templ_free::<", Self::container_templ_path(), container_type).unwrap(); - self.write_template_generics(&mut created_container, &mut args.iter().map(|t| *t), generics, is_ref, true); - writeln!(&mut created_container, ">;").unwrap(); + let mut b_ty: Vec = Vec::new(); + if let syn::Type::Tuple(tup) = args.iter().skip(1).next().unwrap() { + if tup.elems.is_empty() { + write!(&mut b_ty, "()").unwrap(); + } else { + if !self.write_template_generics(&mut b_ty, &mut args.iter().map(|t| *t).skip(1), generics, is_ref) { return false; } + } + } else { + if !self.write_template_generics(&mut b_ty, &mut args.iter().map(|t| *t).skip(1), generics, is_ref) { return false; } + } - if !self.write_template_constructor(&mut created_container, container_type, &mangled_container, &args, generics, is_ref) { - return false; + let ok_str = String::from_utf8(a_ty).unwrap(); + let err_str = String::from_utf8(b_ty).unwrap(); + let is_clonable = self.is_clonable(&ok_str) && self.is_clonable(&err_str); + write_result_block(&mut created_container, &mangled_container, &ok_str, &err_str, is_clonable); + if is_clonable { + self.crate_types.clonable_types.insert(Self::generated_container_path().to_owned() + "::" + &mangled_container); + } + } else if container_type == "Vec" { + let mut a_ty: Vec = Vec::new(); + if !self.write_template_generics(&mut a_ty, &mut args.iter().map(|t| *t), generics, is_ref) { return false; } + let ty = String::from_utf8(a_ty).unwrap(); + let is_clonable = self.is_clonable(&ty); + write_vec_block(&mut created_container, &mangled_container, &ty, is_clonable); + if is_clonable { + self.crate_types.clonable_types.insert(Self::generated_container_path().to_owned() + "::" + &mangled_container); + } + } else if container_type.ends_with("Tuple") { + let mut tuple_args = Vec::new(); + let mut is_clonable = true; + for arg in args.iter() { + let mut ty: Vec = Vec::new(); + if !self.write_template_generics(&mut ty, &mut [arg].iter().map(|t| **t), generics, is_ref) { return false; } + let ty_str = String::from_utf8(ty).unwrap(); + if !self.is_clonable(&ty_str) { + is_clonable = false; + } + tuple_args.push(ty_str); + } + write_tuple_block(&mut created_container, &mangled_container, &tuple_args, is_clonable); + if is_clonable { + self.crate_types.clonable_types.insert(Self::generated_container_path().to_owned() + "::" + &mangled_container); + } + } else { + unreachable!(); } self.crate_types.templates_defined.insert(mangled_container.clone(), true); @@ -1921,7 +1864,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { generics, &subtype, is_ref, is_mut, ptr_for_ref, true); } } else { - let id = &&$p_arg.path.segments.iter().rev().next().unwrap().ident; + let id = subtype.rsplitn(2, ':').next().unwrap(); // Get the "Base" name of the resolved type write!(w, "{}", id).unwrap(); write!(mangled_type, "{}", id).unwrap(); if let Some(w2) = $extra_write as Option<&mut Vec> { @@ -1965,7 +1908,6 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } else if let syn::Type::Path(p_arg) = arg { write_path!(p_arg, None); } else if let syn::Type::Reference(refty) = arg { - if args.len() != 1 { return false; } if let syn::Type::Path(p_arg) = &*refty.elem { write_path!(p_arg, None); } else if let syn::Type::Slice(_) = &*refty.elem { @@ -1973,6 +1915,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { // make it a pointer so that its an option. Note that we cannot always convert // the Vec-as-slice (ie non-ref types) containers, so sometimes need to be able // to edit it, hence we use *mut here instead of *const. + if args.len() != 1 { return false; } write!(w, "*mut ").unwrap(); self.write_c_type(w, arg, None, true); } else { return false; }