Support Option<()> (and &Option<()>) incl conversion and printing
authorMatt Corallo <git@bluematt.me>
Sat, 18 Dec 2021 02:07:52 +0000 (02:07 +0000)
committerMatt Corallo <git@bluematt.me>
Sun, 19 Dec 2021 23:58:04 +0000 (23:58 +0000)
c-bindings-gen/src/blocks.rs
c-bindings-gen/src/types.rs

index 6e6b897e9c13ce9cd9b21fdda30cbbbf28870a39..b2f952be5fa1cb3fdcb6f51a6d677d7680f59d60 100644 (file)
@@ -346,27 +346,38 @@ pub fn write_option_block<W: std::io::Write>(w: &mut W, mangled_container: &str,
        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();
+       if inner_type != "" {
+               writeln!(w, "\tSome({}),", inner_type).unwrap();
+       } else {
+               writeln!(w, "\tSome,").unwrap();
+       }
        writeln!(w, "\t/// When we're in this state, this {} contains nothing", mangled_container).unwrap();
        writeln!(w, "\tNone").unwrap();
        writeln!(w, "}}").unwrap();
 
        writeln!(w, "impl {} {{", mangled_container).unwrap();
        writeln!(w, "\t#[allow(unused)] pub(crate) fn is_some(&self) -> bool {{").unwrap();
-       writeln!(w, "\t\tif let Self::Some(_) = self {{ true }} else {{ false }}").unwrap();
+       writeln!(w, "\t\tif let Self::None = self {{ false }} else {{ true }}").unwrap();
        writeln!(w, "\t}}").unwrap();
        writeln!(w, "\t#[allow(unused)] pub(crate) fn is_none(&self) -> bool {{").unwrap();
        writeln!(w, "\t\t!self.is_some()").unwrap();
        writeln!(w, "\t}}").unwrap();
-       writeln!(w, "\t#[allow(unused)] pub(crate) fn take(mut self) -> {} {{", inner_type).unwrap();
-       writeln!(w, "\t\tif let Self::Some(v) = self {{ v }} else {{ unreachable!() }}").unwrap();
-       writeln!(w, "\t}}").unwrap();
+       if inner_type != "" {
+               writeln!(w, "\t#[allow(unused)] pub(crate) fn take(mut self) -> {} {{", inner_type).unwrap();
+               writeln!(w, "\t\tif let Self::Some(v) = self {{ v }} else {{ unreachable!() }}").unwrap();
+               writeln!(w, "\t}}").unwrap();
+       }
        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();
+       if inner_type != "" {
+               writeln!(w, "pub extern \"C\" fn {}_some(o: {}) -> {} {{", mangled_container, inner_type, mangled_container).unwrap();
+               writeln!(w, "\t{}::Some(o)", mangled_container).unwrap();
+       } else {
+               writeln!(w, "pub extern \"C\" fn {}_some() -> {} {{", mangled_container, mangled_container).unwrap();
+               writeln!(w, "\t{}::Some", mangled_container).unwrap();
+       }
        writeln!(w, "}}").unwrap();
 
        writeln!(w, "#[no_mangle]").unwrap();
index 5fc90b1ff29fbcd478a50cf1389e174954540ab0..0a6bce453e5628a4847c890e44c9ca0c49e5ac16 100644 (file)
@@ -1386,6 +1386,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                        }
                                }
                                if let Some(t) = single_contained {
+                                       if let syn::Type::Tuple(syn::TypeTuple { elems, .. }) = t {
+                                               assert!(elems.is_empty());
+                                               let inner_name = self.get_c_mangled_container_type(vec![single_contained.unwrap()], generics, "Option").unwrap();
+                                               return Some(("if ", vec![
+                                                       (format!(".is_none() {{ {}::None }} else {{ {}::Some /*",
+                                                               inner_name, inner_name), format!(""))
+                                                       ], " */}", ContainerPrefixLocation::PerConv));
+                                       }
                                        if let syn::Type::Reference(syn::TypeReference { elem, .. }) = t {
                                                if let syn::Type::Slice(_) = &**elem {
                                                        return Some(("if ", vec![
@@ -2393,7 +2401,13 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                }
                                if !self.write_c_type_intern(w, t, generics, false, false, false, false) { return false; }
                        } else {
-                               assert!(!is_ref); // We don't currently support outer reference types for non-primitive inners
+                               // We don't currently support outer reference types for non-primitive inners,
+                               // except for the empty tuple.
+                               if let syn::Type::Tuple(t_arg) = t {
+                                       assert!(t_arg.elems.len() == 0 || !is_ref);
+                               } else {
+                                       assert!(!is_ref);
+                               }
                                if !self.write_c_type_intern(w, t, generics, false, false, false, false) { return false; }
                        }
                }