]> git.proxmox.com Git - perlmod.git/commitdiff
macro: allow optional option parameters
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 24 Nov 2021 19:59:27 +0000 (20:59 +0100)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 24 Nov 2021 19:59:27 +0000 (20:59 +0100)
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
README.md
perlmod-macro/src/function.rs

index 4d1ab5587ed4707e52211dfff066822898f2f167..c608542afe31455ca6cd48e46ddff68c69dc14df 100644 (file)
--- a/README.md
+++ b/README.md
@@ -49,7 +49,6 @@ elsewhere.
 Pending Changes before 1.0
 ==========================
 
-* Don't export non-bootstrap methods anymore, we don't need them.
 * Make some kind of perl-package-generation tool for generating the `.pm`
   files, we only need to call bootstrap functions after all.
   (So we may not even need to parse the rust code, rather, just provide a list
index 7a27cfef5b2ac4a631a70f4ef607c86a5e996752..22f529706306e8c3d1bacc34d5083bac1c82ebd5 100644 (file)
@@ -118,14 +118,22 @@ pub fn handle_function(
             arg_name.span(),
         );
 
-        extract_arguments.extend(quote! {
-            let #extracted_name: ::perlmod::Value = match args.next() {
-                Some(arg) => ::perlmod::Value::from(arg),
-                None => {
+        let none_handling = if is_option_type(arg_type).is_some() {
+            quote! { ::perlmod::Value::new_undef(), }
+        } else {
+            quote! {
+                {
                     return Err(::perlmod::Value::new_string(#missing_message)
                         .into_mortal()
                         .into_raw());
                 }
+            }
+        };
+
+        extract_arguments.extend(quote! {
+            let #extracted_name: ::perlmod::Value = match args.next() {
+                Some(arg) => ::perlmod::Value::from(arg),
+                None => #none_handling
             };
         });
 
@@ -456,8 +464,8 @@ pub fn is_result_type(ty: &syn::Type) -> Option<&syn::Type> {
         }
         let segs = &p.path.segments;
         let is_result = match segs.len() {
-            1 => segs.last().unwrap().ident == "Result",
-            2 => segs.first().unwrap().ident == "std" && segs.last().unwrap().ident == "Result",
+            1 => segs[0].ident == "Result",
+            3 => segs[0].ident == "std" && segs[1].ident == "result" && segs[2].ident == "Result",
             _ => false,
         };
         if !is_result {
@@ -491,3 +499,32 @@ pub fn get_result_type(ty: &syn::Type) -> (&syn::Type, bool) {
 fn simple_usize(i: usize, span: Span) -> syn::LitInt {
     syn::LitInt::new(&format!("{}", i), span)
 }
+
+/// Note that we cannot handle renamed imports at all here...
+pub fn is_option_type(ty: &syn::Type) -> Option<&syn::Type> {
+    if let syn::Type::Path(p) = ty {
+        if p.qself.is_some() {
+            return None;
+        }
+        let segs = &p.path.segments;
+        let is_option = match segs.len() {
+            1 => segs[0].ident == "Option",
+            3 => segs[0].ident == "std" && segs[1].ident == "option" && segs[2].ident == "Option",
+            _ => false,
+        };
+        if !is_option {
+            return None;
+        }
+
+        if let syn::PathArguments::AngleBracketed(generic) = &segs.last().unwrap().arguments {
+            if generic.args.len() != 1 {
+                return None;
+            }
+
+            if let syn::GenericArgument::Type(ty) = generic.args.first().unwrap() {
+                return Some(ty);
+            }
+        }
+    }
+    None
+}