From 2ba60a3b40ed06ca147557b09d186da8e69677b5 Mon Sep 17 00:00:00 2001
From: sup39 <dev@sup39.dev>
Date: Fri, 12 Apr 2024 04:31:21 +0900
Subject: [PATCH] feat (macro-rs): convert `&[T]` to `Vec<T>`

---
 packages/macro-rs/src/lib.rs | 63 +++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 8 deletions(-)

diff --git a/packages/macro-rs/src/lib.rs b/packages/macro-rs/src/lib.rs
index c3cc0c505d..4478b80179 100644
--- a/packages/macro-rs/src/lib.rs
+++ b/packages/macro-rs/src/lib.rs
@@ -16,6 +16,7 @@ pub fn dummy_macro(
 ///
 /// The types of the function arguments is converted with following rules:
 /// - `&str` and `&mut str` are converted to `String`
+/// - `&[T]` and `&mut [T]` are converted to `Vec<T>`
 /// - `&T` and `&mut T` are converted to `T`
 /// - Other `T` remains `T`
 ///
@@ -67,6 +68,28 @@ pub fn dummy_macro(
 /// }
 /// ```
 ///
+/// ## Example with `&[String]` argument
+/// ```
+/// # mod napi_derive { pub use macro_rs::dummy_macro as napi; } // FIXME
+/// #[macro_rs::napi]
+/// pub fn string_array_length(array: &[String]) -> u32 {
+///     array.len() as u32
+/// }
+/// ```
+///
+/// generates
+///
+/// ```
+/// # mod napi_derive { pub use macro_rs::dummy_macro as napi; } // FIXME
+/// # pub fn string_array_length(array: &[String]) -> u32 {
+/// #     array.len() as u32
+/// # }
+/// #[napi_derive::napi(js_name = "stringArrayLength")]
+/// pub fn string_array_length_napi(array: Vec<String>) -> u32 {
+///     string_array_length(&array)
+/// }
+/// ```
+///
 /// ## Example with `Result<T, E>` return type
 /// ```
 /// # mod napi_derive { pub use macro_rs::dummy_macro as napi; } // FIXME
@@ -220,14 +243,21 @@ fn napi_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
                                 // (1) add `mut` token to `&mut` type
                                 ident.mutability = r.mutability;
                                 // (2) remove reference
-                                let elem_tokens = r.elem.to_token_stream();
-                                *arg.ty =
-                                    syn::Type::Verbatim(match elem_tokens.to_string().as_str() {
-                                        // &str => String
-                                        "str" => quote! { String },
-                                        // &T => T
-                                        _ => elem_tokens,
-                                    });
+                                *arg.ty = syn::Type::Verbatim(match &*r.elem {
+                                    syn::Type::Slice(slice) => {
+                                        let ty = &*slice.elem;
+                                        quote! { Vec<#ty> }
+                                    }
+                                    _ => {
+                                        let elem_tokens = r.elem.to_token_stream();
+                                        match elem_tokens.to_string().as_str() {
+                                            // &str => String
+                                            "str" => quote! { String },
+                                            // &T => T
+                                            _ => elem_tokens,
+                                        }
+                                    }
+                                });
 
                                 // return arguments in function call
                                 tokens
@@ -374,4 +404,21 @@ mod tests {
             }
         )
     }
+
+    #[test]
+    fn slice_type() {
+        test_macro!(
+            quote! {
+                pub fn string_array_length(array: &[String]) -> u32 {
+                    array.len() as u32
+                }
+            },
+            quote! {
+                #[napi_derive::napi(js_name = "stringArrayLength")]
+                pub fn string_array_length_napi(array: Vec<String>) -> u32 {
+                    string_array_length(&array)
+                }
+            }
+        )
+    }
 }