[bindings] Tuples!
authorMatt Corallo <git@bluematt.me>
Tue, 5 Jan 2021 01:57:19 +0000 (20:57 -0500)
committerMatt Corallo <git@bluematt.me>
Tue, 5 Jan 2021 02:09:23 +0000 (21:09 -0500)
c-bindings-gen/src/blocks.rs
c-bindings-gen/src/types.rs
lightning-c-bindings/src/c_types/mod.rs

index 01e6d1f70c2fa286e6ae1b57c3c407a9700d941b..e9aca1140d4c2c17935f7b5b291bb16aade25d76 100644 (file)
@@ -195,6 +195,65 @@ 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]) {
+       writeln!(w, "#[repr(C)]").unwrap();
+       writeln!(w, "pub struct {} {{", mangled_container).unwrap();
+       for (idx, ty) in types.iter().enumerate() {
+               writeln!(w, "\tpub {}: {},", ('a' as u8 + idx as u8) as char, ty).unwrap();
+       }
+       writeln!(w, "}}").unwrap();
+
+       let mut needs_clone = true;
+       let mut tuple_str = "(".to_owned();
+       for (idx, ty) in types.iter().enumerate() {
+               if idx != 0 { tuple_str += ", "; }
+               tuple_str += ty;
+               if !ty.starts_with("u") ||
+                       ty.len() > 3 || ty.len() < 2 ||
+                       ty.as_bytes()[1] < '0' as u8 || ty.as_bytes()[1] > '9' as u8 ||
+                       (ty.len() == 3 && (ty.as_bytes()[2] < '0' as u8 || ty.as_bytes()[2] > '9' as u8)) {
+                               // For non-uXX types, we don't implement clone
+                               needs_clone = false;
+               }
+       }
+       tuple_str += ")";
+
+       writeln!(w, "impl From<{}> for {} {{", tuple_str, mangled_container).unwrap();
+       writeln!(w, "\tfn from (tup: {}) -> Self {{", tuple_str).unwrap();
+       writeln!(w, "\t\tSelf {{").unwrap();
+       for idx in 0..types.len() {
+               writeln!(w, "\t\t\t{}: tup.{},", ('a' as u8 + idx as u8) as char, idx).unwrap();
+       }
+       writeln!(w, "\t\t}}").unwrap();
+       writeln!(w, "\t}}").unwrap();
+       writeln!(w, "}}").unwrap();
+       writeln!(w, "impl {} {{", mangled_container).unwrap();
+       writeln!(w, "\t#[allow(unused)] pub(crate) fn to_rust(mut self) -> {} {{", tuple_str).unwrap();
+       write!(w, "\t\t(").unwrap();
+       for idx in 0..types.len() {
+               write!(w, "{}self.{}", if idx != 0 {", "} else {""}, ('a' as u8 + idx as u8) as char).unwrap();
+       }
+       writeln!(w, ")").unwrap();
+       writeln!(w, "\t}}").unwrap();
+       writeln!(w, "}}").unwrap();
+
+       if needs_clone {
+               writeln!(w, "impl Clone for {} {{", mangled_container).unwrap();
+               writeln!(w, "\tfn clone(&self) -> Self {{").unwrap();
+               writeln!(w, "\t\tSelf {{").unwrap();
+               for idx in 0..types.len() {
+                       writeln!(w, "\t\t\t{}: self.{}.clone(),", ('a' as u8 + idx as u8) as char, ('a' as u8 + idx as u8) as char).unwrap();
+               }
+               writeln!(w, "\t\t}}").unwrap();
+               writeln!(w, "\t}}").unwrap();
+               writeln!(w, "}}").unwrap();
+       }
+
+       writeln!(w, "#[no_mangle]").unwrap();
+       writeln!(w, "pub extern \"C\" fn {}_free(_res: {}) {{ }}", mangled_container, mangled_container).unwrap();
+}
+
 /// Prints the docs from a given attribute list unless its tagged no export
 pub fn writeln_docs<W: std::io::Write>(w: &mut W, attrs: &[syn::Attribute], prefix: &str) {
        for attr in attrs.iter() {
index 4e420267f238b92b19934a8dda337551f27c682b..b6321a350a1c65138b88536406a46804847e1923 100644 (file)
@@ -1742,9 +1742,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                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();
+                                       let mut inner_args = Vec::new();
+                                       for arg in tup.elems.iter() {
+                                               inner_args.push(arg);
+                                       }
+                                       assert!(self.write_c_mangled_container_path(w, inner_args, generics, &format!("{}Tuple", tup.elems.len()), is_ref, false, false));
                                }
                        } else if let syn::Type::Path(p_arg) = t {
                                let resolved_generic = self.resolve_path(&p_arg.path, generics);
@@ -1841,20 +1843,28 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                let mut a_ty: Vec<u8> = Vec::new();
                                self.write_template_generics(&mut a_ty, &mut args.iter().map(|t| *t), generics, is_ref, true);
                                write_vec_block(&mut created_container, &mangled_container, &String::from_utf8(a_ty).unwrap());
-                       } else {
-                               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();
-
-                               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();
+                       } else if container_type.ends_with("Tuple") {
+                               let mut tuple_args = Vec::new();
+                               for arg in args.iter() {
+                                       let mut ty: Vec<u8> = Vec::new();
+                                       self.write_template_generics(&mut ty, &mut [arg].iter().map(|t| **t), generics, is_ref, true);
+                                       tuple_args.push(String::from_utf8(ty).unwrap());
+                               }
+                               write_tuple_block(&mut created_container, &mangled_container, &tuple_args);
 
-                               if !self.write_template_constructor(&mut created_container, container_type, &mangled_container, &args, generics, is_ref) {
-                                       return false;
+                               write!(&mut created_container, "#[no_mangle]\npub extern \"C\" fn {}_new(", mangled_container).unwrap();
+                               for (idx, gen) in args.iter().enumerate() {
+                                       write!(&mut created_container, "{}{}: ", if idx != 0 { ", " } else { "" }, ('a' as u8 + idx as u8) as char).unwrap();
+                                       if !self.write_c_type_intern(&mut created_container, gen, generics, false, false, false) { return false; }
+                               }
+                               writeln!(&mut created_container, ") -> {} {{", mangled_container).unwrap();
+                               write!(&mut created_container, "\t{} {{ ", mangled_container).unwrap();
+                               for idx in 0..args.len() {
+                                       write!(&mut created_container, "{}, ", ('a' as u8 + idx as u8) as char).unwrap();
                                }
+                               writeln!(&mut created_container, "}}\n}}\n").unwrap();
+                       } else {
+                               unreachable!();
                        }
                        self.crate_types.templates_defined.insert(mangled_container.clone(), true);
 
@@ -1953,7 +1963,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 {
@@ -1961,6 +1970,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; }
index 006f323f6a0f73e5255cd54d9808bade257c85b7..82a96fc157eacc72bfe1fdbecc258a2cd04a3ec8 100644 (file)
@@ -295,56 +295,6 @@ impl<O, E> Drop for CResultTempl<O, E> {
        }
 }
 
-#[repr(C)]
-pub struct C2TupleTempl<A, B> {
-       pub a: A,
-       pub b: B,
-}
-impl<A, B> From<(A, B)> for C2TupleTempl<A, B> {
-       fn from(tup: (A, B)) -> Self {
-               Self {
-                       a: tup.0,
-                       b: tup.1,
-               }
-       }
-}
-impl<A, B> C2TupleTempl<A, B> {
-       pub(crate) fn to_rust(mut self) -> (A, B) {
-               (self.a, self.b)
-       }
-}
-pub extern "C" fn C2TupleTempl_free<A, B>(_res: C2TupleTempl<A, B>) { }
-impl <A: Clone, B: Clone> Clone for C2TupleTempl<A, B> {
-       fn clone(&self) -> Self {
-               Self {
-                       a: self.a.clone(),
-                       b: self.b.clone()
-               }
-       }
-}
-
-#[repr(C)]
-pub struct C3TupleTempl<A, B, C> {
-       pub a: A,
-       pub b: B,
-       pub c: C,
-}
-impl<A, B, C> From<(A, B, C)> for C3TupleTempl<A, B, C> {
-       fn from(tup: (A, B, C)) -> Self {
-               Self {
-                       a: tup.0,
-                       b: tup.1,
-                       c: tup.2,
-               }
-       }
-}
-impl<A, B, C> C3TupleTempl<A, B, C> {
-       pub(crate) fn to_rust(mut self) -> (A, B, C) {
-               (self.a, self.b, self.c)
-       }
-}
-pub extern "C" fn C3TupleTempl_free<A, B, C>(_res: C3TupleTempl<A, B, C>) { }
-
 /// Utility to make it easy to set a pointer to null and get its original value in line.
 pub(crate) trait TakePointer<T> {
        fn take_ptr(&mut self) -> T;