Import the memory cache

This commit is contained in:
Savanni D'Gerinel 2023-06-20 09:49:05 -04:00
parent b15658dd0c
commit 5431f1e37f
2 changed files with 116 additions and 0 deletions

16
cachememory/Cargo.toml Normal file
View File

@ -0,0 +1,16 @@
[package]
name = "cachememory"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = { version = "0.4" }
futures = { version = "0.3" }
serde_derive = { version = "1" }
serde = { version = "1" }
#[dev-dependencies]
tokio = { version = "1", features = ["full"] }

100
cachememory/src/lib.rs Normal file
View File

@ -0,0 +1,100 @@
use chrono::{DateTime, Utc};
use futures::Future;
use std::{
collections::HashMap,
sync::{Arc, RwLock},
};
#[derive(Clone)]
pub struct CacheRecord<T> {
pub timeout: DateTime<Utc>,
pub value: T,
}
pub struct Cache<T>(Arc<RwLock<HashMap<String, CacheRecord<T>>>>);
impl<T: Clone> Cache<T> {
pub fn new() -> Cache<T> {
Cache(Arc::new(RwLock::new(HashMap::new())))
}
pub async fn find(&self, key: &str, f: impl Future<Output = (DateTime<Utc>, T)>) -> T {
let val = {
let cache = self.0.read().unwrap();
cache.get(key).cloned()
};
match val {
Some(ref val) if val.timeout > Utc::now() => val.value.clone(),
_ => {
let response = f.await;
let mut cache = self.0.write().unwrap();
let record = CacheRecord {
timeout: response.0,
value: response.1.clone(),
};
cache
.entry(key.to_owned())
.and_modify(|rec| *rec = record.clone())
.or_insert(record);
response.1
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::Duration;
use std::sync::{Arc, RwLock};
#[derive(Clone, Debug, PartialEq)]
struct Value(i64);
#[tokio::test]
async fn it_calls_function_when_element_does_not_exist() {
let cache = Cache::new();
let value = cache
.find("my_key", async { (Utc::now(), Value(15)) })
.await;
assert_eq!(value, Value(15));
}
#[tokio::test]
async fn it_calls_function_when_element_is_old() {
let calls = Arc::new(RwLock::new(false));
let cache = Cache::new();
let _ = cache
.find("my_key", async {
(Utc::now() - Duration::seconds(10), Value(15))
})
.await;
let value = cache
.find("my_key", async {
*calls.write().unwrap() = true;
(Utc::now(), Value(16))
})
.await;
assert_eq!(value, Value(16));
assert_eq!(*calls.read().unwrap(), true);
}
#[tokio::test]
async fn it_does_not_call_function_when_element_is_not_old() {
let calls = Arc::new(RwLock::new(false));
let cache = Cache::new();
let _ = cache
.find("my_key", async {
(Utc::now() + Duration::seconds(10), Value(15))
})
.await;
let value = cache
.find("my_key", async {
*calls.write().unwrap() = true;
(Utc::now(), Value(16))
})
.await;
assert_eq!(value, Value(15));
assert_eq!(*calls.read().unwrap(), false);
}
}