| Crates.io | generic_cache |
| lib.rs | generic_cache |
| version | 1.1.0 |
| created_at | 2025-02-22 09:41:23.731551+00 |
| updated_at | 2025-06-25 09:42:27.353592+00 |
| description | Easy to use object caching based on defined TTL |
| homepage | |
| repository | https://github.com/NattapongSiri/generic_cache_rs |
| max_upload_size | |
| id | 1565262 |
| size | 30,660 |
A generic cached object which provide user two possible usage options.
Object::get() until it return TimeoutError then manually call Object::refresh() function.Object::get_or_refresh() which will automatically refresh the value when it is expired.There is a special case that require explicit type declaration.
In such case, since version 1.1.0, it add trait CachedObject which required only two generic type which is a type being cache and the error type which may occur during value refresh. The type of refresh function is no longer required.
You do not need to use this trait to use cache. Only Object struct is all you need. The trait is just to workaround this specific case.
By current Rust limitation, it is currently impossible to use impl trait on let/static binding.
See this RFC for detail.
With this trait, it allow usage in static context by utilizing dyn trait.
An example of such usage is:
use core::time::Duration;
use generic_cache::{CachedObject, Object};
use std::sync::{LazyLock, RwLock};
use tokio::time::sleep;
static CACHED: LazyLock<RwLock<Box<dyn CachedObject<u16, ()> + Send + Sync>>> = LazyLock::new(|| {
RwLock::new(Box::new(Object::new(std::time::Duration::from_secs(1), 100, async || {Ok::<u16, ()>(200)})))
});
assert_eq!((&*CACHED).read().unwrap().get().unwrap(), &100u16);
sleep(Duration::from_secs(2)).await;
assert!((&*CACHED).read().unwrap().get().is_err(), "Cache should be expired");
assert_eq!((&*CACHED).write().unwrap().get_or_refresh().await.unwrap(), &200u16, "Cache should be refreshed to 200");
It is important to note that the trait provides mirror function to the original function provided by Object with two differents. Both method refresh and get_or_refresh return Pin<Box<dyn Future>> instead of impl Future.
This mean that the trait return heap allocated pinned future whereas Object return impl Future which may or may not be on heap. This is a trade-off that need to be made to make it dyn compatible.
If this RFC is resolved, it will allow omitting the type declaration altogether if there's no ambiguity type inference occur.
For performance critical application, most of the time, major performance cost came from I/O. To reduce cost, the easiest way is to cache the value. In some case, it is possible to delegate this work to network layer, e.g. Proxy. In some other case, it is not possible due to security reason. An example of such case is the bearer token which is used to communicate between API server. It is normally obtained via HTTP POST which proxy won't cache. In such case, some vendor provide a library which handle token caching but it is not always the case. This is where this library fit in.
ttl argument type from u128 to std::time::Duration type.