Merge pull request #19 from TheBlueMatt/2021-04-invoice-incl
[ldk-c-bindings] / c-bindings-gen / src / blocks.rs
index b6622617731fb14947cfe00e3f3f41582307a21b..82b10ad831bd4ca2ef21ec3c1d9804d5dbe6e26c 100644 (file)
@@ -11,7 +11,9 @@
 
 use std::fs::File;
 use std::io::Write;
-use proc_macro2::{TokenTree, Span};
+
+use proc_macro2::TokenTree;
+use quote::format_ident;
 
 use crate::types::*;
 
@@ -43,14 +45,19 @@ pub fn write_cpp_wrapper(cpp_header_file: &mut File, ty: &str, has_destructor: b
 /// Writes out a C-callable concrete Result<A, B> struct and utility methods
 pub fn write_result_block<W: std::io::Write>(w: &mut W, mangled_container: &str, ok_type: &str, err_type: &str, clonable: bool) {
        writeln!(w, "#[repr(C)]").unwrap();
+       writeln!(w, "/// The contents of {}", mangled_container).unwrap();
        writeln!(w, "pub union {}Ptr {{", mangled_container).unwrap();
        if ok_type != "()" {
+               writeln!(w, "\t/// A pointer to the contents in the success state.").unwrap();
+               writeln!(w, "\t/// Reading from this pointer when `result_ok` is not set is undefined.").unwrap();
                writeln!(w, "\tpub result: *mut {},", ok_type).unwrap();
        } else {
                writeln!(w, "\t/// Note that this value is always NULL, as there are no contents in the OK variant").unwrap();
                writeln!(w, "\tpub result: *mut std::ffi::c_void,").unwrap();
        }
        if err_type != "()" {
+               writeln!(w, "\t/// A pointer to the contents in the error state.").unwrap();
+               writeln!(w, "\t/// Reading from this pointer when `result_ok` is set is undefined.").unwrap();
                writeln!(w, "\tpub err: *mut {},", err_type).unwrap();
        } else {
                writeln!(w, "\t/// Note that this value is always NULL, as there are no contents in the Err variant").unwrap();
@@ -58,15 +65,23 @@ pub fn write_result_block<W: std::io::Write>(w: &mut W, mangled_container: &str,
        }
        writeln!(w, "}}").unwrap();
        writeln!(w, "#[repr(C)]").unwrap();
+       writeln!(w, "/// A {} represents the result of a fallible operation,", mangled_container).unwrap();
+       writeln!(w, "/// containing a {} on success and a {} on failure.", ok_type, err_type).unwrap();
+       writeln!(w, "/// `result_ok` indicates the overall state, and the contents are provided via `contents`.").unwrap();
        writeln!(w, "pub struct {} {{", mangled_container).unwrap();
+       writeln!(w, "\t/// The contents of this {}, accessible via either", mangled_container).unwrap();
+       writeln!(w, "\t/// `err` or `result` depending on the state of `result_ok`.").unwrap();
        writeln!(w, "\tpub contents: {}Ptr,", mangled_container).unwrap();
+       writeln!(w, "\t/// Whether this {} represents a success state.", mangled_container).unwrap();
        writeln!(w, "\tpub result_ok: bool,").unwrap();
        writeln!(w, "}}").unwrap();
 
        writeln!(w, "#[no_mangle]").unwrap();
        if ok_type != "()" {
+               writeln!(w, "/// Creates a new {} in the success state.", mangled_container).unwrap();
                writeln!(w, "pub extern \"C\" fn {}_ok(o: {}) -> {} {{", mangled_container, ok_type, mangled_container).unwrap();
        } else {
+               writeln!(w, "/// Creates a new {} in the success state.", mangled_container).unwrap();
                writeln!(w, "pub extern \"C\" fn {}_ok() -> {} {{", mangled_container, mangled_container).unwrap();
        }
        writeln!(w, "\t{} {{", mangled_container).unwrap();
@@ -83,8 +98,10 @@ pub fn write_result_block<W: std::io::Write>(w: &mut W, mangled_container: &str,
 
        writeln!(w, "#[no_mangle]").unwrap();
        if err_type != "()" {
+               writeln!(w, "/// Creates a new {} in the error state.", mangled_container).unwrap();
                writeln!(w, "pub extern \"C\" fn {}_err(e: {}) -> {} {{", mangled_container, err_type, mangled_container).unwrap();
        } else {
+               writeln!(w, "/// Creates a new {} in the error state.", mangled_container).unwrap();
                writeln!(w, "pub extern \"C\" fn {}_err() -> {} {{", mangled_container, mangled_container).unwrap();
        }
        writeln!(w, "\t{} {{", mangled_container).unwrap();
@@ -100,6 +117,7 @@ pub fn write_result_block<W: std::io::Write>(w: &mut W, mangled_container: &str,
        writeln!(w, "}}").unwrap();
 
        writeln!(w, "#[no_mangle]").unwrap();
+       writeln!(w, "/// Frees any resources used by the {}.", mangled_container).unwrap();
        writeln!(w, "pub extern \"C\" fn {}_free(_res: {}) {{ }}", mangled_container, mangled_container).unwrap();
        writeln!(w, "impl Drop for {} {{", mangled_container).unwrap();
        writeln!(w, "\tfn drop(&mut self) {{").unwrap();
@@ -119,12 +137,8 @@ pub fn write_result_block<W: std::io::Write>(w: &mut W, mangled_container: &str,
        writeln!(w, "\t}}").unwrap();
        writeln!(w, "}}").unwrap();
 
-       // TODO: Templates should use () now that they can, too
-       let templ_ok_type = if ok_type != "()" { ok_type } else { "u8" };
-       let templ_err_type = if err_type != "()" { err_type } else { "u8" };
-
-       writeln!(w, "impl From<crate::c_types::CResultTempl<{}, {}>> for {} {{", templ_ok_type, templ_err_type, mangled_container).unwrap();
-       writeln!(w, "\tfn from(mut o: crate::c_types::CResultTempl<{}, {}>) -> Self {{", templ_ok_type, templ_err_type).unwrap();
+       writeln!(w, "impl From<crate::c_types::CResultTempl<{}, {}>> for {} {{", ok_type, err_type, mangled_container).unwrap();
+       writeln!(w, "\tfn from(mut o: crate::c_types::CResultTempl<{}, {}>) -> Self {{", ok_type, err_type).unwrap();
        writeln!(w, "\t\tlet contents = if o.result_ok {{").unwrap();
        if ok_type != "()" {
                writeln!(w, "\t\t\tlet result = unsafe {{ o.contents.result }};").unwrap();
@@ -176,6 +190,8 @@ pub fn write_result_block<W: std::io::Write>(w: &mut W, mangled_container: &str,
                writeln!(w, "\t}}").unwrap();
                writeln!(w, "}}").unwrap();
                writeln!(w, "#[no_mangle]").unwrap();
+               writeln!(w, "/// Creates a new {} which has the same data as `orig`", mangled_container).unwrap();
+               writeln!(w, "/// but with all dynamically-allocated buffers duplicated in new buffers.").unwrap();
                writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{ orig.clone() }}", mangled_container, mangled_container, mangled_container).unwrap();
        }
 }
@@ -183,8 +199,13 @@ pub fn write_result_block<W: std::io::Write>(w: &mut W, mangled_container: &str,
 /// Writes out a C-callable concrete Vec<A> struct and utility methods
 pub fn write_vec_block<W: std::io::Write>(w: &mut W, mangled_container: &str, inner_type: &str, clonable: bool) {
        writeln!(w, "#[repr(C)]").unwrap();
+       writeln!(w, "/// A dynamically-allocated array of {}s of arbitrary size.", inner_type).unwrap();
+       writeln!(w, "/// This corresponds to std::vector in C++").unwrap();
        writeln!(w, "pub struct {} {{", mangled_container).unwrap();
+       writeln!(w, "\t/// The elements in the array.").unwrap();
+       writeln!(w, "\t/// If datalen is non-0 this must be a valid, non-NULL pointer allocated by malloc().").unwrap();
        writeln!(w, "\tpub data: *mut {},", inner_type).unwrap();
+       writeln!(w, "\t/// The number of elements pointed to by `data`.").unwrap();
        writeln!(w, "\tpub datalen: usize").unwrap();
        writeln!(w, "}}").unwrap();
 
@@ -210,6 +231,7 @@ pub fn write_vec_block<W: std::io::Write>(w: &mut W, mangled_container: &str, in
        writeln!(w, "}}").unwrap();
 
        writeln!(w, "#[no_mangle]").unwrap();
+       writeln!(w, "/// Frees the buffer pointed to by `data` if `datalen` is non-0.").unwrap();
        writeln!(w, "pub extern \"C\" fn {}_free(_res: {}) {{ }}", mangled_container, mangled_container).unwrap();
        writeln!(w, "impl Drop for {} {{", mangled_container).unwrap();
        writeln!(w, "\tfn drop(&mut self) {{").unwrap();
@@ -232,8 +254,10 @@ pub fn write_vec_block<W: std::io::Write>(w: &mut W, mangled_container: &str, in
 /// Writes out a C-callable concrete (A, B, ...) struct and utility methods
 pub fn write_tuple_block<W: std::io::Write>(w: &mut W, mangled_container: &str, types: &[String], clonable: bool) {
        writeln!(w, "#[repr(C)]").unwrap();
+       writeln!(w, "/// A tuple of {} elements. See the individual fields for the types contained.", types.len()).unwrap();
        writeln!(w, "pub struct {} {{", mangled_container).unwrap();
        for (idx, ty) in types.iter().enumerate() {
+               writeln!(w, "\t/// The element at position {}", idx).unwrap();
                writeln!(w, "\tpub {}: {},", ('a' as u8 + idx as u8) as char, ty).unwrap();
        }
        writeln!(w, "}}").unwrap();
@@ -275,9 +299,12 @@ pub fn write_tuple_block<W: std::io::Write>(w: &mut W, mangled_container: &str,
                writeln!(w, "\t}}").unwrap();
                writeln!(w, "}}").unwrap();
                writeln!(w, "#[no_mangle]").unwrap();
+               writeln!(w, "/// Creates a new tuple which has the same data as `orig`").unwrap();
+               writeln!(w, "/// but with all dynamically-allocated buffers duplicated in new buffers.").unwrap();
                writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{ orig.clone() }}", mangled_container, mangled_container, mangled_container).unwrap();
        }
 
+       writeln!(w, "/// Creates a new {} from the contained elements.", mangled_container).unwrap();
        write!(w, "#[no_mangle]\npub extern \"C\" fn {}_new(", mangled_container).unwrap();
        for (idx, gen) in types.iter().enumerate() {
                write!(w, "{}{}: ", if idx != 0 { ", " } else { "" }, ('a' as u8 + idx as u8) as char).unwrap();
@@ -292,6 +319,7 @@ pub fn write_tuple_block<W: std::io::Write>(w: &mut W, mangled_container: &str,
        writeln!(w, "}}\n}}\n").unwrap();
 
        writeln!(w, "#[no_mangle]").unwrap();
+       writeln!(w, "/// Frees any resources used by the {}.", mangled_container).unwrap();
        writeln!(w, "pub extern \"C\" fn {}_free(_res: {}) {{ }}", mangled_container, mangled_container).unwrap();
 }
 
@@ -301,8 +329,11 @@ pub fn write_option_block<W: std::io::Write>(w: &mut W, mangled_container: &str,
        if clonable {
                writeln!(w, "#[derive(Clone)]").unwrap();
        }
+       writeln!(w, "/// An enum which can either contain a {} or not", inner_type).unwrap();
        writeln!(w, "pub enum {} {{", mangled_container).unwrap();
+       writeln!(w, "\t/// When we're in this state, this {} contains a {}", mangled_container, inner_type).unwrap();
        writeln!(w, "\tSome({}),", inner_type).unwrap();
+       writeln!(w, "\t/// When we're in this state, this {} contains nothing", mangled_container).unwrap();
        writeln!(w, "\tNone").unwrap();
        writeln!(w, "}}").unwrap();
 
@@ -316,9 +347,24 @@ pub fn write_option_block<W: std::io::Write>(w: &mut W, mangled_container: &str,
        writeln!(w, "}}").unwrap();
 
        writeln!(w, "#[no_mangle]").unwrap();
+       writeln!(w, "/// Constructs a new {} containing a {}", mangled_container, inner_type).unwrap();
+       writeln!(w, "pub extern \"C\" fn {}_some(o: {}) -> {} {{", mangled_container, inner_type, mangled_container).unwrap();
+       writeln!(w, "\t{}::Some(o)", mangled_container).unwrap();
+       writeln!(w, "}}").unwrap();
+
+       writeln!(w, "#[no_mangle]").unwrap();
+       writeln!(w, "/// Constructs a new {} containing nothing", mangled_container).unwrap();
+       writeln!(w, "pub extern \"C\" fn {}_none() -> {} {{", mangled_container, mangled_container).unwrap();
+       writeln!(w, "\t{}::None", mangled_container).unwrap();
+       writeln!(w, "}}").unwrap();
+
+       writeln!(w, "#[no_mangle]").unwrap();
+       writeln!(w, "/// Frees any resources associated with the {}, if we are in the Some state", inner_type).unwrap();
        writeln!(w, "pub extern \"C\" fn {}_free(_res: {}) {{ }}", mangled_container, mangled_container).unwrap();
        if clonable {
                writeln!(w, "#[no_mangle]").unwrap();
+               writeln!(w, "/// Creates a new {} which has the same data as `orig`", mangled_container).unwrap();
+               writeln!(w, "/// but with all dynamically-allocated buffers duplicated in new buffers.").unwrap();
                writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{ orig.clone() }}", mangled_container, mangled_container, mangled_container).unwrap();
        }
 }
@@ -392,14 +438,16 @@ pub fn write_method_params<W: std::io::Write>(w: &mut W, sig: &syn::Signature, t
        for inp in sig.inputs.iter() {
                match inp {
                        syn::FnArg::Receiver(recv) => {
-                               if !recv.attrs.is_empty() || recv.reference.is_none() { unimplemented!(); }
-                               write!(w, "this_arg: {}{}",
-                                       match (self_ptr, recv.mutability.is_some()) {
-                                               (true, true) => "*mut ",
-                                               (true, false) => "*const ",
-                                               (false, true) => "&mut ",
-                                               (false, false) => "&",
-                                       }, this_param).unwrap();
+                               if !recv.attrs.is_empty() { unimplemented!(); }
+                               write!(w, "{}this_arg: {}{}", if recv.reference.is_none() { "mut " } else { "" },
+                                       if recv.reference.is_some() {
+                                               match (self_ptr, recv.mutability.is_some()) {
+                                                       (true, true) => "*mut ",
+                                                       (true, false) => "*const ",
+                                                       (false, true) => "&mut ",
+                                                       (false, false) => "&",
+                                               }
+                                       } else { "" }, this_param).unwrap();
                                assert!(first_arg);
                                first_arg = false;
                        },
@@ -438,12 +486,7 @@ pub fn write_method_params<W: std::io::Write>(w: &mut W, sig: &syn::Signature, t
                                        return;
                                }
                        }
-                       if let syn::Type::Reference(r) = &**rtype {
-                               // We can't return a reference, cause we allocate things on the stack.
-                               types.write_c_type(w, &*r.elem, generics, true);
-                       } else {
-                               types.write_c_type(w, &*rtype, generics, true);
-                       }
+                       types.write_c_type(w, &*rtype, generics, true);
                },
                _ => {},
        }
@@ -454,7 +497,7 @@ pub fn write_method_params<W: std::io::Write>(w: &mut W, sig: &syn::Signature, t
 /// mut ret = " assuming the next print will be the unmapped Rust function to call followed by the
 /// parameters we mapped to/from C here.
 pub fn write_method_var_decl_body<W: std::io::Write>(w: &mut W, sig: &syn::Signature, extra_indent: &str, types: &TypeResolver, generics: Option<&GenericTypes>, to_c: bool) {
-       let mut num_unused = 0;
+       let mut num_unused = 0u32;
        for inp in sig.inputs.iter() {
                match inp {
                        syn::FnArg::Receiver(_) => {},
@@ -483,7 +526,7 @@ pub fn write_method_var_decl_body<W: std::io::Write>(w: &mut W, sig: &syn::Signa
                                        },
                                        syn::Pat::Wild(w) => {
                                                if !w.attrs.is_empty() { unimplemented!(); }
-                                               write_new_var!(syn::Ident::new(&format!("unused_{}", num_unused), Span::call_site()), *arg.ty);
+                                               write_new_var!(format_ident!("unused_{}", num_unused), *arg.ty);
                                                num_unused += 1;
                                        },
                                        _ => unimplemented!(),
@@ -511,8 +554,9 @@ pub fn write_method_call_params<W: std::io::Write>(w: &mut W, sig: &syn::Signatu
        for inp in sig.inputs.iter() {
                match inp {
                        syn::FnArg::Receiver(recv) => {
-                               if !recv.attrs.is_empty() || recv.reference.is_none() { unimplemented!(); }
+                               if !recv.attrs.is_empty() { unimplemented!(); }
                                if to_c {
+                                       if recv.reference.is_none() { unimplemented!(); }
                                        write!(w, "self.this_arg").unwrap();
                                        first_arg = false;
                                }
@@ -576,7 +620,7 @@ pub fn write_method_call_params<W: std::io::Write>(w: &mut W, sig: &syn::Signatu
                                // If we're returning "Self" (and not "Self::X"), just do it manually
                                write!(w, "{} {{ inner: Box::into_raw(Box::new(ret)), is_owned: true }}", this_type).unwrap();
                        } else if to_c {
-                               let new_var = types.write_from_c_conversion_new_var(w, &syn::Ident::new("ret", Span::call_site()), rtype, generics);
+                               let new_var = types.write_from_c_conversion_new_var(w, &format_ident!("ret"), rtype, generics);
                                if new_var {
                                        write!(w, "\n\t{}", extra_indent).unwrap();
                                }
@@ -584,13 +628,12 @@ pub fn write_method_call_params<W: std::io::Write>(w: &mut W, sig: &syn::Signatu
                                write!(w, "ret").unwrap();
                                types.write_from_c_conversion_suffix(w, &*rtype, generics);
                        } else {
-                               let ret_returned = if let syn::Type::Reference(_) = &**rtype { true } else { false };
-                               let new_var = types.write_to_c_conversion_new_var(w, &syn::Ident::new("ret", Span::call_site()), &rtype, generics, true);
+                               let new_var = types.write_to_c_conversion_new_var(w, &format_ident!("ret"), &rtype, generics, true);
                                if new_var {
                                        write!(w, "\n\t{}", extra_indent).unwrap();
                                }
                                types.write_to_c_conversion_inline_prefix(w, &rtype, generics, true);
-                               write!(w, "{}ret", if ret_returned && !new_var { "*" } else { "" }).unwrap();
+                               write!(w, "ret").unwrap();
                                types.write_to_c_conversion_inline_suffix(w, &rtype, generics, true);
                        }
                }
@@ -601,7 +644,7 @@ pub fn write_method_call_params<W: std::io::Write>(w: &mut W, sig: &syn::Signatu
 /// Prints concrete generic parameters for a struct/trait/function, including the less-than and
 /// greater-than symbols, if any generic parameters are defined.
 pub fn maybe_write_generics<W: std::io::Write>(w: &mut W, generics: &syn::Generics, types: &TypeResolver, concrete_lifetimes: bool) {
-       let mut gen_types = GenericTypes::new();
+       let mut gen_types = GenericTypes::new(None);
        assert!(gen_types.learn_generics(generics, types));
        if !generics.params.is_empty() {
                write!(w, "<").unwrap();