use std::future::Future;
use std::hash::Hash;
use std::sync::Arc;
use anyhow::{Error, Result};
use quick_cache::{Equivalent, Weighter};
use surrealism_runtime::runtime::Runtime;
use crate::catalog::{DatabaseId, NamespaceId};
#[cfg(feature = "http")]
use crate::http::HttpClient;
pub struct SurrealismCache {
cache: quick_cache::sync::Cache<SurrealismCacheKey, SurrealismCacheValue, Weight>,
}
impl SurrealismCache {
pub fn new(size: usize) -> Self {
Self {
cache: quick_cache::sync::Cache::with_weighter(size, size as u64, Weight),
}
}
pub fn remove(&self, lookup: &SurrealismCacheLookup) {
self.cache.remove(lookup);
}
pub async fn get_or_insert_with<F, Fut>(
&self,
lookup: &SurrealismCacheLookup<'_>,
compute: F,
) -> Result<SurrealismCachedModule>
where
F: FnOnce() -> Fut,
Fut: Future<Output = Result<SurrealismCachedModule>>,
{
let value = match self.cache.get(lookup) {
Some(cached) => cached,
None => {
let compute = async {
let value = compute().await?;
let wrapped = SurrealismCacheValue {
runtime: value.runtime,
module_display_name: value.module_display_name,
#[cfg(feature = "http")]
client: value.client,
};
Result::<_, Error>::Ok(wrapped)
};
self.cache.get_or_insert_async(&lookup.to_key(), compute).await?
}
};
Ok(SurrealismCachedModule {
runtime: value.runtime,
module_display_name: value.module_display_name,
#[cfg(feature = "http")]
client: value.client,
})
}
}
#[derive(Clone, Hash, Eq, PartialEq)]
pub enum SurrealismCacheKey {
File(NamespaceId, DatabaseId, String, String),
Silo(String, String, u32, u32, u32),
}
#[derive(Hash, Eq, PartialEq, Debug)]
pub enum SurrealismCacheLookup<'a> {
File(&'a NamespaceId, &'a DatabaseId, &'a str, &'a str),
Silo(&'a str, &'a str, u32, u32, u32),
}
impl SurrealismCacheLookup<'_> {
pub fn to_key(&self) -> SurrealismCacheKey {
match self {
SurrealismCacheLookup::File(ns, db, bucket, key) => {
SurrealismCacheKey::File(**ns, **db, (*bucket).to_string(), (*key).to_string())
}
SurrealismCacheLookup::Silo(org, pkg, maj, min, pat) => {
SurrealismCacheKey::Silo((*org).to_string(), (*pkg).to_string(), *maj, *min, *pat)
}
}
}
}
impl<'a> From<SurrealismCacheLookup<'a>> for SurrealismCacheKey {
fn from(lookup: SurrealismCacheLookup<'a>) -> Self {
lookup.to_key()
}
}
impl Equivalent<SurrealismCacheKey> for SurrealismCacheLookup<'_> {
fn equivalent(&self, key: &SurrealismCacheKey) -> bool {
match (self, key) {
(Self::File(a1, b1, c1, d1), SurrealismCacheKey::File(a2, b2, c2, d2)) => {
a1.0 == a2.0 && b1.0 == b2.0 && c1 == c2 && d1 == d2
}
(Self::Silo(a1, b1, c1, d1, e1), SurrealismCacheKey::Silo(a2, b2, c2, d2, e2)) => {
a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2
}
_ => false,
}
}
}
#[derive(Clone)]
pub(crate) struct SurrealismCachedModule {
pub runtime: Arc<Runtime>,
pub module_display_name: Arc<str>,
#[cfg(feature = "http")]
pub client: Arc<HttpClient>,
}
#[derive(Clone)]
pub struct SurrealismCacheValue {
pub(crate) runtime: Arc<Runtime>,
pub(crate) module_display_name: Arc<str>,
#[cfg(feature = "http")]
pub(crate) client: Arc<HttpClient>,
}
#[derive(Clone)]
pub(crate) struct Weight;
impl Weighter<SurrealismCacheKey, SurrealismCacheValue> for Weight {
fn weight(&self, _key: &SurrealismCacheKey, _val: &SurrealismCacheValue) -> u64 {
1
}
}