use std::{borrow::Borrow, future::Future, hash::Hash, sync::atomic::Ordering};
use crate::Map;
pub trait GetOrInitAsync: Map {
fn get_or_init_async<'a, Q, E, Fut>(
&'a self,
key: &Q,
func: impl FnOnce(&Q) -> Fut,
) -> impl Future<Output = Result<Self::RefVal<'a>, E>>
where
Self::Key: Borrow<Q>,
Q: ToOwned<Owned = Self::Key> + Hash + Eq + ?Sized,
Fut: Future<Output = Result<Self::Val, E>>;
}
impl<T: GetOrInitAsync + 'static> crate::Expire<T> {
pub async fn get_or_init_async<'a, Q, E, Fut>(
&'a self,
key: &Q,
func: impl FnOnce(&Q) -> Fut,
) -> Result<T::RefVal<'a>, E>
where
T::Key: Borrow<Q>,
Q: ToOwned<Owned = T::Key> + Hash + Eq + ?Sized,
Fut: Future<Output = Result<T::Val, E>>,
{
let inner = self.inner();
let pos = inner.pos.load(Ordering::Relaxed);
if let Some(v) = inner.cache[pos].get(key) {
return Ok(v);
}
if let Some(v) = inner.cache[1 - pos].get(key) {
return Ok(v);
}
inner.cache[pos].get_or_init_async(key, func).await
}
}