Try clone'ing the field before skipping exporting a field getter
[ldk-c-bindings] / c-bindings-gen / src / main.rs
index 76938baf2cf7ab44a0cf89b1b65713672d3112e6..fd32a1ca776610dd5813d7f6dc2fce41b6e5bb72 100644 (file)
@@ -163,7 +163,7 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
 
                                write!(w, "\tlet res: ").unwrap();
                                // At least in one case we need type annotations here, so provide them.
-                               types.write_rust_type(w, Some(generics), &res_ty);
+                               types.write_rust_type(w, Some(generics), &res_ty, false);
 
                                if t == "lightning::util::ser::ReadableArgs" {
                                        writeln!(w, " = crate::c_types::deserialize_obj_arg(ser, arg_conv);").unwrap();
@@ -484,7 +484,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                                                                                }
                                                                                _ => panic!("5"),
                                                                        }
-                                                                       $type_resolver.write_rust_type(w, Some(&gen_types), &*arg.ty);
+                                                                       $type_resolver.write_rust_type(w, Some(&gen_types), &*arg.ty, false);
                                                                }
                                                        }
                                                }
@@ -492,7 +492,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                                                match &m.sig.output {
                                                        syn::ReturnType::Type(_, rtype) => {
                                                                write!(w, " -> ").unwrap();
-                                                               $type_resolver.write_rust_type(w, Some(&gen_types), &*rtype)
+                                                               $type_resolver.write_rust_type(w, Some(&gen_types), &*rtype, false)
                                                        },
                                                        _ => {},
                                                }
@@ -735,6 +735,25 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
                                                write!(w, "inner_val").unwrap();
                                                types.write_to_c_conversion_inline_suffix(w, &ref_type, Some(&gen_types), true);
                                                writeln!(w, "\n}}").unwrap();
+                                       } else {
+                                               // If the type isn't reference-able, but is clonable, export a getter that just clones
+                                               if types.understood_c_type(&$field.ty, Some(&gen_types)) {
+                                                       let mut v = Vec::new();
+                                                       types.write_c_type(&mut v, &$field.ty, Some(&gen_types), true);
+                                                       let s = String::from_utf8(v).unwrap();
+                                                       if types.is_clonable(&s) {
+                                                               writeln_arg_docs(w, &$field.attrs, "", types, Some(&gen_types), vec![].drain(..), Some(&$field.ty));
+                                                               writeln!(w, "///\n/// Returns a copy of the field.").unwrap();
+                                                               write!(w, "#[no_mangle]\npub extern \"C\" fn {}_get_{}(this_ptr: &{}) -> {}", struct_name, $new_name, struct_name, s).unwrap();
+                                                               write!(w, " {{\n\tlet mut inner_val = this_ptr.get_native_mut_ref().{}.clone();\n\t", $real_name).unwrap();
+                                                               let local_var = types.write_to_c_conversion_new_var(w, &format_ident!("inner_val"), &$field.ty, Some(&gen_types), true);
+                                                               if local_var { write!(w, "\n\t").unwrap(); }
+                                                               types.write_to_c_conversion_inline_prefix(w, &$field.ty, Some(&gen_types), true);
+                                                               write!(w, "inner_val").unwrap();
+                                                               types.write_to_c_conversion_inline_suffix(w, &$field.ty, Some(&gen_types), true);
+                                                               writeln!(w, "\n}}").unwrap();
+                                                       }
+                                               }
                                        }
                                }
 
@@ -1594,8 +1613,37 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
 
        let mut needs_free = false;
        let mut constr = Vec::new();
+       let mut is_clonable = true;
 
-       writeln!(w, "#[must_use]\n#[derive(Clone)]\n#[repr(C)]\npub enum {} {{", e.ident).unwrap();
+       for var in e.variants.iter() {
+               if let syn::Fields::Named(fields) = &var.fields {
+                       needs_free = true;
+                       for field in fields.named.iter() {
+                               if export_status(&field.attrs) == ExportStatus::TestOnly { continue; }
+
+                               let mut ty_checks = Vec::new();
+                               types.write_c_type(&mut ty_checks, &field.ty, Some(&gen_types), false);
+                               if !types.is_clonable(&String::from_utf8(ty_checks).unwrap()) {
+                                       is_clonable = false;
+                               }
+                       }
+               } else if let syn::Fields::Unnamed(fields) = &var.fields {
+                       for field in fields.unnamed.iter() {
+                               let mut ty_checks = Vec::new();
+                               types.write_c_type(&mut ty_checks, &field.ty, Some(&gen_types), false);
+                               let ty = String::from_utf8(ty_checks).unwrap();
+                               if ty != "" && !types.is_clonable(&ty) {
+                                       is_clonable = false;
+                               }
+                       }
+               }
+       }
+
+       if is_clonable {
+               writeln!(w, "#[derive(Clone)]").unwrap();
+               types.crate_types.set_clonable(format!("{}::{}", types.module_path, e.ident));
+       }
+       writeln!(w, "#[must_use]\n#[repr(C)]\npub enum {} {{", e.ident).unwrap();
        for var in e.variants.iter() {
                assert_eq!(export_status(&var.attrs), ExportStatus::Export); // We can't partially-export a mirrored enum
                writeln_docs(w, &var.attrs, "\t");
@@ -1803,9 +1851,13 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                }
        }
 
-       write_conv!(format!("to_native(&self) -> native{}", e.ident), false, true);
+       if is_clonable {
+               write_conv!(format!("to_native(&self) -> native{}", e.ident), false, true);
+       }
        write_conv!(format!("into_native(self) -> native{}", e.ident), false, false);
-       write_conv!(format!("from_native(native: &native{}) -> Self", e.ident), true, true);
+       if is_clonable {
+               write_conv!(format!("from_native(native: &native{}) -> Self", e.ident), true, true);
+       }
        write_conv!(format!("native_into(native: native{}) -> Self", e.ident), true, false);
        writeln!(w, "}}").unwrap();
 
@@ -1813,11 +1865,13 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                writeln!(w, "/// Frees any resources used by the {}", e.ident).unwrap();
                writeln!(w, "#[no_mangle]\npub extern \"C\" fn {}_free(this_ptr: {}) {{ }}", e.ident, e.ident).unwrap();
        }
-       writeln!(w, "/// Creates a copy of the {}", e.ident).unwrap();
-       writeln!(w, "#[no_mangle]").unwrap();
-       writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{", e.ident, e.ident, e.ident).unwrap();
-       writeln!(w, "\torig.clone()").unwrap();
-       writeln!(w, "}}").unwrap();
+       if is_clonable {
+               writeln!(w, "/// Creates a copy of the {}", e.ident).unwrap();
+               writeln!(w, "#[no_mangle]").unwrap();
+               writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{", e.ident, e.ident, e.ident).unwrap();
+               writeln!(w, "\torig.clone()").unwrap();
+               writeln!(w, "}}").unwrap();
+       }
        w.write_all(&constr).unwrap();
        write_cpp_wrapper(cpp_headers, &format!("{}", e.ident), needs_free, None);
 }