diff --git a/src/util.rs b/src/util.rs index d70b404..d1e89e9 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,7 +1,5 @@ mod html; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; use url::Url; pub use self::html::{convert_relative_url, fragment_root_node_id, html_body}; @@ -69,131 +67,142 @@ mod app_base { pub use self::app_base::app_base_from_env; -#[derive( - JsonSchema, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, -)] -#[serde(untagged)] -pub enum SingleOrVec { - /// A single entry - Single(T), - /// A list of entries - Vec(Vec), -} - -impl Default for SingleOrVec { - fn default() -> Self { - Self::empty() +mod single_or_vec { + use schemars::JsonSchema; + use serde::{Deserialize, Serialize}; + + #[derive( + JsonSchema, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, + )] + #[serde(untagged)] + pub enum SingleOrVec { + /// A single entry + Single(T), + /// A list of entries + Vec(Vec), } -} -pub enum SingleOrVecIter<'a, T> { - Single(std::iter::Once<&'a T>), - Vec(std::slice::Iter<'a, T>), -} + impl Default for SingleOrVec { + fn default() -> Self { + Self::empty() + } + } -impl SingleOrVec { - pub fn empty() -> Self { - Self::Vec(Vec::new()) + pub enum SingleOrVecIter<'a, T> { + Single(std::iter::Once<&'a T>), + Vec(std::slice::Iter<'a, T>), } - pub fn into_vec(self) -> Vec { - match self { - Self::Single(s) => vec![s], - Self::Vec(v) => v, + impl SingleOrVec { + pub fn empty() -> Self { + Self::Vec(Vec::new()) + } + + pub fn into_vec(self) -> Vec { + match self { + Self::Single(s) => vec![s], + Self::Vec(v) => v, + } } } -} -impl<'a, T> IntoIterator for &'a SingleOrVec { - type Item = &'a T; - type IntoIter = SingleOrVecIter<'a, T>; + impl<'a, T> IntoIterator for &'a SingleOrVec { + type Item = &'a T; + type IntoIter = SingleOrVecIter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - match self { - SingleOrVec::Single(s) => SingleOrVecIter::Single(std::iter::once(s)), - SingleOrVec::Vec(v) => SingleOrVecIter::Vec(v.iter()), + fn into_iter(self) -> Self::IntoIter { + match self { + SingleOrVec::Single(s) => SingleOrVecIter::Single(std::iter::once(s)), + SingleOrVec::Vec(v) => SingleOrVecIter::Vec(v.iter()), + } } } -} -impl<'a, T> Iterator for SingleOrVecIter<'a, T> { - type Item = &'a T; + impl<'a, T> Iterator for SingleOrVecIter<'a, T> { + type Item = &'a T; - fn next(&mut self) -> Option { - match self { - Self::Single(s) => s.next(), - Self::Vec(v) => v.next(), + fn next(&mut self) -> Option { + match self { + Self::Single(s) => s.next(), + Self::Vec(v) => v.next(), + } } } } -use std::{ - hash::Hash, - num::NonZeroUsize, - sync::{ - atomic::{AtomicUsize, Ordering}, - RwLock, - }, - time::{Duration, Instant}, -}; - -use lru::LruCache; - -pub struct Timed { - value: T, - created: Instant, -} +pub use self::single_or_vec::SingleOrVec; + +mod cache { + use std::{ + hash::Hash, + num::NonZeroUsize, + sync::{ + atomic::{AtomicUsize, Ordering}, + RwLock, + }, + time::{Duration, Instant}, + }; -pub struct TimedLruCache { - map: RwLock>>, - misses: AtomicUsize, - hits: AtomicUsize, - timeout: Duration, -} + use lru::LruCache; -impl TimedLruCache { - pub fn new(max_entries: usize, timeout: Duration) -> Self { - let max_entries = max_entries.try_into().unwrap_or(NonZeroUsize::MIN); - Self { - map: RwLock::new(LruCache::new(max_entries)), - timeout, - misses: AtomicUsize::new(0), - hits: AtomicUsize::new(0), - } + struct Timed { + value: T, + created: Instant, } - pub fn get_cached(&self, key: &K) -> Option { - let mut map = self.map.write().ok()?; - let Some(entry) = map.get(key) else { - self.misses.fetch_add(1, Ordering::Relaxed); - return None; - }; - - if entry.created.elapsed() > self.timeout { - self.misses.fetch_add(1, Ordering::Relaxed); - map.pop(key); - return None; + pub struct TimedLruCache { + map: RwLock>>, + misses: AtomicUsize, + hits: AtomicUsize, + timeout: Duration, + } + + impl TimedLruCache { + pub fn new(max_entries: usize, timeout: Duration) -> Self { + let max_entries = max_entries.try_into().unwrap_or(NonZeroUsize::MIN); + Self { + map: RwLock::new(LruCache::new(max_entries)), + timeout, + misses: AtomicUsize::new(0), + hits: AtomicUsize::new(0), + } } - self.hits.fetch_add(1, Ordering::Relaxed); - Some(entry.value.clone()) - } + pub fn get_cached(&self, key: &K) -> Option { + let mut map = self.map.write().ok()?; + let Some(entry) = map.get(key) else { + self.misses.fetch_add(1, Ordering::Relaxed); + return None; + }; + + if entry.created.elapsed() > self.timeout { + self.misses.fetch_add(1, Ordering::Relaxed); + map.pop(key); + return None; + } + + self.hits.fetch_add(1, Ordering::Relaxed); + Some(entry.value.clone()) + } - pub fn insert(&self, key: K, value: V) -> Option<()> { - let timed = Timed { - value, - created: Instant::now(), - }; - self.map.write().ok()?.push(key, timed); - Some(()) - } + pub fn insert(&self, key: K, value: V) -> Option<()> { + let timed = Timed { + value, + created: Instant::now(), + }; + self.map.write().ok()?.push(key, timed); + Some(()) + } - // hit, miss - #[allow(unused)] - pub fn stats(&self) -> (usize, usize) { - ( - self.hits.load(Ordering::Relaxed), - self.misses.load(Ordering::Relaxed), - ) + // hit, miss + #[allow(unused)] + pub fn stats(&self) -> (usize, usize) { + ( + self.hits.load(Ordering::Relaxed), + self.misses.load(Ordering::Relaxed), + ) + } } } + +pub use self::cache::TimedLruCache;