changeset 1:df9526623f04

Initial working version!
author Lewin Bormann <lbo@spheniscida.de>
date Thu, 15 Oct 2020 12:52:23 +0200
parents 49c550904d88
children 112b5335a4a0
files Cargo.toml examples/test1.rs src/lib.rs
diffstat 3 files changed, 106 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/Cargo.toml	Wed Oct 14 19:42:54 2020 +0200
+++ b/Cargo.toml	Thu Oct 15 12:52:23 2020 +0200
@@ -10,3 +10,6 @@
 
 [dependencies]
 lazy_static = "1.4"
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = { version = "1.0", features = ["full"] }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/test1.rs	Thu Oct 15 12:52:23 2020 +0200
@@ -0,0 +1,12 @@
+use memoize::memoize;
+
+#[memoize]
+fn hello(a: i32) -> bool {
+    println!("HELLO");
+    a%2 == 0
+}
+
+fn main() {
+    println!("result: {}", hello(32));
+    println!("result: {}", hello(32));
+}
--- a/src/lib.rs	Wed Oct 14 19:42:54 2020 +0200
+++ b/src/lib.rs	Thu Oct 15 12:52:23 2020 +0200
@@ -1,16 +1,103 @@
 #![crate_type = "proc-macro"]
 
-use proc_macro::TokenStream;
+use syn;
+use syn::{parse_macro_input, spanned::Spanned, ItemFn};
 
 use lazy_static::lazy_static;
+use proc_macro::TokenStream;
+use proc_macro2::Span;
+use quote::{self, ToTokens};
 
 use std::collections::HashMap;
 use std::sync::Mutex;
 
+/*
+ * TODO:
+ * - Create static map for memoized arguments/results
+ * - Create memoized version of function
+ * - Rename original function to memoized_original_{fn}
+ *
+ */
+
 #[proc_macro_attribute]
-pub fn memoize(attr: TokenStream, item: TokenStream) -> TokenStream {
-    let func = parse_macro_input
-    item
+pub fn memoize(_attr: TokenStream, item: TokenStream) -> TokenStream {
+    let func = parse_macro_input!(item as ItemFn);
+    let sig = &func.sig;
+
+    let original_name = &func.sig.ident;
+    let fn_name = &func.sig.ident.to_string();
+    let renamed_name = format!("memoized_original_{}", fn_name);
+    let map_name = format!("memoized_mapping_{}", fn_name);
+    println!("{}", fn_name);
+
+    let mut type_in = None;
+    let mut name_in = None;
+    let type_out;
+
+    // Only one argument
+    if sig.inputs.len() == 1 {
+        if let syn::FnArg::Typed(ref arg) = sig.inputs[0] {
+            type_in = Some(arg.ty.clone());
+            if let syn::Pat::Ident(_) = &*arg.pat {
+                name_in = Some(arg.pat.clone());
+            } else {
+                return syn::Error::new(
+                    sig.span(),
+                    "Cannot memoize method (self-receiver) without arguments!",
+                )
+                .to_compile_error()
+                .into();
+            }
+        } else {
+            return TokenStream::from(
+                syn::Error::new(
+                    sig.span(),
+                    "Cannot memoize method (self-receiver) without arguments!",
+                )
+                .to_compile_error(),
+            );
+        }
+    }
+    // TODO: Cache methods too
+    match &sig.output {
+        syn::ReturnType::Default => type_out = quote::quote! { () },
+        syn::ReturnType::Type(_, ty) => type_out = ty.to_token_stream(),
+    }
+
+    let type_in = type_in.unwrap();
+    let map_ident = syn::Ident::new(&map_name, sig.span());
+    let store = quote::quote! {
+        lazy_static::lazy_static! {
+            static ref #map_ident : std::sync::Mutex<std::collections::HashMap<#type_in, #type_out>> =
+                std::sync::Mutex::new(std::collections::HashMap::new());
+        }
+    };
+
+    let mut renamed_fn = func.clone();
+    renamed_fn.sig.ident = syn::Ident::new(&renamed_name, func.sig.span());
+
+    let name_in = name_in.unwrap();
+    let memoized_id = &renamed_fn.sig.ident;
+    let memoizer = quote::quote! {
+        #sig {
+            let mut hm = &mut #map_ident.lock().unwrap();
+            if let Some(r) = hm.get(&#name_in) {
+                return *r;
+            }
+            let r = #memoized_id(#name_in);
+            hm.insert(#name_in, r);
+            r
+        }
+    };
+
+    (quote::quote! {
+        #store
+
+        #renamed_fn
+
+        #memoizer
+    })
+    .into()
 }
 
 lazy_static! {
@@ -30,5 +117,4 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-
 }