### Instantiating AsyncCache with Builder in Rust Source: https://github.com/purewhitewu/async_cache/blob/main/README.md Shows how to create an instance of `AsyncCache` using its builder pattern in Rust. It demonstrates initializing the builder with a refresh interval and a custom fetcher, then calling the `build` method to obtain the cache object. This is the starting point for using the cache. ```rust let builder = AsyncCache::builder(Duration::from_secs(60), YourFetcher); let cache = builder.build(); ``` -------------------------------- ### Asynchronously Getting a Value from AsyncCache (Rust) Source: https://github.com/purewhitewu/async_cache/blob/main/README.md Demonstrates the asynchronous retrieval of a value from `AsyncCache` using the `get` method in Rust. The `get` method returns an `Option`, attempting to fetch the data if it's not present and the fetcher is available. The example unwraps the result, assuming the key exists. ```rust let value = cache.get(FastStr::from("key")).await.unwrap(); ``` -------------------------------- ### Configuring AsyncCacheBuilder with Options (Rust) Source: https://github.com/purewhitewu/async_cache/blob/main/README.md Illustrates advanced configuration of `AsyncCacheBuilder` in Rust. This example shows how to set an optional expiration duration using `with_expire`, and how to configure channels for receiving errors (`with_error_tx`) and deletion notifications (`with_delete_tx`). ```rust let builder = AsyncCache::builder(Duration::from_secs(60), YourFetcher) .with_expire(Some(Duration::from_secs(60))) .with_error_tx(tx) .with_delete_tx(tx); ``` -------------------------------- ### Deleting Cache Entries Based on a Predicate (Rust) Source: https://github.com/purewhitewu/async_cache/blob/main/README.md Provides an example of using the `delete` method in `AsyncCache` (Rust) to remove entries. The method accepts a closure that determines which keys should be deleted based on a condition. In this case, it deletes keys starting with a specific prefix. ```rust cache.delete(|key| key.starts_with("prefix_")).await; ``` -------------------------------- ### AsyncCache::retain Example in Rust Source: https://context7.com/purewhitewu/async_cache/llms.txt Demonstrates how to use the `retain` method on `DefaultAsyncCache` to keep only entries that meet specific criteria, with the ability to modify values before deciding to retain them. It shows how to conditionally retain entries based on access count or premium status, and then filters further by premium status and value. ```rust use async_cache::{DefaultAsyncCache, Fetcher}; use std::time::Duration; #[derive(Clone, Debug, PartialEq)] struct CacheEntry { value: i32, access_count: usize, is_premium: bool, } #[derive(Clone)] struct DataFetcher; impl Fetcher for DataFetcher { type Error = (); async fn fetch(&self, _key: String) -> Result { Ok(CacheEntry { value: 100, access_count: 0, is_premium: false, }) } } #[tokio::main] async fn main() { let cache = DefaultAsyncCache::builder(Duration::from_secs(60), DataFetcher) .build(); // Populate cache cache.set_default("item_a".to_string(), CacheEntry { value: 50, access_count: 100, is_premium: true, }); cache.set_default("item_b".to_string(), CacheEntry { value: 30, access_count: 5, is_premium: false, }); cache.set_default("item_c".to_string(), CacheEntry { value: 80, access_count: 200, is_premium: true, }); cache.set_default("item_d".to_string(), CacheEntry { value: 10, access_count: 2, is_premium: false, }); // Retain entries with high access count or premium status // and increment access count for retained items cache.retain(|_key, entry| { if entry.access_count >= 50 || entry.is_premium { entry.access_count += 1; true } else { false } }); // Check retained items let item_a = cache.get(&"item_a".to_string()).await; assert_eq!(item_a.as_ref().unwrap().access_count, 101); let item_c = cache.get(&"item_c".to_string()).await; assert_eq!(item_c.as_ref().unwrap().access_count, 201); // Check deleted items assert_eq!(cache.get(&"item_b".to_string()).await, None); assert_eq!(cache.get(&"item_d".to_string()).await, None); // Retain only premium items with value > 60 cache.retain(|_key, entry| { entry.is_premium && entry.value > 60 }); // Only item_c should remain assert_eq!(cache.get(&"item_a".to_string()).await, None); assert!(cache.get(&"item_c".to_string()).await.is_some()); } ``` -------------------------------- ### Setting a Default Value in AsyncCache (Rust) Source: https://github.com/purewhitewu/async_cache/blob/main/README.md Illustrates how to use the `set_default` method of `AsyncCache` in Rust. This method assigns a specific value to a given key, which can be useful for pre-populating the cache or providing fallback data. The example uses `FastStr` for the key and `String` for the value. ```rust cache.set_default(FastStr::from("key"), "default_value".to_string()); ``` -------------------------------- ### Getting or Setting a Value in AsyncCache (Rust) Source: https://github.com/purewhitewu/async_cache/blob/main/README.md Shows the usage of the `get_or_set` method in `AsyncCache` (Rust). This method attempts to retrieve a value for a given key; if the key is not found, it inserts the provided default value and returns it. This is useful for ensuring a key always has a value after the operation. ```rust let value = cache.get_or_set(FastStr::from("key"), "default_value".to_string()); ``` -------------------------------- ### AsyncCache Core API in Rust Source: https://github.com/purewhitewu/async_cache/blob/main/README.md Outlines the primary methods available on the `AsyncCache` struct in Rust. This includes building the cache via a builder, setting default values, asynchronously retrieving values, setting values if not present, and deleting entries based on a predicate. These methods provide the main interface for interacting with the cache. ```rust pub struct AsyncCache; impl AsyncCache where K: Eq + Hash + Sync + Send + Clone, F: Fetcher + Sync + Send, T: Send + Sync + Clone + 'static, S: BuildHasher + Clone + 'static, { pub fn builder(refresh_interval: Duration, fetcher: F) -> AsyncCacheBuilder; pub fn set_default(&self, key: K, value: T); pub async fn get(&self, key: K) -> Option; pub fn get_or_set(&self, key: &K, value: T) -> T; pub fn delete(&self, prediction: impl Fn(&K) -> bool); pub fn retain(&self, prediction: impl Fn(&K, &mut T) -> bool); } ``` -------------------------------- ### Rust AsyncCacheBuilder Configuration Source: https://context7.com/purewhitewu/async_cache/llms.txt Demonstrates using the AsyncCacheBuilder to configure and build an AsyncCache instance with custom refresh intervals, expiration policies, and notification channels. It sets up error and deletion monitoring using Tokio's mpsc and broadcast channels. Dependencies include async_cache, Tokio, reqwest, and std::time::Duration. ```rust use async_cache::{DefaultAsyncCache, Fetcher}; use std::time::Duration; use tokio::sync::{mpsc, broadcast}; #[derive(Clone)] struct ApiFetcher; impl Fetcher for ApiFetcher { type Error = reqwest::Error; async fn fetch(&self, endpoint: String) -> Result { // Simulate API call tokio::time::sleep(Duration::from_millis(100)).await; Ok(format!("Response from {}", endpoint)) } } #[tokio::main] async fn main() { // Create channels for monitoring let (error_tx, mut error_rx) = mpsc::channel::<(String, reqwest::Error)>(100); let (delete_tx, mut delete_rx) = broadcast::channel::<(String, String)>(100); let cache = DefaultAsyncCache::builder( Duration::from_secs(30), // Refresh every 30 seconds ApiFetcher ) .with_expire(Some(Duration::from_secs(120))) // Expire after 120 seconds of no access .with_capacity(1000) // Initial capacity .with_error_tx(error_tx) // Receive fetch errors .with_delete_tx(delete_tx) // Receive deletion notifications .build(); // Spawn task to monitor errors tokio::spawn(async move { while let Some((key, error)) = error_rx.recv().await { eprintln!("Fetch error for key '{}': {:?}", key, error); } }); // Spawn task to monitor deletions tokio::spawn(async move { while let Ok((key, value)) = delete_rx.recv().await { println!("Deleted key '{}' with value '{}'", key, value); } }); // Use the cache cache.set_default("/api/users".to_string(), "Default response".to_string()); let result = cache.get(&"/api/users".to_string()).await; println!("Result: {:?}", result); } ``` -------------------------------- ### AsyncCacheBuilder Configuration in Rust Source: https://github.com/purewhitewu/async_cache/blob/main/README.md Demonstrates the configuration options for `AsyncCacheBuilder` in Rust. This builder allows customization of cache behavior, including setting refresh intervals, defining expiration times, and configuring channels for error and deletion notifications. It uses a fluent interface for setting these options. ```rust pub struct AsyncCacheBuilder; impl AsyncCacheBuilder where T: Send + Sync + Clone + 'static, F: Fetcher + Sync + Send + 'static, { pub fn new(refresh_interval: Duration, fetcher: F) -> Self; pub fn with_expire(mut self, expire_interval: Option) -> Self; pub fn with_error_tx(mut self, tx: mpsc::Sender<(K, F::Error)>) -> Self; pub fn with_delete_tx(mut self, tx: broadcast::Sender<(K, T)>) -> Self; pub fn build(self) -> AsyncCache } ``` -------------------------------- ### Rust Fetcher Trait and Cache Usage Source: https://context7.com/purewhitewu/async_cache/llms.txt Demonstrates implementing the Fetcher trait to define data retrieval logic and using DefaultAsyncCache to fetch and cache data. It shows how the cache retrieves data from the fetcher on the first call and returns cached data on subsequent calls. Dependencies include async_cache, Tokio, and std::time::Duration. ```rust use async_cache::{Fetcher, DefaultAsyncCache}; use std::time::Duration; #[derive(Debug, Clone, PartialEq)] struct UserData { id: u64, name: String, score: u32, } #[derive(Clone)] struct DatabaseFetcher { connection_string: String, } impl Fetcher for DatabaseFetcher { type Error = String; async fn fetch(&self, user_id: u64) -> Result { // Simulate database query tokio::time::sleep(Duration::from_millis(50)).await; if user_id == 0 { return Err("Invalid user ID".to_string()); } Ok(UserData { id: user_id, name: format!("User_{}", user_id), score: (user_id * 10) as u32, }) } } #[tokio::main] async fn main() { let fetcher = DatabaseFetcher { connection_string: "postgres://localhost/mydb".to_string(), }; let cache = DefaultAsyncCache::builder(Duration::from_secs(60), fetcher) .with_expire(Some(Duration::from_secs(180))) .build(); // First call fetches from database let user = cache.get(&42).await; println!("Fetched user: {:?}", user); // Subsequent calls return cached value let cached_user = cache.get(&42).await; println!("Cached user: {:?}", cached_user); } ``` -------------------------------- ### AsyncCache::get in Rust Source: https://context7.com/purewhitewu/async_cache/llms.txt Asynchronously retrieves a value from the cache. If the key is not present, it triggers a fetch operation using the configured Fetcher. If the initial fetch fails, it returns None. Subsequent requests for the same key within the cache's TTL will return the cached value without triggering another fetch. Concurrent requests for a missing key will only result in a single fetch. ```rust use async_cache::{DefaultAsyncCache, Fetcher}; use std::time::Duration; use std::sync::{Arc, atomic::{AtomicUsize, Ordering}}; #[derive(Clone)] struct MetricsFetcher { call_count: Arc, } impl Fetcher for MetricsFetcher { type Error = (); async fn fetch(&self, metric_name: String) -> Result { self.call_count.fetch_add(1, Ordering::SeqCst); tokio::time::sleep(Duration::from_millis(50)).await; // Simulate fetching different metrics let value = match metric_name.as_str() { "requests" => 12345, "errors" => 42, "latency_ms" => 150, _ => 0, }; Ok(value) } } #[tokio::main] async fn main() { let call_count = Arc::new(AtomicUsize::new(0)); let fetcher = MetricsFetcher { call_count: call_count.clone() }; let cache = DefaultAsyncCache::builder(Duration::from_secs(10), fetcher) .with_expire(Some(Duration::from_secs(30))) .build(); // First get triggers a fetch let requests = cache.get(&"requests".to_string()).await; assert_eq!(requests, Some(12345)); assert_eq!(call_count.load(Ordering::SeqCst), 1); // Subsequent gets return cached value (no additional fetch) let requests_cached = cache.get(&"requests".to_string()).await; assert_eq!(requests_cached, Some(12345)); assert_eq!(call_count.load(Ordering::SeqCst), 1); // Different key triggers another fetch let errors = cache.get(&"errors".to_string()).await; assert_eq!(errors, Some(42)); assert_eq!(call_count.load(Ordering::SeqCst), 2); // Multiple concurrent requests for same key only trigger one fetch let handles: Vec<_> = (0..10).map(|_| { let cache_clone = cache.clone(); tokio::spawn(async move { cache_clone.get(&"latency_ms".to_string()).await }) }).collect(); for handle in handles { let result = handle.await.unwrap(); assert_eq!(result, Some(150)); } // Only one additional fetch occurred despite 10 concurrent requests assert_eq!(call_count.load(Ordering::SeqCst), 3); } ``` -------------------------------- ### AsyncCache::set_default in Rust Source: https://context7.com/purewhitewu/async_cache/llms.txt Sets a default value for a cache key without triggering a fetch. This is useful for cache warming or providing fallback values. It takes a key and a default value as arguments. The cache uses a configured Fetcher to retrieve values if a key is not found and no default is set. ```rust use async_cache::{DefaultAsyncCache, Fetcher}; use std::time::Duration; #[derive(Clone)] struct ConfigFetcher; impl Fetcher for ConfigFetcher { type Error = std::io::Error; async fn fetch(&self, key: String) -> Result { tokio::time::sleep(Duration::from_millis(200)).await; Ok(42) } } #[tokio::main] async fn main() { let cache = DefaultAsyncCache::builder(Duration::from_secs(60), ConfigFetcher) .build(); // Warm up cache with default values cache.set_default("max_connections".to_string(), 100); cache.set_default("timeout_ms".to_string(), 5000); cache.set_default("retry_count".to_string(), 3); // Get returns immediately without fetching let max_conn = cache.get(&"max_connections".to_string()).await; assert_eq!(max_conn, Some(100)); // New key triggers a fetch let buffer_size = cache.get(&"buffer_size".to_string()).await; assert_eq!(buffer_size, Some(42)); // Subsequent access returns cached value let buffer_size_cached = cache.get(&"buffer_size".to_string()).await; assert_eq!(buffer_size_cached, Some(42)); } ``` -------------------------------- ### AsyncCache::get_or_set: Synchronous Cache Retrieval and Defaulting (Rust) Source: https://context7.com/purewhitewu/async_cache/llms.txt The `get_or_set` method synchronously retrieves a value from the cache. If the key is not found, it immediately returns the provided default value without triggering any asynchronous fetch operations. This is useful for ensuring a value is always available without waiting for async operations. ```rust use async_cache::{DefaultAsyncCache, Fetcher}; use std::time::Duration; #[derive(Clone)] struct SessionFetcher; impl Fetcher> for SessionFetcher { type Error = (); async fn fetch(&self, session_id: String) -> Result, Self::Error> { tokio::time::sleep(Duration::from_millis(100)).await; Ok(session_id.as_bytes().to_vec()) } } #[tokio::main] async fn main() { let cache = DefaultAsyncCache::builder(Duration::from_secs(60), SessionFetcher) .with_expire(Some(Duration::from_secs(300))) .build(); // get_or_set returns immediately without async operation let session_data = cache.get_or_set( "session_123".to_string(), vec![1, 2, 3, 4, 5] ); assert_eq!(session_data, vec![1, 2, 3, 4, 5]); // Subsequent calls return the same cached value let cached_data = cache.get_or_set( "session_123".to_string(), vec![99, 99, 99] // This value is ignored ); assert_eq!(cached_data, vec![1, 2, 3, 4, 5]); // Different key gets the new default value let new_session = cache.get_or_set( "session_456".to_string(), vec![6, 7, 8] ); assert_eq!(new_session, vec![6, 7, 8]); // After setting, async get returns the same value let async_result = cache.get(&"session_123".to_string()).await; assert_eq!(async_result, Some(vec![1, 2, 3, 4, 5])); } ``` -------------------------------- ### AsyncCache::delete: Conditional Cache Entry Removal (Rust) Source: https://context7.com/purewhitewu/async_cache/llms.txt The `delete` method removes entries from the cache that satisfy a given predicate function. This is valuable for targeted cache invalidation, such as removing all entries matching a pattern or based on specific criteria. It allows for efficient bulk deletion operations. ```rust use async_cache::{DefaultAsyncCache, Fetcher}; use std::time::Duration; #[derive(Clone)] struct ResourceFetcher; impl Fetcher for ResourceFetcher { type Error = (); async fn fetch(&self, resource_path: String) -> Result { Ok(format!("Content of {}", resource_path)) } } #[tokio::main] async fn main() { let cache = DefaultAsyncCache::builder(Duration::from_secs(60), ResourceFetcher) .build(); // Populate cache with various resources cache.set_default("/api/v1/users/1".to_string(), "User 1".to_string()); cache.set_default("/api/v1/users/2".to_string(), "User 2".to_string()); cache.set_default("/api/v2/users/1".to_string(), "User 1 v2".to_string()); cache.set_default("/api/v1/posts/1".to_string(), "Post 1".to_string()); cache.set_default("/static/image.png".to_string(), "Image data".to_string()); // Delete all v1 API endpoints cache.delete(|key: &String| key.starts_with("/api/v1/")); // Check deletions assert_eq!(cache.get(&"/api/v1/users/1".to_string()).await, None); assert_eq!(cache.get(&"/api/v1/users/2".to_string()).await, None); assert_eq!(cache.get(&"/api/v1/posts/1".to_string()).await, None); // v2 endpoints still exist let v2_result = cache.get(&"/api/v2/users/1".to_string()).await; assert_eq!(v2_result, Some("User 1 v2".to_string())); // Static resources still exist let static_result = cache.get(&"/static/image.png".to_string()).await; assert_eq!(static_result, Some("Image data".to_string())); // Delete by suffix cache.delete(|key: &String| key.ends_with(".png")); assert_eq!(cache.get(&"/static/image.png".to_string()).await, None); // Delete by length cache.delete(|key: &String| key.len() > 20); assert_eq!(cache.get(&"/api/v2/users/1".to_string()).await, None); } ``` -------------------------------- ### Fetcher Trait Definition in Rust Source: https://github.com/purewhitewu/async_cache/blob/main/README.md Defines the asynchronous `Fetcher` trait for custom data retrieval. It requires implementing an async `fetch` method that takes a key and returns a `Result` containing the fetched data or an error. This trait is essential for the cache to asynchronously load data when a key is not found. ```rust pub trait Fetcher where T: Send + Sync + Clone + 'static, { type Error: Send; async fn fetch(&self, key: K) -> Result; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.