Support converting Option<&[]> to C
authorMatt Corallo <git@bluematt.me>
Sun, 31 Oct 2021 23:14:41 +0000 (23:14 +0000)
committerMatt Corallo <git@bluematt.me>
Tue, 2 Nov 2021 16:54:45 +0000 (16:54 +0000)
c-bindings-gen/src/types.rs
lightning-c-bindings/src/c_types/mod.rs

index 5d36ed5795eb9b6ff1860a9b9c802d9edfd003fe..14fd918e2be81cb267a01f08f18206bf0bbd1b7b 100644 (file)
@@ -1373,6 +1373,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                        }
                                }
                                if let Some(t) = single_contained {
+                                       if let syn::Type::Reference(syn::TypeReference { elem, .. }) = t {
+                                               if let syn::Type::Slice(_) = &**elem {
+                                                       return Some(("if ", vec![
+                                                                       (".is_none() { SmartPtr::null() } else { SmartPtr::from_obj(".to_string(),
+                                                                        format!("({}.unwrap())", var_access))
+                                                               ], ") }", ContainerPrefixLocation::PerConv));
+                                               }
+                                       }
                                        let mut v = Vec::new();
                                        self.write_empty_rust_val(generics, &mut v, t);
                                        let s = String::from_utf8(v).unwrap();
@@ -2106,7 +2114,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
 
                                if let Some((prefix, conversions, suffix, prefix_location)) = container_lookup(&$container_type, is_ref && ty_has_inner, only_contained_type, ident, var) {
                                        assert_eq!(conversions.len(), $args_len);
-                                       write!(w, "let mut local_{}{} = ", ident, if !to_c && needs_ref_map {"_base"} else { "" }).unwrap();
+                                       write!(w, "let mut local_{}{} = ", ident,
+                                               if (!to_c && needs_ref_map) || (to_c && $container_type == "Option" && contains_slice) {"_base"} else { "" }).unwrap();
                                        if prefix_location == ContainerPrefixLocation::OutsideConv {
                                                var_prefix(w, $args_iter().next().unwrap(), generics, is_ref, ptr_for_ref, true);
                                        }
@@ -2131,7 +2140,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                                        write!(w, "ObjOps::heap_alloc(").unwrap();
                                                }
 
-                                               write!(w, "{}{}", if contains_slice { "local_" } else { "" }, if new_var { new_var_name } else { var_access }).unwrap();
+                                               write!(w, "{}{}", if contains_slice && !to_c { "local_" } else { "" }, if new_var { new_var_name } else { var_access }).unwrap();
                                                if prefix_location == ContainerPrefixLocation::PerConv {
                                                        var_suffix(w, conv_ty, generics, is_ref && ty_has_inner, ptr_for_ref, false);
                                                } else if !is_ref && !needs_ref_map && to_c && only_contained_has_inner {
@@ -2150,6 +2159,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                                        write!(w, ".map(|a| &a[..])").unwrap();
                                                }
                                                write!(w, ";").unwrap();
+                                       } else if to_c && $container_type == "Option" && contains_slice {
+                                               write!(w, " let mut local_{} = *local_{}_base;", ident, ident).unwrap();
                                        }
                                        return true;
                                }
index 274981da8e02a22c3a7dc24e7e61aba72ea9e5f5..69319563b72a8c2fd284fda2de9f7a9de460731f 100644 (file)
@@ -607,3 +607,28 @@ pub(crate) mod ObjOps {
                }
        }
 }
+
+pub(crate) struct SmartPtr<T> {
+       ptr: *mut T,
+}
+impl<T> SmartPtr<T> {
+       pub(crate) fn from_obj(o: T) -> Self {
+               Self { ptr: Box::into_raw(Box::new(o)) }
+       }
+       pub(crate) fn null() -> Self {
+               Self { ptr: std::ptr::null_mut() }
+       }
+}
+impl<T> Drop for SmartPtr<T> {
+       fn drop(&mut self) {
+               if self.ptr != std::ptr::null_mut() {
+                       unsafe { Box::from_raw(self.ptr); }
+               }
+       }
+}
+impl<T> std::ops::Deref for SmartPtr<T> {
+       type Target = *mut T;
+       fn deref(&self) -> &*mut T {
+               &self.ptr
+       }
+}