From 7469f0dc78cc7b44243a220386e4990e9defe8f6 Mon Sep 17 00:00:00 2001 From: Omid Rad Date: Thu, 8 Aug 2024 08:15:43 +0200 Subject: [PATCH 1/2] Sync some part of the cache types (cached, io_cached and once) - Add no_cache function to io_cached and once - Add `attributes` to prime function of all types - Add `generics` to some/all missing places - Remove some duplicate codes --- cached_proc_macro/src/io_cached.rs | 181 ++++++++++++++++------------- cached_proc_macro/src/once.rs | 37 +++--- 2 files changed, 126 insertions(+), 92 deletions(-) diff --git a/cached_proc_macro/src/io_cached.rs b/cached_proc_macro/src/io_cached.rs index 2750eee..e7aeff7 100644 --- a/cached_proc_macro/src/io_cached.rs +++ b/cached_proc_macro/src/io_cached.rs @@ -68,9 +68,9 @@ pub fn io_cached(args: TokenStream, input: TokenStream) -> TokenStream { let inputs = signature.inputs.clone(); let output = signature.output.clone(); let asyncness = signature.asyncness; + let generics = signature.generics.clone(); let input_tys = get_input_types(&inputs); - let input_names = get_input_names(&inputs); // pull out the output type @@ -407,26 +407,13 @@ pub fn io_cached(args: TokenStream, input: TokenStream) -> TokenStream { (set_cache_block, return_cache_block) }; - let do_set_return_block = if asyncness.is_some() { - quote! { - // run the function and cache the result - async fn inner(#inputs) #output #body; - let result = inner(#(#input_names),*).await; - let cache = &#cache_ident.get_or_init(init).await; - #set_cache_block - result - } - } else { - quote! { - // run the function and cache the result - fn inner(#inputs) #output #body; - let result = inner(#(#input_names),*); - let cache = &#cache_ident; - #set_cache_block - result - } + let set_cache_and_return = quote! { + #set_cache_block + result }; + let no_cache_fn_ident = Ident::new(&format!("{}_no_cache", &fn_ident), fn_ident.span()); + let signature_no_muts = get_mut_signature(signature); // create a signature for the cache-priming function @@ -436,6 +423,7 @@ pub fn io_cached(args: TokenStream, input: TokenStream) -> TokenStream { // make cached static, cached function and prime cached function doc comments let cache_ident_doc = format!("Cached static for the [`{}`] function.", fn_ident); + let no_cache_fn_indent_doc = format!("Origin of the cached function [`{}`].", fn_ident); let prime_fn_indent_doc = format!("Primes the cached function [`{}`].", fn_ident); let cache_fn_doc_extra = format!( "This is a cached function that uses the [`{}`] cached static.", @@ -443,16 +431,6 @@ pub fn io_cached(args: TokenStream, input: TokenStream) -> TokenStream { ); fill_in_attributes(&mut attributes, cache_fn_doc_extra); - let async_trait = if asyncness.is_some() && !args.disk { - quote! { - use cached::IOCachedAsync; - } - } else { - quote! { - use cached::IOCached; - } - }; - let async_cache_get_return = if asyncness.is_some() && !args.disk { quote! { if let Some(result) = cache.cache_get(&key).await.map_err(#map_error)? { @@ -466,62 +444,107 @@ pub fn io_cached(args: TokenStream, input: TokenStream) -> TokenStream { } } }; - // put it all together - let expanded = if asyncness.is_some() { - quote! { - // Cached static - #[doc = #cache_ident_doc] + + let use_trait = if asyncness.is_some() && !args.disk { + quote! { use cached::IOCachedAsync; } + } else { + quote! { use cached::IOCached; } + }; + + let init; + let function_no_cache; + let function_call; + let ty; + let logic; + if asyncness.is_some() { + init = quote! { + let init = || async { #cache_create }; + }; + + function_no_cache = quote! { + async fn #no_cache_fn_ident #generics (#inputs) #output #body + }; + + function_call = quote! { + let result = #no_cache_fn_ident(#(#input_names),*).await; + }; + + ty = quote! { #visibility static #cache_ident: ::cached::async_sync::OnceCell<#cache_ty> = ::cached::async_sync::OnceCell::const_new(); - // Cached function - #(#attributes)* - #visibility #signature_no_muts { - let init = || async { #cache_create }; - #async_trait - let key = #key_convert_block; - { - // check if the result is cached - let cache = &#cache_ident.get_or_init(init).await; - #async_cache_get_return - } - #do_set_return_block - } - // Prime cached function - #[doc = #prime_fn_indent_doc] - #[allow(dead_code)] - #visibility #prime_sig { - #async_trait - let init = || async { #cache_create }; - let key = #key_convert_block; - #do_set_return_block + }; + + logic = quote! { + let cache = &#cache_ident.get_or_init(init).await; + #async_cache_get_return + }; + } else { + init = quote! {}; + + function_no_cache = quote! { + fn #no_cache_fn_ident #generics (#inputs) #output #body + }; + + function_call = quote! { + let result = #no_cache_fn_ident(#(#input_names),*); + }; + + ty = quote! { + #visibility static #cache_ident: ::cached::once_cell::sync::Lazy<#cache_ty> = ::cached::once_cell::sync::Lazy::new(|| #cache_create); + }; + + logic = quote! { + let cache = &#cache_ident; + if let Some(result) = cache.cache_get(&key).map_err(#map_error)? { + #return_cache_block } + }; + } + + let do_set_return_block = if asyncness.is_some() { + quote! { + // run the function and cache the result + #function_call + let cache = &#cache_ident.get_or_init(init).await; + #set_cache_and_return } } else { quote! { - // Cached static - #[doc = #cache_ident_doc] - #visibility static #cache_ident: ::cached::once_cell::sync::Lazy<#cache_ty> = ::cached::once_cell::sync::Lazy::new(|| #cache_create); - // Cached function - #(#attributes)* - #visibility #signature_no_muts { - use cached::IOCached; - let key = #key_convert_block; - { - // check if the result is cached - let cache = &#cache_ident; - if let Some(result) = cache.cache_get(&key).map_err(#map_error)? { - #return_cache_block - } - } - #do_set_return_block - } - // Prime cached function - #[doc = #prime_fn_indent_doc] - #[allow(dead_code)] - #visibility #prime_sig { - use cached::IOCached; - let key = #key_convert_block; - #do_set_return_block + // run the function and cache the result + #function_call + let cache = &#cache_ident; + #set_cache_and_return + } + }; + + // put it all together + let expanded = quote! { + // Cached static + #[doc = #cache_ident_doc] + #ty + // No cache function (origin of the cached function) + #[doc = #no_cache_fn_indent_doc] + #visibility #function_no_cache + // Cached function + #(#attributes)* + #visibility #signature_no_muts { + #init + #use_trait + let key = #key_convert_block; + { + // check if the result is cached + #logic } + #do_set_return_block + } + // Prime cached function + #[doc = #prime_fn_indent_doc] + #[allow(dead_code)] + #(#attributes)* + #visibility #prime_sig { + #use_trait + #init + let key = #key_convert_block; + #do_set_return_block } }; diff --git a/cached_proc_macro/src/once.rs b/cached_proc_macro/src/once.rs index 70d5617..65c6c23 100644 --- a/cached_proc_macro/src/once.rs +++ b/cached_proc_macro/src/once.rs @@ -48,8 +48,8 @@ pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { let inputs = signature.inputs.clone(); let output = signature.output.clone(); let asyncness = signature.asyncness; + let generics = signature.generics.clone(); - // pull out the names and types of the function inputs let input_names = get_input_names(&inputs); // pull out the output type @@ -89,13 +89,9 @@ pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { let (set_cache_block, return_cache_block) = match (&args.result, &args.option) { (false, false) => { let set_cache_block = if args.time.is_some() { - quote! { - *cached = Some((now, result.clone())); - } + quote! { *cached = Some((now, result.clone())); } } else { - quote! { - *cached = Some(result.clone()); - } + quote! { *cached = Some(result.clone()); } }; let return_cache_block = if args.with_cached_flag { @@ -159,8 +155,12 @@ pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { #set_cache_block result }; + + let no_cache_fn_ident = Ident::new(&format!("{}_no_cache", &fn_ident), fn_ident.span()); + let r_lock; let w_lock; + let function_no_cache; let function_call; let ty; if asyncness.is_some() { @@ -174,10 +174,12 @@ pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { let mut cached = #cache_ident.read().await; }; + function_no_cache = quote! { + async fn #no_cache_fn_ident #generics (#inputs) #output #body + }; + function_call = quote! { - // run the function and cache the result - async fn inner(#inputs) #output #body; - let result = inner(#(#input_names),*).await; + let result = #no_cache_fn_ident(#(#input_names),*).await; }; ty = quote! { @@ -194,10 +196,12 @@ pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { let mut cached = #cache_ident.read().unwrap(); }; + function_no_cache = quote! { + fn #no_cache_fn_ident #generics (#inputs) #output #body + }; + function_call = quote! { - // run the function and cache the result - fn inner(#inputs) #output #body; - let result = inner(#(#input_names),*); + let result = #no_cache_fn_ident(#(#input_names),*); }; ty = quote! { @@ -206,7 +210,9 @@ pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { } let prime_do_set_return_block = quote! { + // try to get a lock first #w_lock + // run the function and cache the result #function_call #set_cache_and_return }; @@ -247,6 +253,7 @@ pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { // make cached static, cached function and prime cached function doc comments let cache_ident_doc = format!("Cached static for the [`{}`] function.", fn_ident); + let no_cache_fn_indent_doc = format!("Origin of the cached function [`{}`].", fn_ident); let prime_fn_indent_doc = format!("Primes the cached function [`{}`].", fn_ident); let cache_fn_doc_extra = format!( "This is a cached function that uses the [`{}`] cached static.", @@ -259,6 +266,9 @@ pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { // Cached static #[doc = #cache_ident_doc] #ty + // No cache function (origin of the cached function) + #[doc = #no_cache_fn_indent_doc] + #visibility #function_no_cache // Cached function #(#attributes)* #visibility #signature_no_muts { @@ -268,6 +278,7 @@ pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { // Prime cached function #[doc = #prime_fn_indent_doc] #[allow(dead_code)] + #(#attributes)* #visibility #prime_sig { let now = ::cached::web_time::Instant::now(); #prime_do_set_return_block From d4da7268965aa5cdeac5c7d240cc05985ebaa713 Mon Sep 17 00:00:00 2001 From: Omid Rad Date: Thu, 8 Aug 2024 08:59:16 +0200 Subject: [PATCH 2/2] Add `attributes` to `no_cache` functions and update some deps --- Cargo.toml | 24 ++++++++++--- cached_proc_macro/Cargo.toml | 2 +- cached_proc_macro/src/cached.rs | 1 + cached_proc_macro/src/io_cached.rs | 58 ++++++++++++------------------ cached_proc_macro/src/once.rs | 1 + src/stores/disk.rs | 14 ++++---- 6 files changed, 51 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1fd1d76..5f661c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,14 +23,28 @@ async = ["futures", "tokio", "async-trait"] async_tokio_rt_multi_thread = ["async", "tokio/rt-multi-thread"] redis_store = ["redis", "r2d2", "serde", "serde_json"] redis_connection_manager = ["redis_store", "redis/connection-manager"] -redis_async_std = ["redis_store", "async", "redis/aio", "redis/async-std-comp", "redis/tls", "redis/async-std-tls-comp"] -redis_tokio = ["redis_store", "async", "redis/aio", "redis/tokio-comp", "redis/tls", "redis/tokio-native-tls-comp"] +redis_async_std = [ + "redis_store", + "async", + "redis/aio", + "redis/async-std-comp", + "redis/tls", + "redis/async-std-tls-comp", +] +redis_tokio = [ + "redis_store", + "async", + "redis/aio", + "redis/tokio-comp", + "redis/tls", + "redis/tokio-native-tls-comp", +] redis_ahash = ["redis_store", "redis/ahash"] disk_store = ["sled", "serde", "rmp-serde", "directories"] wasm = [] [dependencies.cached_proc_macro] -version = "0.22.0" +version = "0.23.0" path = "cached_proc_macro" optional = true @@ -65,7 +79,7 @@ version = "0.1" optional = true [dependencies.redis] -version = "0.25" +version = "0.26" features = ["r2d2"] optional = true @@ -104,7 +118,7 @@ version = "^1.1.0" [dev-dependencies] copy_dir = "0.1.3" -googletest = "0.11.0" +googletest = "0.12.0" tempfile = "3.10.1" [dev-dependencies.async-std] diff --git a/cached_proc_macro/Cargo.toml b/cached_proc_macro/Cargo.toml index 327be3d..1a98b26 100644 --- a/cached_proc_macro/Cargo.toml +++ b/cached_proc_macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cached_proc_macro" -version = "0.22.0" +version = "0.23.0" authors = ["csos95 ", "James Kominick "] description = "Generic cache implementations and simplified function memoization" repository = "https://github.com/jaemk/cached" diff --git a/cached_proc_macro/src/cached.rs b/cached_proc_macro/src/cached.rs index fc63555..98221e8 100644 --- a/cached_proc_macro/src/cached.rs +++ b/cached_proc_macro/src/cached.rs @@ -314,6 +314,7 @@ pub fn cached(args: TokenStream, input: TokenStream) -> TokenStream { #ty // No cache function (origin of the cached function) #[doc = #no_cache_fn_indent_doc] + #(#attributes)* #visibility #function_no_cache // Cached function #(#attributes)* diff --git a/cached_proc_macro/src/io_cached.rs b/cached_proc_macro/src/io_cached.rs index e7aeff7..ef7dd1d 100644 --- a/cached_proc_macro/src/io_cached.rs +++ b/cached_proc_macro/src/io_cached.rs @@ -290,47 +290,32 @@ pub fn io_cached(args: TokenStream, input: TokenStream) -> TokenStream { } } None => { - let create = quote! { + let mut create = quote! { cached::DiskCache::new(#cache_name) }; - let create = match time { - None => create, - Some(time) => { - quote! { - (#create).set_lifespan(#time) - } - } - }; - let create = match time_refresh { - None => create, - Some(time_refresh) => { - quote! { - (#create).set_refresh(#time_refresh) - } - } - }; - let create = match sync_to_disk_on_cache_change { - None => create, - Some(sync_to_disk_on_cache_change) => { - quote! { - (#create).set_sync_to_disk_on_cache_change(#sync_to_disk_on_cache_change) - } - } + if let Some(time) = time { + create = quote! { + (#create).set_lifespan(#time) + }; }; - let create = match connection_config { - None => create, - Some(connection_config) => { - quote! { - (#create).set_connection_config(#connection_config) - } - } + if let Some(time_refresh) = time_refresh { + create = quote! { + (#create).set_refresh(#time_refresh) + }; + } + if let Some(sync_to_disk_on_cache_change) = sync_to_disk_on_cache_change { + create = quote! { + (#create).set_sync_to_disk_on_cache_change(#sync_to_disk_on_cache_change) + }; }; - let create = match args.disk_dir { - None => create, - Some(disk_dir) => { - quote! { (#create).set_disk_directory(#disk_dir) } - } + if let Some(connection_config) = connection_config { + create = quote! { + (#create).set_connection_config(#connection_config) + }; }; + if let Some(disk_dir) = args.disk_dir { + create = quote! { (#create).set_disk_directory(#disk_dir) }; + } quote! { (#create).build().expect("error constructing DiskCache in #[io_cached] macro") } } }; @@ -523,6 +508,7 @@ pub fn io_cached(args: TokenStream, input: TokenStream) -> TokenStream { #ty // No cache function (origin of the cached function) #[doc = #no_cache_fn_indent_doc] + #(#attributes)* #visibility #function_no_cache // Cached function #(#attributes)* diff --git a/cached_proc_macro/src/once.rs b/cached_proc_macro/src/once.rs index 65c6c23..d42f46d 100644 --- a/cached_proc_macro/src/once.rs +++ b/cached_proc_macro/src/once.rs @@ -268,6 +268,7 @@ pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { #ty // No cache function (origin of the cached function) #[doc = #no_cache_fn_indent_doc] + #(#attributes)* #visibility #function_no_cache // Cached function #(#attributes)* diff --git a/src/stores/disk.rs b/src/stores/disk.rs index 67683ae..057097b 100644 --- a/src/stores/disk.rs +++ b/src/stores/disk.rs @@ -540,7 +540,7 @@ mod test_DiskCache { ); assert_that!( cache.cache_get(&TEST_KEY), - ok(some(eq(TEST_VAL))), + ok(some(eq(&TEST_VAL))), "Getting a newly set (previously expired) key-value should return the value" ); @@ -571,12 +571,12 @@ mod test_DiskCache { assert_that!( cache.cache_get(&TEST_KEY), - ok(some(eq(TEST_VAL))), + ok(some(eq(&TEST_VAL))), "Getting a newly set (previously expired) key-value should return the value" ); assert_that!( cache.cache_get(&TEST_KEY), - ok(some(eq(TEST_VAL))), + ok(some(eq(&TEST_VAL))), "Getting the same value again should return the value" ); } @@ -600,7 +600,7 @@ mod test_DiskCache { sleep(Duration::from_secs(HALF_LIFE_SPAN)); assert_that!( cache.cache_get(&TEST_KEY), - ok(some(eq(TEST_VAL))), + ok(some(eq(&TEST_VAL))), "Getting a value before expiry should return the value" ); @@ -608,7 +608,7 @@ mod test_DiskCache { sleep(Duration::from_secs(HALF_LIFE_SPAN)); assert_that!( cache.cache_get(&TEST_KEY), - ok(some(eq(TEST_VAL))), + ok(some(eq(&TEST_VAL))), "Getting a value after the initial expiry should return the value as we have refreshed" ); @@ -742,7 +742,7 @@ mod test_DiskCache { |recovered_cache| { assert_that!( recovered_cache.cache_get(&TEST_KEY), - ok(some(eq(TEST_VAL))), + ok(some(eq(&TEST_VAL))), "set_sync_to_disk_on_cache_change is false, and there is no auto-flushing, so the cache_remove should not have persisted" ); }, @@ -773,7 +773,7 @@ mod test_DiskCache { |recovered_cache| { assert_that!( recovered_cache.cache_get(&TEST_KEY), - ok(some(eq(TEST_VAL))), + ok(some(eq(&TEST_VAL))), "Getting a set key should return the value" ); },