Skip to content

Commit

Permalink
impl X for Y
Browse files Browse the repository at this point in the history
  • Loading branch information
TheBlueMatt committed May 13, 2020
1 parent 67541ae commit bfa9148
Show file tree
Hide file tree
Showing 7 changed files with 533 additions and 263 deletions.
138 changes: 106 additions & 32 deletions c-bindings-gen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,31 @@ fn maybe_print_generics<W: std::io::Write>(w: &mut W, generics: &syn::Generics,
}
}

macro_rules! walk_supertraits { ($t: expr, $types: expr, ($( $pat: pat => $e: expr),*) ) => { {
if $t.colon_token.is_some() {
for st in $t.supertraits.iter() {
match st {
syn::TypeParamBound::Trait(supertrait) => {
if supertrait.paren_token.is_some() || supertrait.lifetimes.is_some() {
unimplemented!();
}
if let Some(ident) = supertrait.path.get_ident() {
match (&format!("{}", ident) as &str, &ident) {
$( $pat => $e, )*
}
} else {
let path = $types.resolve_path(&supertrait.path);
match (&path as &str, &supertrait.path.segments.iter().last().unwrap().ident) {
$( $pat => $e, )*
}
}
},
syn::TypeParamBound::Lifetime(_) => unimplemented!(),
}
}
}
} } }

fn println_trait<'a, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, types: &mut TypeResolver<'a>) {
let trait_name = format!("{}", t.ident);
match export_status(&t.attrs) {
Expand All @@ -256,40 +281,15 @@ fn println_trait<'a, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, types:
}
println_docs(w, &t.attrs, "");

macro_rules! walk_supertraits { ($( $pat: pat => $e: expr),*) => { {
if t.colon_token.is_some() {
for st in t.supertraits.iter() {
match st {
syn::TypeParamBound::Trait(supertrait) => {
if supertrait.paren_token.is_some() || supertrait.lifetimes.is_some() {
unimplemented!();
}
if let Some(ident) = supertrait.path.get_ident() {
match (&format!("{}", ident) as &str, &ident) {
$( $pat => $e, )*
}
} else {
let path = types.resolve_path(&supertrait.path);
match (&path as &str, &supertrait.path.segments.iter().last().unwrap().ident) {
$( $pat => $e, )*
}
}
},
syn::TypeParamBound::Lifetime(_) => unimplemented!(),
}
}
}
} } }

walk_supertraits!(
walk_supertraits!(t, types, (
("Clone", _) => write!(w, "#[derive(Clone)]\n").unwrap(),
("std::cmp::Eq", _) => {},
("std::hash::Hash", _) => {},
("Send", _) => {}, ("Sync", _) => {},
(s, _) => {
if !s.starts_with("util::") { unimplemented!(); }
}
);
) );
write!(w, "#[repr(C)]\npub struct {} {{\n", trait_name).unwrap();
write!(w, "\tpub this_arg: *mut c_void,\n").unwrap();
let mut associated_types: HashMap<&syn::Ident, &syn::Ident> = HashMap::new();
Expand Down Expand Up @@ -325,7 +325,7 @@ fn println_trait<'a, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, types:
_ => unimplemented!(),
}
}
walk_supertraits!(
walk_supertraits!(t, types, (
("Clone", _) => {},
("std::cmp::Eq", _) => write!(w, "\tpub eq: extern \"C\" fn (this_arg: *const c_void, other_arg: *const c_void) -> bool,\n").unwrap(),
("std::hash::Hash", _) => write!(w, "\tpub hash: extern \"C\" fn (this_arg: *const c_void) -> u64,\n").unwrap(),
Expand All @@ -334,9 +334,9 @@ fn println_trait<'a, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, types:
if !s.starts_with("util::") { unimplemented!(); }
write!(w, "\tpub {}: crate::{},\n", i, s).unwrap();
}
);
) );
write!(w, "}}\n").unwrap();
walk_supertraits!(
walk_supertraits!(t, types, (
("Send", _) => write!(w, "unsafe impl Send for {} {{}}\n", trait_name).unwrap(),
("Sync", _) => write!(w, "unsafe impl Sync for {} {{}}\n", trait_name).unwrap(),
("std::cmp::Eq", _) => {
Expand All @@ -357,7 +357,7 @@ fn println_trait<'a, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, types:
write!(w, "\tfn get_and_clear_pending_msg_events(&self) -> Vec<lightning::util::events::MessageSendEvent> {{\n").unwrap();
write!(w, "\t\tunimplemented!()\n\t}}\n}}\n").unwrap();
}
);
) );
write!(w, "\nuse {}::{}::{} as ln{};\n", types.orig_crate, types.module_path, t.ident, trait_name).unwrap();
write!(w, "impl ln{}", t.ident).unwrap();
maybe_print_generics(w, &t.generics, types);
Expand Down Expand Up @@ -573,8 +573,82 @@ fn println_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &TypeRes
if trait_path.0.is_some() { unimplemented!(); }
if types.understood_c_path(&trait_path.1) {
eprintln!("WIP: IMPL {:?} FOR {}", trait_path.1, ident);
let full_trait_path = types.resolve_path(&trait_path.1);
let trait_obj = types.crate_types.traits.get(&full_trait_path).unwrap();
let export = export_status(&trait_obj.attrs);
match export {
ExportStatus::Export => {},
ExportStatus::NoExport|ExportStatus::TestOnly => return,
}
write!(w, "#[no_mangle]\npub extern \"C\" fn {}_as_{}(this_arg: *const {}) -> crate::{} {{\n", ident, trait_obj.ident, ident, full_trait_path).unwrap();
write!(w, "\tcrate::{} {{\n\t\tthis_arg: unsafe {{ (*this_arg).inner as *mut c_void }},\n", full_trait_path).unwrap();

for item in i.items.iter() {
match item {
syn::ImplItem::Method(m) => {
let trait_method = trait_obj.items.iter().filter_map(|item| {
if let syn::TraitItem::Method(t_m) = item { Some(t_m) } else { None }
}).find(|trait_meth| trait_meth.sig.ident == m.sig.ident).unwrap();
match export_status(&trait_method.attrs) {
ExportStatus::Export => {},
ExportStatus::NoExport => {
write!(w, "\t\t//XXX: Need to export {}\n", m.sig.ident).unwrap();
continue;
},
ExportStatus::TestOnly => continue,
}
write!(w, "\t\t{}: {}_{}_{},\n", m.sig.ident, ident, trait_obj.ident, m.sig.ident).unwrap();
},
_ => {},
}
}
walk_supertraits!(trait_obj, types, (
(s, t) => {
if s.starts_with("util::") {
let supertrait_obj = types.crate_types.traits.get(s).unwrap();
write!(w, "\t\t{}: crate::{} {{\t\t\tthis_arg: unsafe {{ (*this_arg).inner as *mut c_void }},\n", t, s).unwrap();
// TODO: Expose supertrait methods
write!(w, "\t\t}},\n").unwrap();
}
}
) );
write!(w, "\t}}\n}}\nuse {}::{} as {}TraitImport;\n", types.orig_crate, full_trait_path, trait_obj.ident).unwrap();

for item in i.items.iter() {
match item {
syn::ImplItem::Method(m) => {
let trait_method = trait_obj.items.iter().filter_map(|item| {
if let syn::TraitItem::Method(t_m) = item { Some(t_m) } else { None }
}).find(|trait_meth| trait_meth.sig.ident == m.sig.ident).unwrap();
match export_status(&trait_method.attrs) {
ExportStatus::Export => {},
ExportStatus::NoExport|ExportStatus::TestOnly => continue,
}
write!(w, "extern \"C\" fn {}_{}_{}(", ident, trait_obj.ident, m.sig.ident).unwrap();
print_method_params(w, &m.sig, &HashMap::new(), "c_void", types, Some(&gen_types), true);
write!(w, " {{\n\t").unwrap();
print_method_var_decl_body(w, &m.sig, "", types, Some(&gen_types), false);
let mut takes_self = false;
for inp in m.sig.inputs.iter() {
if let syn::FnArg::Receiver(_) = inp {
takes_self = true;
}
}
if takes_self {
write!(w, "unsafe {{ &*(*(this_arg as *const {})).inner }}.{}(", ident, m.sig.ident).unwrap();
} else {
write!(w, "lightning::{}::{}(", resolved_path, m.sig.ident).unwrap();
}
print_method_call_params(w, &m.sig, types, Some(&gen_types), "", false);
write!(w, "\n}}\n").unwrap();
},
syn::ImplItem::Type(_) => {},
_ => unimplemented!(),
}
}
write!(w, "\n").unwrap();
} else if let Some(trait_ident) = trait_path.1.get_ident() {
//XXX: implement for basic things like ToString and implement traits
//XXX: implement for other things like ToString
match &format!("{}", trait_ident) as &str {
"From" => {},
"Default" => {
Expand Down
122 changes: 79 additions & 43 deletions c-bindings-gen/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ impl<'a> TypeResolver<'a> {
return Some("");
}
match full_path {
"bitcoin::secp256k1::key::PublicKey" if is_ref => Some("&"),
"bitcoin::secp256k1::key::PublicKey" => Some(""),
"bitcoin::secp256k1::key::SecretKey" if is_ref => unimplemented!(),
"bitcoin::secp256k1::key::SecretKey" => Some(""),
Expand Down Expand Up @@ -340,7 +341,6 @@ impl<'a> TypeResolver<'a> {
return None;
}
match full_path {
"bitcoin::blockdata::script::Script" => Some(("::bitcoin::consensus::encode::serialize(", ")")),
"bitcoin::blockdata::transaction::Transaction" => Some(("::bitcoin::consensus::encode::serialize(", ")")),
"bitcoin::hash_types::Txid" => None,

Expand All @@ -358,8 +358,10 @@ impl<'a> TypeResolver<'a> {
match full_path {
"bitcoin::secp256k1::key::PublicKey" if is_ref => Some("crate::c_types::PublicKey::from_rust("),
"bitcoin::secp256k1::key::PublicKey" => Some("crate::c_types::PublicKey::from_rust(&"),
"bitcoin::blockdata::script::Script" => Some("crate::c_types::Script::from_slice(&c_"),
"bitcoin::blockdata::transaction::Transaction" => Some("crate::c_types::Transaction::from_slice(&c_"),
"bitcoin::secp256k1::key::SecretKey" if is_ref => unimplemented!(),
"bitcoin::secp256k1::key::SecretKey" if !is_ref => Some("crate::c_types::SecretKey::from_rust("),
"bitcoin::blockdata::script::Script" if is_ref => Some("crate::c_types::Script::from_slice(&c_"),
"bitcoin::blockdata::transaction::Transaction" if is_ref => Some("crate::c_types::Transaction::from_slice(&c_"),
"bitcoin::hash_types::Txid" => Some(""),

// Override the default since Records contain an fmt with a lifetime:
Expand All @@ -384,6 +386,7 @@ impl<'a> TypeResolver<'a> {
}
match full_path {
"bitcoin::secp256k1::key::PublicKey" => Some(")"),
"bitcoin::secp256k1::key::SecretKey" => Some(")"),
"bitcoin::blockdata::script::Script" => Some(")"),
"bitcoin::blockdata::transaction::Transaction" => Some(")"),
"bitcoin::hash_types::Txid" => Some(".into_inner()"),
Expand Down Expand Up @@ -467,24 +470,24 @@ impl<'a> TypeResolver<'a> {
self.declared.get(ident)
}

pub fn maybe_resolve_ident(&self, id: &syn::Ident) -> Option<String> {
if let Some(imp) = self.imports.get(id) {
Some(imp.clone())
} else if self.declared.get(id).is_some() {
Some(self.module_path.to_string() + "::" + &format!("{}", id))
} else { None }
}

pub fn maybe_resolve_path(&self, p: &syn::Path) -> Option<String> {
if p.leading_colon.is_some() {
//format!("{}", p.segments);
return None;
} else if let Some(id) = p.get_ident() {
if let Some(imp) = self.imports.get(id) {
Some(imp.clone())
} else if self.declared.get(id).is_some() {
Some(self.module_path.to_string() + "::" + &format!("{}", id))
} else { None }
self.maybe_resolve_ident(id)
} else {
if p.segments.len() == 1 {
let seg = p.segments.iter().next().unwrap();
if let Some(imp) = self.imports.get(&seg.ident) {
return Some(imp.clone());
} else if self.declared.get(&seg.ident).is_some() {
return Some(self.module_path.to_string() + "::" + &format!("{}", seg.ident));
} else { return None; }
return self.maybe_resolve_ident(&seg.ident);
}
let mut seg_iter = p.segments.iter();
let first_seg = seg_iter.next().unwrap();
Expand Down Expand Up @@ -845,17 +848,18 @@ impl<'a> TypeResolver<'a> {
} else { unimplemented!(); }
} else { unimplemented!(); }
true
} else {
let ty_ident = single_ident_generic_path_to_ident(&p.path).unwrap();
if let Some(full_path) = self.imports.get(ty_ident) {
if let Some(rust_type) = self.from_c_conversion_new_var_from_path_prefix(&full_path) {
} else if self.is_primitive(&resolved_path) {
false
} else if let Some(ty_ident) = single_ident_generic_path_to_ident(&p.path) {
if let Some(rust_type) = self.from_c_conversion_new_var_from_path_prefix(&resolved_path) {
if let Some(_) = self.imports.get(ty_ident) {
write!(w, "let rust_{} = {}{});", ident, rust_type, ident).unwrap();
true
} else { false }
} else if self.declared.get(ty_ident).is_some() {
false
} else { unimplemented!(); }
}
} else { false }
} else { false }
},
syn::Type::Array(_) => {
// We assume all arrays contain only primitive types.
Expand Down Expand Up @@ -901,17 +905,22 @@ impl<'a> TypeResolver<'a> {
if self.is_known_container(&resolved_path) {
write!(w, "rust_").unwrap();
} else {
let ident = single_ident_generic_path_to_ident(&p.path).unwrap();
if let Some(full_path) = self.imports.get(ident) {
if let Some(c_type) = self.from_c_conversion_prefix_from_path(&full_path, is_ref) {
write!(w, "{}", c_type).unwrap();
if let Some(c_type) = self.from_c_conversion_prefix_from_path(&resolved_path, is_ref) {
write!(w, "{}", c_type).unwrap();
} else if let Some(ident) = single_ident_generic_path_to_ident(&p.path) {
if let Some(decl_type) = self.declared.get(ident) {
match decl_type {
DeclType::StructImported(_) if !is_ref => write!(w, "*unsafe {{ Box::from_raw(").unwrap(),
DeclType::StructImported(_) => {},
DeclType::MirroredEnum => {},
_ => unimplemented!(),
}
} else { unimplemented!(); }
} else if let Some(decl_type) = self.declared.get(ident) {
match decl_type {
DeclType::StructImported(_) if !is_ref => write!(w, "*unsafe {{ Box::from_raw(").unwrap(),
DeclType::StructImported(_) => {},
DeclType::MirroredEnum => {},
_ => unimplemented!(),
} else if self.crate_types.structs.get(&resolved_path).is_some() {
if !is_ref {
write!(w, "&unsafe {{ &*").unwrap();
} else {
write!(w, "unsafe {{ &*").unwrap();
}
} else { unimplemented!(); }
}
Expand Down Expand Up @@ -964,18 +973,19 @@ impl<'a> TypeResolver<'a> {
if self.is_known_container(&resolved_path) {
write!(w, "").unwrap();
} else {
let ident = single_ident_generic_path_to_ident(&p.path).unwrap();
if let Some(full_path) = self.imports.get(ident) {
if let Some(c_type) = self.from_c_conversion_suffix_from_path(&full_path) {
write!(w, "{}", c_type).unwrap();
if let Some(c_type) = self.from_c_conversion_suffix_from_path(&resolved_path) {
write!(w, "{}", c_type).unwrap();
} else if let Some(ident) = single_ident_generic_path_to_ident(&p.path) {
if let Some(decl_type) = self.declared.get(ident) {
match decl_type {
DeclType::StructImported(_) if !is_ref => write!(w, ".inner as *mut _) }}").unwrap(),
DeclType::StructImported(_) => {},
DeclType::MirroredEnum => write!(w, ".to_ln()").unwrap(),
_ => unimplemented!(),
}
} else { unimplemented!(); }
} else if let Some(decl_type) = self.declared.get(ident) {
match decl_type {
DeclType::StructImported(_) if !is_ref => write!(w, ".inner as *mut _) }}").unwrap(),
DeclType::StructImported(_) => {},
DeclType::MirroredEnum => write!(w, ".to_ln()").unwrap(),
_ => unimplemented!(),
}
} else if self.crate_types.structs.get(&resolved_path).is_some() {
write!(w, ".inner }}").unwrap();
} else { unimplemented!(); }
}
},
Expand Down Expand Up @@ -1031,6 +1041,34 @@ impl<'a> TypeResolver<'a> {
true
} else { false }
}

fn print_c_path_intern<W: std::io::Write>(&self, w: &mut W, path: &syn::Path, is_ref: bool, is_mut: bool, ptr_for_ref: bool) -> bool {
let full_path = match self.maybe_resolve_path(&path) {
Some(path) => path, None => return false };
if let Some(ident) = single_ident_generic_path_to_ident(&path) {
self.print_c_ident_intern(w, ident, is_ref, is_mut, ptr_for_ref)
} else if let Some(t) = self.crate_types.traits.get(&full_path) {
if is_ref && ptr_for_ref {
write!(w, "*const crate::{}", full_path).unwrap();
} else if is_ref {
write!(w, "&crate::{}", full_path).unwrap();
} else {
write!(w, "crate::{}", full_path).unwrap();
}
true
} else if let Some(s) = self.crate_types.structs.get(&full_path) {
if is_ref && ptr_for_ref {
write!(w, "*const crate::{}", full_path).unwrap();
} else if is_ref {
write!(w, "&crate::{}", full_path).unwrap();
} else {
write!(w, "crate::{}", full_path).unwrap();
}
true
} else {
false
}
}
fn print_c_type_intern<W: std::io::Write>(&self, generics: Option<&GenericTypes>, w: &mut W, t: &syn::Type, is_ref: bool, is_mut: bool, ptr_for_ref: bool) -> bool {
match t {
syn::Type::Path(p) => {
Expand All @@ -1054,9 +1092,7 @@ impl<'a> TypeResolver<'a> {
}
}
if p.path.leading_colon.is_some() { return false; }
if let Some(ident) = single_ident_generic_path_to_ident(&p.path) {
self.print_c_ident_intern(w, &ident, is_ref, is_mut, ptr_for_ref)
} else { false }
self.print_c_path_intern(w, &p.path, is_ref, is_mut, ptr_for_ref)
},
syn::Type::Reference(r) => {
if r.lifetime.is_some() { return false; }
Expand Down
Loading

0 comments on commit bfa9148

Please sign in to comment.