From 40372f0cf8a95f4d5bdf78fc522328b776482dbf Mon Sep 17 00:00:00 2001 From: alyx Date: Wed, 9 Aug 2023 01:34:47 -0400 Subject: fix packages, implement caching --- .gitignore | 1 + Cargo.toml | 2 + src/cache.rs | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/deserialize.rs | 4 +- src/lib.rs | 3 ++ 5 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 src/cache.rs diff --git a/.gitignore b/.gitignore index e1193dd..c97d769 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/Cargo.lock /target *~ .#* diff --git a/Cargo.toml b/Cargo.toml index ab70ee6..91dcbec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +serde = { version = "1.0.183", features = ["derive", "rc", "alloc"] } +serde_json = "1.0.104" diff --git a/src/cache.rs b/src/cache.rs new file mode 100644 index 0000000..9089ff1 --- /dev/null +++ b/src/cache.rs @@ -0,0 +1,120 @@ +use std::{future::Future, time::*, collections::HashMap, hash::Hash}; + +pub struct AsyncCache { + func: F, + cache: HashMap, + interval: Duration +} + +impl AsyncCache +where + F: for<'a> FnMut(&'a K) -> Fut, + K: Hash + PartialEq + Eq + Clone, + Fut: Future> +{ + pub fn new(interval: Duration, mut func: F) -> Self { + Self{ + cache: HashMap::new(), + interval, func + } + } + + pub async fn get(&mut self, key: &K) -> Result<&V, &'static str> { + if self.is_stale(&key) { + self.renew(&key).await + } else { + Ok(&self.cache.get(&key).unwrap().1) + } + } + + pub async fn renew(&mut self, key: &K) -> Result<&V, &'static str> { + let val = (self.func)(&key).await?; + self.cache.insert(key.clone(), (Instant::now(), val)); + Ok(&self.cache.get(key).unwrap().1) + } + + pub fn is_stale(&self, key: &K) -> bool { + if let Some((last_update, _)) = self.cache.get(key) { + let now = Instant::now(); + now < (*last_update + self.interval) + } + else { true } + } + + pub async fn get_opt(&self, key: &K) -> Option<&V> { + if self.is_stale(key) { + self.cache.get(key).map(|(_, v)| v) + } + else { None } + } +} + +impl AsyncCache +where + F: for<'a> FnMut(&'a K) -> Fut, + K: Hash + PartialEq + Eq + Clone, + V: Clone, + Fut: Future> +{ + pub async fn get_owned(&mut self, key: &K) -> Result { + self.get(key).await.cloned() + } +} +/* +pub struct AsyncCache { + func: F, + cache: HashMap, + interval: Duration +} + +impl AsyncCache +where + for<'a> F: FnMut(&'a K) -> Fut + 'a, + Fut: Future +{ + pub fn new(interval: Duration, mut func: F) -> Self { + Self{ + cache: HashMap::new(), + interval, func + } + } + + pub async fn get(&mut self, key: &K) -> &V { + if self.is_stale(key) { + self.renew().await + } else { + self.cache.get(key) + } + } + + pub async fn renew(&mut self, key: &K) -> &V { + self.cache.get_mut(key).0 = now; + self.cache.get_mut(key).1 = (self.func)(key).await; + self.cache.get(key) + } + + pub fn is_stale(&self, key: &K) -> bool { + let now = Instant::now(); + let last_update = self.cache.get(key).0; + now < (last_update + self.interval) + } + + pub fn get_opt(&self, key: &K) -> Option<&T> { + if self.is_stale(key) { + Some(self.cache.get(key)) + } + else { None } + } +} + +impl AsyncCache +where + F: for<'a> FnMut(&'a K) -> Fut + 'a, + Fut: Future, + V: Clone +{ + pub async fn get_owned(&mut self, key: &K) -> V { + self.get(key).await.clone() + } +} +*/ diff --git a/src/deserialize.rs b/src/deserialize.rs index 4cedc9f..a00ebcb 100644 --- a/src/deserialize.rs +++ b/src/deserialize.rs @@ -74,8 +74,8 @@ pub struct Artist { #[serde(default)] #[serde(rename = "image")] pub images: Vec, - pub #[serde(default)] - url: Option> + #[serde(default)] + pub url: Option> } #[derive(Deserialize, Debug)] diff --git a/src/lib.rs b/src/lib.rs index 5d0a682..87a87c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,4 @@ +#![feature(entry_insert)] + mod deserialize; +mod cache; -- cgit v1.2.3-54-g00ecf