//! This example demonstrates how to increment a cached `u64` counter. It uses the //! `and_compute_with` method of `Cache`. use moka::{ future::Cache, ops::compute::{CompResult, Op}, }; #[tokio::main] async fn main() { let cache: Cache = Cache::new(100); let key = "key".to_string(); // This should insert a new counter value 1 to the cache, and return the value // with the kind of the operation performed. let result = inclement_or_remove_counter(&cache, &key).await; let CompResult::Inserted(entry) = result else { panic!("`Inserted` should be returned: {result:?}"); }; assert_eq!(entry.into_value(), 1); // This should increment the cached counter value by 1. let result = inclement_or_remove_counter(&cache, &key).await; let CompResult::ReplacedWith(entry) = result else { panic!("`ReplacedWith` should be returned: {result:?}"); }; assert_eq!(entry.into_value(), 2); // This should remove the cached counter from the cache, and returns the // _removed_ value. let result = inclement_or_remove_counter(&cache, &key).await; let CompResult::Removed(entry) = result else { panic!("`Removed` should be returned: {result:?}"); }; assert_eq!(entry.into_value(), 2); // The key should not exist. assert!(!cache.contains_key(&key)); // This should start over; insert a new counter value 1 to the cache. let result = inclement_or_remove_counter(&cache, &key).await; let CompResult::Inserted(entry) = result else { panic!("`Inserted` should be returned: {result:?}"); }; assert_eq!(entry.into_value(), 1); } /// Increment a cached `u64` counter. If the counter is greater than or equal to 2, /// remove it. /// /// This method uses cache's `and_compute_with` method. async fn inclement_or_remove_counter( cache: &Cache, key: &str, ) -> CompResult { // - If the counter does not exist, insert a new value of 1. // - If the counter is less than 2, increment it by 1. // - If the counter is greater than or equal to 2, remove it. cache .entry_by_ref(key) .and_compute_with(|maybe_entry| { let op = if let Some(entry) = maybe_entry { // The entry exists. let counter = entry.into_value(); if counter < 2 { // Increment the counter by 1. Op::Put(counter.saturating_add(1)) } else { // Remove the entry. Op::Remove } } else { // The entry does not exist, insert a new value of 1. Op::Put(1) }; // Return a Future that is resolved to `op` immediately. std::future::ready(op) }) .await }