X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Fmain.rs;h=4572f7d921d405256d67b50d7616cacf8461aa7f;hb=HEAD;hp=8876583315246524ffb938df804234b9a2784d86;hpb=8f4db29a29bcce3b945f698ab81dee2306770832;p=ldk-c-bindings diff --git a/c-bindings-gen/src/main.rs b/c-bindings-gen/src/main.rs index 8876583..6dd63f8 100644 --- a/c-bindings-gen/src/main.rs +++ b/c-bindings-gen/src/main.rs @@ -62,18 +62,22 @@ fn maybe_convert_trait_impl(w: &mut W, trait_path: &syn::Path if let Some(t) = types.maybe_resolve_path(&trait_path, Some(generics)) { let for_obj; let full_obj_path; + let native_path; let mut has_inner = false; if let syn::Type::Path(ref p) = for_ty { let resolved_path = types.resolve_path(&p.path, Some(generics)); for_obj = format!("{}", p.path.segments.last().unwrap().ident); full_obj_path = format!("crate::{}", resolved_path); has_inner = types.c_type_has_inner_from_path(&resolved_path); + let (path, name) = full_obj_path.rsplit_once("::").unwrap(); + native_path = path.to_string() + "::native" + name; } else { // We assume that anything that isn't a Path is somehow a generic that ends up in our // derived-types module. let mut for_obj_vec = Vec::new(); types.write_c_type(&mut for_obj_vec, for_ty, Some(generics), false); full_obj_path = String::from_utf8(for_obj_vec).unwrap(); + native_path = full_obj_path.clone(); if !full_obj_path.starts_with(TypeResolver::generated_container_path()) { return; } for_obj = full_obj_path[TypeResolver::generated_container_path().len() + 2..].into(); } @@ -94,12 +98,15 @@ fn maybe_convert_trait_impl(w: &mut W, trait_path: &syn::Path writeln!(w, ")").unwrap(); writeln!(w, "}}").unwrap(); + + writeln!(w, "#[allow(unused)]").unwrap(); + writeln!(w, "pub(crate) extern \"C\" fn {}_write_void(obj: *const c_void) -> crate::c_types::derived::CVec_u8Z {{", for_obj).unwrap(); if has_inner { - writeln!(w, "#[no_mangle]").unwrap(); - writeln!(w, "pub(crate) extern \"C\" fn {}_write_void(obj: *const c_void) -> crate::c_types::derived::CVec_u8Z {{", for_obj).unwrap(); - writeln!(w, "\tcrate::c_types::serialize_obj(unsafe {{ &*(obj as *const native{}) }})", for_obj).unwrap(); - writeln!(w, "}}").unwrap(); + writeln!(w, "\tcrate::c_types::serialize_obj(unsafe {{ &*(obj as *const {}) }})", native_path).unwrap(); + } else { + writeln!(w, "\t{}_write(unsafe {{ &*(obj as *const {}) }})", for_obj, for_obj).unwrap(); } + writeln!(w, "}}").unwrap(); }, "lightning::util::ser::Readable"|"lightning::util::ser::ReadableArgs"|"lightning::util::ser::MaybeReadable" => { // Create the Result syn::Type @@ -218,6 +225,11 @@ fn do_write_impl_trait(w: &mut W, trait_path: &str, _trait_na writeln!(w, "\t\tlet vec = (self.write)(self.this_arg);").unwrap(); writeln!(w, "\t\tw.write_all(vec.as_slice())").unwrap(); writeln!(w, "\t}}\n}}").unwrap(); + writeln!(w, "impl {} for {}Ref {{", trait_path, for_obj).unwrap(); + writeln!(w, "\tfn write(&self, w: &mut W) -> Result<(), crate::c_types::io::Error> {{").unwrap(); + writeln!(w, "\t\tlet vec = (self.0.write)(self.0.this_arg);").unwrap(); + writeln!(w, "\t\tw.write_all(vec.as_slice())").unwrap(); + writeln!(w, "\t}}\n}}").unwrap(); }, _ => panic!(), } @@ -267,8 +279,8 @@ macro_rules! walk_supertraits { ($t: expr, $types: expr, ($( $($pat: pat)|* => $ } } } macro_rules! get_module_type_resolver { - ($module: expr, $crate_libs: expr, $crate_types: expr) => { { - let module: &str = &$module; + ($type_in_module: expr, $crate_types: expr) => { { + let module: &str = &$type_in_module; let mut module_iter = module.rsplitn(2, "::"); module_iter.next().unwrap(); let module = module_iter.next().unwrap(); @@ -304,7 +316,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty (s, _i, _) => { if let Some(supertrait) = types.crate_types.traits.get(s) { supertrait_name = s.to_string(); - supertrait_resolver = get_module_type_resolver!(supertrait_name, types.crate_libs, types.crate_types); + supertrait_resolver = get_module_type_resolver!(supertrait_name, types.crate_types); gen_types.learn_associated_types(&supertrait, &supertrait_resolver); break; } @@ -443,6 +455,47 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty ($t: expr, $impl_accessor: expr, $type_resolver: expr, $generic_impls: expr) => { let mut trait_gen_types = gen_types.push_ctx(); assert!(trait_gen_types.learn_generics_with_impls(&$t.generics, $generic_impls, $type_resolver)); + + let mut ref_types = HashSet::new(); + for item in $t.items.iter() { + if let syn::TraitItem::Type(ref t) = &item { + if t.default.is_some() || t.generics.lt_token.is_some() { panic!("10"); } + let mut bounds_iter = t.bounds.iter(); + loop { + match bounds_iter.next().unwrap() { + syn::TypeParamBound::Trait(tr) => { + match $type_resolver.resolve_path(&tr.path, None).as_str() { + "core::ops::Deref"|"core::ops::DerefMut"|"std::ops::Deref"|"std::ops::DerefMut" => { + // Handle cases like + // trait A { + // type B; + // type C: Deref; + // } + // by tracking if we have any B's here and making them + // the *Ref types below. + if let syn::PathArguments::AngleBracketed(args) = &tr.path.segments.iter().last().unwrap().arguments { + if let syn::GenericArgument::Binding(bind) = args.args.iter().last().unwrap() { + assert_eq!(format!("{}", bind.ident), "Target"); + if let syn::Type::Path(p) = &bind.ty { + assert!(p.qself.is_none()); + let mut segs = p.path.segments.iter(); + assert_eq!(format!("{}", segs.next().unwrap().ident), "Self"); + ref_types.insert(format!("{}", segs.next().unwrap().ident)); + assert!(segs.next().is_none()); + } else { panic!(); } + } + } + }, + _ => {}, + } + break; + } + syn::TypeParamBound::Lifetime(_) => {}, + } + } + } + } + for item in $t.items.iter() { match item { syn::TraitItem::Method(m) => { @@ -531,7 +584,11 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty loop { match bounds_iter.next().unwrap() { syn::TypeParamBound::Trait(tr) => { - writeln!(w, "\ttype {} = crate::{};", t.ident, $type_resolver.resolve_path(&tr.path, Some(&gen_types))).unwrap(); + write!(w, "\ttype {} = crate::{}", t.ident, $type_resolver.resolve_path(&tr.path, Some(&gen_types))).unwrap(); + if ref_types.contains(&format!("{}", t.ident)) { + write!(w, "Ref").unwrap(); + } + writeln!(w, ";").unwrap(); for bound in bounds_iter { if let syn::TypeParamBound::Trait(t) = bound { // We only allow for `Sized` here. @@ -554,8 +611,8 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty writeln!(w, "unsafe impl Send for {} {{}}", trait_name).unwrap(); writeln!(w, "unsafe impl Sync for {} {{}}", trait_name).unwrap(); - writeln!(w, "#[no_mangle]").unwrap(); - writeln!(w, "pub(crate) extern \"C\" fn {}_clone_fields(orig: &{}) -> {} {{", trait_name, trait_name, trait_name).unwrap(); + writeln!(w, "#[allow(unused)]").unwrap(); + writeln!(w, "pub(crate) fn {}_clone_fields(orig: &{}) -> {} {{", trait_name, trait_name, trait_name).unwrap(); writeln!(w, "\t{} {{", trait_name).unwrap(); writeln!(w, "\t\tthis_arg: orig.this_arg,").unwrap(); for (field, clone_fn, _) in generated_fields.iter() { @@ -574,10 +631,15 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty writeln!(w, "impl core::cmp::Eq for {} {{}}", trait_name).unwrap(); writeln!(w, "impl core::cmp::PartialEq for {} {{", trait_name).unwrap(); writeln!(w, "\tfn eq(&self, o: &Self) -> bool {{ (self.eq)(self.this_arg, o) }}\n}}").unwrap(); + writeln!(w, "impl core::cmp::Eq for {}Ref {{}}", trait_name).unwrap(); + writeln!(w, "impl core::cmp::PartialEq for {}Ref {{", trait_name).unwrap(); + writeln!(w, "\tfn eq(&self, o: &Self) -> bool {{ (self.0.eq)(self.0.this_arg, &o.0) }}\n}}").unwrap(); }, ("std::hash::Hash", _, _)|("core::hash::Hash", _, _) => { writeln!(w, "impl core::hash::Hash for {} {{", trait_name).unwrap(); writeln!(w, "\tfn hash(&self, hasher: &mut H) {{ hasher.write_u64((self.hash)(self.this_arg)) }}\n}}").unwrap(); + writeln!(w, "impl core::hash::Hash for {}Ref {{", trait_name).unwrap(); + writeln!(w, "\tfn hash(&self, hasher: &mut H) {{ hasher.write_u64((self.0.hash)(self.0.this_arg)) }}\n}}").unwrap(); }, ("Send", _, _) => {}, ("Sync", _, _) => {}, ("Clone", _, _) => { @@ -591,6 +653,10 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty writeln!(w, "\tfn clone(&self) -> Self {{").unwrap(); writeln!(w, "\t\t{}_clone(self)", trait_name).unwrap(); writeln!(w, "\t}}\n}}").unwrap(); + writeln!(w, "impl Clone for {}Ref {{", trait_name).unwrap(); + writeln!(w, "\tfn clone(&self) -> Self {{").unwrap(); + writeln!(w, "\t\tSelf({}_clone(&self.0))", trait_name).unwrap(); + writeln!(w, "\t}}\n}}").unwrap(); }, ("std::fmt::Debug", _, _)|("core::fmt::Debug", _, _) => { writeln!(w, "impl core::fmt::Debug for {} {{", trait_name).unwrap(); @@ -598,13 +664,18 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty writeln!(w, "\t\tf.write_str((self.debug_str)(self.this_arg).into_str())").unwrap(); writeln!(w, "\t}}").unwrap(); writeln!(w, "}}").unwrap(); + writeln!(w, "impl core::fmt::Debug for {}Ref {{", trait_name).unwrap(); + writeln!(w, "\tfn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {{").unwrap(); + writeln!(w, "\t\tf.write_str((self.0.debug_str)(self.0.this_arg).into_str())").unwrap(); + writeln!(w, "\t}}").unwrap(); + writeln!(w, "}}").unwrap(); }, (s, i, generic_args) => { if let Some(supertrait) = types.crate_types.traits.get(s) { - let resolver = get_module_type_resolver!(s, types.crate_libs, types.crate_types); + let resolver = get_module_type_resolver!(s, types.crate_types); macro_rules! impl_supertrait { ($s: expr, $supertrait: expr, $i: expr, $generic_args: expr) => { - let resolver = get_module_type_resolver!($s, types.crate_libs, types.crate_types); + let resolver = get_module_type_resolver!($s, types.crate_types); // Blindly assume that the same imports where `supertrait` is defined are also // imported here. This will almost certainly break at some point, but it should be @@ -614,9 +685,16 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty write!(w, " {}", $s).unwrap(); maybe_write_generics(w, &$supertrait.generics, $generic_args, types, false); writeln!(w, " for {} {{", trait_name).unwrap(); - impl_trait_for_c!($supertrait, format!(".{}", $i), &resolver, $generic_args); writeln!(w, "}}").unwrap(); + + write!(w, "impl").unwrap(); + maybe_write_lifetime_generics(w, &$supertrait.generics, types); + write!(w, " {}", $s).unwrap(); + maybe_write_generics(w, &$supertrait.generics, $generic_args, types, false); + writeln!(w, " for {}Ref {{", trait_name).unwrap(); + impl_trait_for_c!($supertrait, format!(".0.{}", $i), &resolver, $generic_args); + writeln!(w, "}}").unwrap(); } } impl_supertrait!(s, supertrait, i, generic_args); @@ -643,12 +721,22 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty writeln!(w, " for {} {{", trait_name).unwrap(); impl_trait_for_c!(t, "", types, &syn::PathArguments::None); writeln!(w, "}}\n").unwrap(); + + writeln!(w, "pub struct {}Ref({});", trait_name, trait_name).unwrap(); + write!(w, "impl").unwrap(); + maybe_write_lifetime_generics(w, &t.generics, types); + write!(w, " rust{}", t.ident).unwrap(); + maybe_write_generics(w, &t.generics, &syn::PathArguments::None, types, false); + writeln!(w, " for {}Ref {{", trait_name).unwrap(); + impl_trait_for_c!(t, ".0", types, &syn::PathArguments::None); + writeln!(w, "}}\n").unwrap(); + writeln!(w, "// We're essentially a pointer already, or at least a set of pointers, so allow us to be used").unwrap(); writeln!(w, "// directly as a Deref trait in higher-level structs:").unwrap(); - writeln!(w, "impl core::ops::Deref for {} {{\n\ttype Target = Self;", trait_name).unwrap(); - writeln!(w, "\tfn deref(&self) -> &Self {{\n\t\tself\n\t}}\n}}").unwrap(); + writeln!(w, "impl core::ops::Deref for {} {{\n\ttype Target = {}Ref;", trait_name, trait_name).unwrap(); + writeln!(w, "\tfn deref(&self) -> &Self::Target {{\n\t\tunsafe {{ &*(self as *const _ as *const {}Ref) }}\n\t}}\n}}", trait_name).unwrap(); writeln!(w, "impl core::ops::DerefMut for {} {{", trait_name).unwrap(); - writeln!(w, "\tfn deref_mut(&mut self) -> &mut Self {{\n\t\tself\n\t}}\n}}").unwrap(); + writeln!(w, "\tfn deref_mut(&mut self) -> &mut {}Ref {{\n\t\tunsafe {{ &mut *(self as *mut _ as *mut {}Ref) }}\n\t}}\n}}", trait_name, trait_name).unwrap(); } writeln!(w, "/// Calls the free function if one is set").unwrap(); @@ -686,15 +774,26 @@ fn writeln_opaque(w: &mut W, ident: &syn::Ident, struct_name: writeln!(w, "\t/// this to be true and invalidate the object pointed to by inner.").unwrap(); writeln!(w, "\tpub is_owned: bool,").unwrap(); writeln!(w, "}}\n").unwrap(); + + writeln!(w, "impl core::ops::Deref for {} {{", struct_name).unwrap(); + writeln!(w, "\ttype Target = native{};", struct_name).unwrap(); + writeln!(w, "\tfn deref(&self) -> &Self::Target {{ unsafe {{ &*ObjOps::untweak_ptr(self.inner) }} }}").unwrap(); + writeln!(w, "}}").unwrap(); + + writeln!(w, "unsafe impl core::marker::Send for {} {{ }}", struct_name).unwrap(); + writeln!(w, "unsafe impl core::marker::Sync for {} {{ }}", struct_name).unwrap(); + writeln!(w, "impl Drop for {} {{\n\tfn drop(&mut self) {{", struct_name).unwrap(); writeln!(w, "\t\tif self.is_owned && !<*mut native{}>::is_null(self.inner) {{", ident).unwrap(); writeln!(w, "\t\t\tlet _ = unsafe {{ Box::from_raw(ObjOps::untweak_ptr(self.inner)) }};\n\t\t}}\n\t}}\n}}").unwrap(); + writeln!(w, "/// Frees any resources used by the {}, if is_owned is set and inner is non-NULL.", struct_name).unwrap(); writeln!(w, "#[no_mangle]\npub extern \"C\" fn {}_free(this_obj: {}) {{ }}", struct_name, struct_name).unwrap(); writeln!(w, "#[allow(unused)]").unwrap(); writeln!(w, "/// Used only if an object of this type is returned as a trait impl by a method").unwrap(); writeln!(w, "pub(crate) extern \"C\" fn {}_free_void(this_ptr: *mut c_void) {{", struct_name).unwrap(); writeln!(w, "\tlet _ = unsafe {{ Box::from_raw(this_ptr as *mut native{}) }};\n}}", struct_name).unwrap(); + writeln!(w, "#[allow(unused)]").unwrap(); writeln!(w, "impl {} {{", struct_name).unwrap(); writeln!(w, "\tpub(crate) fn get_native_ref(&self) -> &'static native{} {{", struct_name).unwrap(); @@ -709,6 +808,9 @@ fn writeln_opaque(w: &mut W, ident: &syn::Ident, struct_name: writeln!(w, "\t\tlet ret = ObjOps::untweak_ptr(self.inner);").unwrap(); writeln!(w, "\t\tself.inner = core::ptr::null_mut();").unwrap(); writeln!(w, "\t\tret").unwrap(); + writeln!(w, "\t}}").unwrap(); + writeln!(w, "\tpub(crate) fn as_ref_to(&self) -> Self {{").unwrap(); + writeln!(w, "\t\tSelf {{ inner: self.inner, is_owned: false }}").unwrap(); writeln!(w, "\t}}\n}}").unwrap(); write_cpp_wrapper(cpp_headers, &format!("{}", ident), true, None); @@ -813,6 +915,19 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct, if all_fields_settable { // Build a constructor! writeln!(w, "/// Constructs a new {} given each field", struct_name).unwrap(); + match &s.fields { + syn::Fields::Named(fields) => { + writeln_arg_docs(w, &[], "", types, Some(&gen_types), + fields.named.iter().map(|field| (format!("{}_arg", field.ident.as_ref().unwrap()), &field.ty)), + None); + }, + syn::Fields::Unnamed(fields) => { + writeln_arg_docs(w, &[], "", types, Some(&gen_types), + fields.unnamed.iter().enumerate().map(|(idx, field)| (format!("{}_arg", ('a' as u8 + idx as u8)), &field.ty)), + None); + }, + syn::Fields::Unit => {}, + } write!(w, "#[must_use]\n#[no_mangle]\npub extern \"C\" fn {}_new(", struct_name).unwrap(); match &s.fields { @@ -959,7 +1074,7 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet { if let Some(supertrait) = types.crate_types.traits.get(s) { supertrait_name = s.to_string(); - supertrait_resolver = get_module_type_resolver!(supertrait_name, types.crate_libs, types.crate_types); + supertrait_resolver = get_module_type_resolver!(supertrait_name, types.crate_types); gen_types.learn_associated_types(&supertrait, &supertrait_resolver); break; } @@ -970,7 +1085,7 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet(w: &mut W, w_uses: &mut HashSet(w: &mut W, w_uses: &mut HashSet crate::{} {{\n", ident, trait_obj.ident, ident, full_trait_path).unwrap(); writeln!(w, "\tcrate::{} {{", full_trait_path).unwrap(); - writeln!(w, "\t\tthis_arg: unsafe {{ ObjOps::untweak_ptr((*this_arg).inner) as *mut c_void }},").unwrap(); + if types.c_type_has_inner_from_path(&resolved_path) { + writeln!(w, "\t\tthis_arg: unsafe {{ ObjOps::untweak_ptr((*this_arg).inner) as *mut c_void }},").unwrap(); + } else { + writeln!(w, "\t\tthis_arg: unsafe {{ ObjOps::untweak_ptr(this_arg as *const {} as *mut {}) as *mut c_void }},", ident, ident).unwrap(); + } writeln!(w, "\t\tfree: None,").unwrap(); macro_rules! write_meth { @@ -1077,7 +1200,9 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet {}, ("Send", _, _) => {}, ("std::marker::Sync", _, _) => {}, ("std::marker::Send", _, _) => {}, - ("core::fmt::Debug", _, _) => {}, + ("core::fmt::Debug", _, _) => { + writeln!(w, "\t\tdebug_str: {}_debug_str_void,", ident).unwrap(); + }, (s, t, _) => { if let Some(supertrait_obj) = types.crate_types.traits.get(s) { macro_rules! write_impl_fields { @@ -1103,7 +1228,7 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet { if let Some(supertrait_obj) = types.crate_types.traits.get(s) { @@ -1159,28 +1284,29 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet { + takes_self = true; + break; + }, + syn::FnArg::Typed(ty) => { + if let syn::Pat::Ident(id) = &*ty.pat { + if format!("{}", id.ident) == "self" { + takes_self = true; + break; + } + } + } } } - let mut t_gen_args = String::new(); - for (idx, _) in $trait.generics.params.iter().enumerate() { - if idx != 0 { t_gen_args += ", " }; - t_gen_args += "_" - } - // rustc doesn't like <_> if the _ is actually a lifetime, so - // if all the parameters are lifetimes just skip it. - let mut nonlifetime_param = false; - for param in $trait.generics.params.iter() { - if let syn::GenericParam::Lifetime(_) = param {} - else { nonlifetime_param = true; } - } - if !nonlifetime_param { t_gen_args = String::new(); } + let mut t_gen_args_vec = Vec::new(); + maybe_write_type_non_lifetime_generics(&mut t_gen_args_vec, &$trait.generics, &trait_resolver); + let t_gen_args = String::from_utf8(t_gen_args_vec).unwrap(); if takes_self { - write!(w, ">::{}(unsafe {{ &mut *(this_arg as *mut native{}) }}, ", ident, $trait_path, t_gen_args, $m.sig.ident, ident).unwrap(); + write!(w, "::{}(unsafe {{ &mut *(this_arg as *mut native{}) }}, ", ident, $trait_path, t_gen_args, $m.sig.ident, ident).unwrap(); } else { - write!(w, ">::{}(", ident, $trait_path, t_gen_args, $m.sig.ident).unwrap(); + write!(w, "::{}(", ident, $trait_path, t_gen_args, $m.sig.ident).unwrap(); } let mut real_type = "".to_string(); @@ -1200,13 +1326,13 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet(w: &mut W, w_uses: &mut HashSet { - if types.crate_types.traits.get(s).is_some() { - assert!(!types.is_clonable(s)); // We don't currently support cloning with a clonable supertrait - writeln!(w, "\tnew_obj.{}.this_arg = new_obj.this_arg;", t).unwrap(); - writeln!(w, "\tnew_obj.{}.free = None;", t).unwrap(); + + fn seek_supertraits(w: &mut W, pfx: &str, tr: &syn::ItemTrait, types: &TypeResolver) { + walk_supertraits!(tr, Some(types), ( + (s, t, _) => { + if types.crate_types.traits.get(s).is_some() { + assert!(!types.is_clonable(s)); // We don't currently support cloning with a clonable supertrait + writeln!(w, "\tnew_obj.{}{}.this_arg = new_obj.this_arg;", pfx, t).unwrap(); + writeln!(w, "\tnew_obj.{}{}.free = None;", pfx, t).unwrap(); + let tr = types.crate_types.traits.get(s).unwrap(); + let resolver = get_module_type_resolver!(s, types.crate_types); + seek_supertraits(w, &format!("{}.", t), tr, &resolver); + } } - } - ) ); + ) ); + } + seek_supertraits(w, "", trait_obj, types); writeln!(w, "}}").unwrap(); } write!(w, "\n").unwrap(); @@ -1267,8 +1400,8 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet {} {{\n", ident, ident).unwrap(); write!(w, "\t{} {{ inner: ObjOps::heap_alloc(Default::default()), is_owned: true }}\n", ident).unwrap(); write!(w, "}}\n").unwrap(); - } else if path_matches_nongeneric(&trait_path.1, &["core", "cmp", "PartialEq"]) { - } else if path_matches_nongeneric(&trait_path.1, &["core", "cmp", "Eq"]) { + } else if full_trait_path_opt.as_ref().map(|s| s.as_str()) == Some("core::cmp::PartialEq") { + } else if full_trait_path_opt.as_ref().map(|s| s.as_str()) == Some("core::cmp::Eq") { writeln!(w, "/// Checks if two {}s contain equal inner contents.", ident).unwrap(); writeln!(w, "/// This ignores pointers and is_owned flags and looks at the values in fields.").unwrap(); if types.c_type_has_inner_from_path(&resolved_path) { @@ -1294,7 +1427,7 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet u64 {{\n", ident, ident).unwrap(); if types.c_type_has_inner_from_path(&resolved_path) { @@ -1314,8 +1447,8 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet Self {{").unwrap(); writeln!(w, "\t\tSelf {{").unwrap(); @@ -1326,7 +1459,7 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet *mut c_void {{", ident).unwrap(); - writeln!(w, "\tBox::into_raw(Box::new(unsafe {{ (*(this_ptr as *mut native{})).clone() }})) as *mut c_void", ident).unwrap(); + writeln!(w, "\tBox::into_raw(Box::new(unsafe {{ (*(this_ptr as *const native{})).clone() }})) as *mut c_void", ident).unwrap(); writeln!(w, "}}").unwrap(); writeln!(w, "#[no_mangle]").unwrap(); writeln!(w, "/// Creates a copy of the {}", ident).unwrap(); @@ -1368,7 +1501,15 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet Str {{", ident).unwrap(); + + write!(w, "\talloc::format!(\"{{:?}}\", unsafe {{ o as *const crate::{} }}).into()", resolved_path).unwrap(); + writeln!(w, "}}").unwrap(); + } else if full_trait_path_opt.as_ref().map(|s| s.as_str()) == Some("core::fmt::Display") || + path_matches_nongeneric(&trait_path.1, &["Display"]) + { writeln!(w, "#[no_mangle]").unwrap(); writeln!(w, "/// Get the string representation of a {} object", ident).unwrap(); writeln!(w, "pub extern \"C\" fn {}_to_str(o: &crate::{}) -> Str {{", ident, resolved_path).unwrap(); @@ -1417,10 +1558,23 @@ fn writeln_impl(w: &mut W, w_uses: &mut HashSet { + takes_self = true; + if r.mutability.is_some() { takes_mut_self = true; } + if r.reference.is_none() { takes_owned_self = true; } + break; + }, + syn::FnArg::Typed(ty) => { + if let syn::Pat::Ident(id) = &*ty.pat { + if format!("{}", id.ident) == "self" { + takes_self = true; + if id.mutability.is_some() { takes_mut_self = true; } + if id.by_ref.is_none() { takes_owned_self = true; } + break; + } + } + } } } if !takes_mut_self && !takes_self { @@ -1778,7 +1932,11 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type macro_rules! write_conv { ($fn_sig: expr, $to_c: expr, $ref: expr) => { - writeln!(w, "\t#[allow(unused)]\n\tpub(crate) fn {} {{\n\t\tmatch {} {{", $fn_sig, if $to_c { "native" } else { "self" }).unwrap(); + writeln!(w, "\t#[allow(unused)]\n\tpub(crate) fn {} {{", $fn_sig).unwrap(); + if $to_c && $ref { + writeln!(w, "\t\tlet native = unsafe {{ &*(native as *const _ as *const c_void as *const native{}) }};", e.ident).unwrap(); + } + writeln!(w, "\t\tmatch {} {{", if $to_c { "native" } else { "self" }).unwrap(); for var in e.variants.iter() { write!(w, "\t\t\t{}{}::{} ", if $to_c { "native" } else { "" }, e.ident, var.ident).unwrap(); let mut empty_tuple_variant = false; @@ -1902,7 +2060,10 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type } write_conv!(format!("into_native(self) -> native{}", e.ident), false, false); if is_clonable { - write_conv!(format!("from_native(native: &native{}) -> Self", e.ident), true, true); + let mut args = Vec::new(); + maybe_write_non_lifetime_generics(&mut args, &e.generics, &syn::PathArguments::None, &types); + let fn_line = format!("from_native(native: &{}Import{}) -> Self", e.ident, String::from_utf8(args).unwrap()); + write_conv!(fn_line, true, true); } write_conv!(format!("native_into(native: native{}) -> Self", e.ident), true, false); writeln!(w, "}}").unwrap(); @@ -1917,7 +2078,18 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{", e.ident, e.ident, e.ident).unwrap(); writeln!(w, "\torig.clone()").unwrap(); writeln!(w, "}}").unwrap(); + writeln!(w, "#[allow(unused)]").unwrap(); + writeln!(w, "/// Used only if an object of this type is returned as a trait impl by a method").unwrap(); + writeln!(w, "pub(crate) extern \"C\" fn {}_clone_void(this_ptr: *const c_void) -> *mut c_void {{", e.ident).unwrap(); + writeln!(w, "\tBox::into_raw(Box::new(unsafe {{ (*(this_ptr as *const {})).clone() }})) as *mut c_void", e.ident).unwrap(); + writeln!(w, "}}").unwrap(); } + + writeln!(w, "#[allow(unused)]").unwrap(); + writeln!(w, "/// Used only if an object of this type is returned as a trait impl by a method").unwrap(); + writeln!(w, "pub(crate) extern \"C\" fn {}_free_void(this_ptr: *mut c_void) {{", e.ident).unwrap(); + writeln!(w, "\tlet _ = unsafe {{ Box::from_raw(this_ptr as *mut {}) }};\n}}", e.ident).unwrap(); + w.write_all(&constr).unwrap(); write_cpp_wrapper(cpp_headers, &format!("{}", e.ident), needs_free, None); }