diff --git a/src/cache.rs b/src/cache.rs index 7cdb138..d2855b8 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -13,6 +13,14 @@ where fn key(&self) -> K; } +pub trait Initable +where + T: Cachable, + K: core::cmp::PartialEq, +{ + fn init(key: K) -> T; +} + struct CacheItem where T: Cachable, @@ -105,7 +113,7 @@ where K: core::cmp::PartialEq + core::fmt::Display, { /// Creates a new cache with a certain item lifetime - pub fn new(lifetime: chrono::Duration) -> Self { + pub const fn new(lifetime: chrono::Duration) -> Self { Self { lifetime, items: alloc::vec![], @@ -120,6 +128,13 @@ where .is_some() } + /// Determines the index of a certain key + fn find(&mut self, key: &K) -> Option { + self.items + .iter() + .position(|i| i.data.borrow().key() == *key) + } + /// Retrieves all known keys pub fn keys(&self) -> Vec { self.items.iter().map(|i| i.data.borrow().key()).collect() @@ -194,7 +209,7 @@ where K: core::fmt::Display, { // find item - let Some(pos) = self.items.iter().position(|i| i.data.borrow().key() == key) else { + let Some(pos) = self.find(&key) else { return Err(CacheError::KeyNotFound(key)); }; @@ -209,6 +224,28 @@ where Ok(()) } + /// Updates an item in the cache using the provided function or create a new item with default values + pub fn update_or_init(&mut self, time_now: chrono::NaiveDateTime, key: K, mut func: F) + where + F: FnMut(&mut T), + K: core::fmt::Display, + T: Initable, + { + if let Some(pos) = self.find(&key) { + // update existsting item + // unwrap is fine since we fetched the position before + let item = self.items.get_mut(pos).unwrap(); + + let mut data = item.data.borrow_mut(); + func(&mut data); + + item.timestamp = time_now; + } else { + // insert new item + self.items.push(CacheItem::new(time_now, T::init(key))); + } + } + /// Cleans items which timed out from the cache /// /// Call this regularly to prune old items.