changeset 69:0ada62444b37

Merge pull request #10 from bijij/master Add support for pattern binding to function arguments
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 01 Jan 2022 12:29:34 +0100
parents aefbc4424cb6 (current diff) bf87b6014441 (diff)
children 3adb990ef496
files
diffstat 2 files changed, 37 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/patterns.rs	Sat Jan 01 12:29:34 2022 +0100
@@ -0,0 +1,25 @@
+use memoize::memoize;
+
+// Patterns in memoized function arguments must be bound by name.
+#[memoize]
+fn manhattan_distance(_p1 @ (x1, y1): (i32, i32), _p2 @ (x2, y2): (i32, i32)) -> i32 {
+    (x1 - x2).abs() + (y1 - y2).abs()
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+enum OnlyOne {
+    Value(i32),
+}
+
+#[memoize]
+fn get_value(_enum @ OnlyOne::Value(value): OnlyOne) -> i32 {
+    value
+}
+
+fn main() {
+    // `manhattan_distance` is only called once here.
+    assert_eq!(manhattan_distance((1, 1), (1, 3)), 2);
+    
+    // Same with `get_value`.
+    assert_eq!(!get_value(OnlyOne::Value(0)), 0);
+}
--- a/inner/src/lib.rs	Fri Dec 24 13:40:28 2021 +0100
+++ b/inner/src/lib.rs	Sat Jan 01 12:29:34 2022 +0100
@@ -201,7 +201,7 @@
 
     // Extracted from the function signature.
     let input_types: Vec<Box<syn::Type>>;
-    let input_names: Vec<Box<syn::Pat>>;
+    let input_names: Vec<syn::Ident>;
     let return_type;
 
     match check_signature(sig) {
@@ -221,7 +221,7 @@
 
     // Construct storage for the memoized keys and return values.
     let store_ident = syn::Ident::new(&map_name.to_uppercase(), sig.span());
-    let (cache_type, cache_init) = store::construct_cache(&attr, input_tuple_type, return_type);
+    let (cache_type, cache_init) = store::construct_cache(&attr, input_tuple_type, return_type.clone());
     let store = quote::quote! {
         ::memoize::lazy_static::lazy_static! {
             static ref #store_ident : std::sync::Mutex<#cache_type> =
@@ -234,6 +234,10 @@
     renamed_fn.sig.ident = syn::Ident::new(&renamed_name, func.sig.span());
     let memoized_id = &renamed_fn.sig.ident;
 
+    // Extract the function name and identifier.
+    let fn_name = func.sig.ident.clone();
+    let fn_vis = func.vis.clone();
+    
     // Construct memoizer function, which calls the original function.
     let syntax_names_tuple = quote::quote! { (#(#input_names),*) };
     let syntax_names_tuple_cloned = quote::quote! { (#(#input_names.clone()),*) };
@@ -276,7 +280,9 @@
     };
     #[cfg(not(feature = "full"))]
     let memoizer = quote::quote! {
-        #sig {
+        #fn_vis fn #fn_name (
+            #(#input_names: #input_types),*
+        ) -> #return_type {
             {
                 let mut hm = &mut #store_ident.lock().unwrap();
                 if let Some(r) = hm.#get_fn(&#syntax_names_tuple_cloned) {
@@ -302,7 +308,7 @@
 
 fn check_signature(
     sig: &syn::Signature,
-) -> Result<(Vec<Box<syn::Type>>, Vec<Box<syn::Pat>>), syn::Error> {
+) -> Result<(Vec<Box<syn::Type>>, Vec<syn::Ident>), syn::Error> {
     if let syn::FnArg::Receiver(_) = sig.inputs[0] {
         return Err(syn::Error::new(
             sig.span(),
@@ -316,8 +322,8 @@
         if let syn::FnArg::Typed(ref arg) = a {
             types.push(arg.ty.clone());
 
-            if let syn::Pat::Ident(_) = &*arg.pat {
-                names.push(arg.pat.clone());
+            if let syn::Pat::Ident(patident) = &*arg.pat {
+                names.push(patident.ident.clone());
             } else {
                 return Err(syn::Error::new(
                     sig.span(),