Repository: jaemk/cached (language: rust)

Issue:
Is there a way to use cached with an async / await?
I'd like to be able to use cached with an async function and not use block_on. For example:

```rust
cached!{
    MY_ASYNC_MATH;
    async fn(id: i32) -> i32 = {
        let result = some_async_math_call(id).await;
        result
    }
}
```


Discussion / hints:

Fix patch:
diff --git a/Cargo.toml b/Cargo.toml
index 0ea8e36..f05cd77 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,11 +16,22 @@ travis-ci = { repository = "jaemk/cached", branch = "master" }
 
 [features]
 default = ["proc_macro"]
-proc_macro = []
+proc_macro = ["async-std", "cached_proc_macro"]
 
 [dependencies]
 once_cell = "1"
-cached_proc_macro = { path = "cached_proc_macro"}
+
+[dependencies.async-std]
+version = "1.6.0"
+optional = true
+features = ["attributes"]
+
+[dependencies.cached_proc_macro]
+path = "cached_proc_macro"
+optional = true
+
+[dev-dependencies]
+tokio = { version = "0.2.21", features = ["macros", "time"] }
 
 [workspace]
 members = ["cached_proc_macro"]
\ No newline at end of file
diff --git a/cached_proc_macro/Cargo.toml b/cached_proc_macro/Cargo.toml
index e4f6add..1442810 100644
--- a/cached_proc_macro/Cargo.toml
+++ b/cached_proc_macro/Cargo.toml
@@ -12,6 +12,7 @@ proc-macro = true
 [dependencies]
 quote = "1.0.6"
 darling = "0.10.2"
+async-std = "1.6.0"
 
 [dependencies.syn]
 version = "1.0.27"
diff --git a/cached_proc_macro/src/lib.rs b/cached_proc_macro/src/lib.rs
index bb52514..90e8ead 100644
--- a/cached_proc_macro/src/lib.rs
+++ b/cached_proc_macro/src/lib.rs
@@ -67,6 +67,7 @@ pub fn cached(args: TokenStream, input: TokenStream) -> TokenStream {
     let fn_ident = signature.ident.clone();
     let inputs = signature.inputs.clone();
     let output = signature.output.clone();
+    let asyncness = signature.asyncness.clone();
 
     // pull out the names and types of the function inputs
     let input_tys = inputs
@@ -181,28 +182,53 @@ pub fn cached(args: TokenStream, input: TokenStream) -> TokenStream {
     };
 
     // put it all together
-    let expanded = quote! {
-        #visibility static #cache_ident: ::cached::once_cell::sync::Lazy<std::sync::Mutex<#cache_ty>> = ::cached::once_cell::sync::Lazy::new(|| std::sync::Mutex::new(#cache_create));
-        #visibility #signature {
-            use cached::Cached;
-            let key = #key_convert_block;
-            {
-                // check if the result is cached
-                let mut cache = #cache_ident.lock().unwrap();
-                if let Some(result) = cache.cache_get(&key) {
-                    return result.clone();
+    let expanded = if asyncness.is_some() {
+        quote! {
+            #visibility static #cache_ident: ::cached::once_cell::sync::Lazy<::cached::async_std::sync::Mutex<#cache_ty>> = ::cached::once_cell::sync::Lazy::new(|| ::cached::async_std::sync::Mutex::new(#cache_create));
+            #visibility #signature {
+                use cached::Cached;
+                let key = #key_convert_block;
+                {
+                    // check if the result is cached
+                    let mut cache = #cache_ident.lock().await;
+                    if let Some(result) = cache.cache_get(&key) {
+                        return result.clone();
+                    }
                 }
+
+                // run the function and cache the result
+                async fn inner(#inputs) #output #body;
+                let result = inner(#(#input_names),*).await;
+
+                let mut cache = #cache_ident.lock().await;
+                #set_cache_block
+
+                result
             }
+        }
+    } else {
+        quote! {
+            #visibility static #cache_ident: ::cached::once_cell::sync::Lazy<std::sync::Mutex<#cache_ty>> = ::cached::once_cell::sync::Lazy::new(|| std::sync::Mutex::new(#cache_create));
+            #visibility #signature {
+                use cached::Cached;
+                let key = #key_convert_block;
+                {
+                    // check if the result is cached
+                    let mut cache = #cache_ident.lock().unwrap();
+                    if let Some(result) = cache.cache_get(&key) {
+                        return result.clone();
+                    }
+                }
 
-            // run the function and cache the result
-            fn inner(#inputs) #output #body;
-            let result = inner(#(#input_names),*);
+                // run the function and cache the result
+                fn inner(#inputs) #output #body;
+                let result = inner(#(#input_names),*);
 
-            let mut cache = #cache_ident.lock().unwrap();
-            // cache.cache_set(key, result.clone());
-            #set_cache_block
+                let mut cache = #cache_ident.lock().unwrap();
+                #set_cache_block
 
-            result
+                result
+            }
         }
     };
 
diff --git a/examples/async_std.rs b/examples/async_std.rs
new file mode 100644
index 0000000..3e3fe2b
--- /dev/null
+++ b/examples/async_std.rs
@@ -0,0 +1,24 @@
+use async_std::task::sleep;
+use cached::proc_macro::cached;
+use std::time::Duration;
+
+async fn sleep_secs(secs: u64) {
+    sleep(Duration::from_secs(secs)).await;
+}
+
+#[cached]
+async fn cached_sleep_secs(secs: u64) {
+    sleep(Duration::from_secs(secs)).await;
+}
+
+#[async_std::main]
+async fn main() {
+    println!("sleeping for 4 seconds");
+    sleep_secs(4).await;
+    println!("sleeping for 4 seconds");
+    sleep_secs(4).await;
+    println!("cached sleeping for 4 seconds");
+    cached_sleep_secs(4).await;
+    println!("cached sleeping for 4 seconds");
+    cached_sleep_secs(4).await;
+}
diff --git a/examples/tokio.rs b/examples/tokio.rs
new file mode 100644
index 0000000..a1d646f
--- /dev/null
+++ b/examples/tokio.rs
@@ -0,0 +1,24 @@
+use cached::proc_macro::cached;
+use std::time::Duration;
+use tokio::time::delay_for;
+
+async fn sleep_secs(secs: u64) {
+    delay_for(Duration::from_secs(secs)).await;
+}
+
+#[cached]
+async fn cached_sleep_secs(secs: u64) {
+    delay_for(Duration::from_secs(secs)).await;
+}
+
+#[tokio::main]
+async fn main() {
+    println!("sleeping for 4 seconds");
+    sleep_secs(4).await;
+    println!("sleeping for 4 seconds");
+    sleep_secs(4).await;
+    println!("cached sleeping for 4 seconds");
+    cached_sleep_secs(4).await;
+    println!("cached sleeping for 4 seconds");
+    cached_sleep_secs(4).await;
+}
diff --git a/src/lib.rs b/src/lib.rs
index 84dd37a..663931c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -242,6 +242,8 @@ pub use stores::{SizedCache, TimedCache, UnboundCache};
 pub mod proc_macro {
     pub use cached_proc_macro::cached;
 }
+#[cfg(feature = "proc_macro")]
+pub use async_std;
 
 /// Cache operations
 pub trait Cached<K, V> {


Test patch: