use tokio::sync::mpsc::{self, UnboundedSender};
use tokio::sync::oneshot;
enum CacheSender<V> {
Get,
Insert(V),
Clean,
}
enum CacheReceiver<V> {
Get(Option<V>),
Insert(Option<V>),
Clean(Option<V>),
}
type AsyncCacheSender<V> = UnboundedSender<(CacheSender<V>, oneshot::Sender<CacheReceiver<V>>)>;
#[derive(Clone)]
pub struct AsyncCache<V> {
sender: AsyncCacheSender<V>,
}
impl<V> Default for AsyncCache<V>
where
V: std::marker::Send + Sync + 'static + Clone,
{
fn default() -> Self {
Self::new()
}
}
impl<V> AsyncCache<V>
where
V: std::marker::Send + Sync + 'static + Clone,
{
pub fn new() -> Self {
let (sender, mut receiver) =
mpsc::unbounded_channel::<(CacheSender<V>, oneshot::Sender<CacheReceiver<V>>)>();
tokio::spawn(async move {
let mut cache = None;
while let Some(msg) = receiver.recv().await {
match msg.0 {
CacheSender::Get => {
let _ = msg.1.send(CacheReceiver::Get(cache.as_ref().cloned()));
}
CacheSender::Insert(value) => {
let old_value = cache.take();
let _ = cache.insert(value);
let _ = msg.1.send(CacheReceiver::Insert(old_value));
}
CacheSender::Clean => {
let old_value = cache.take();
let _ = msg.1.send(CacheReceiver::Clean(old_value));
}
}
}
});
Self { sender }
}
pub async fn get(&self) -> Option<V> {
let oneshot = oneshot::channel();
let _ = self.sender.send((CacheSender::Get, oneshot.0));
match oneshot.1.await.unwrap() {
CacheReceiver::Get(value) => value,
_ => panic!("err receiver"),
}
}
pub async fn insert(&self, value: V) -> Option<V> {
let oneshot = oneshot::channel();
let _ = self.sender.send((CacheSender::Insert(value), oneshot.0));
match oneshot.1.await.unwrap() {
CacheReceiver::Insert(value) => value,
_ => panic!("err receiver"),
}
}
pub async fn remove(&self) -> Option<V> {
let oneshot = oneshot::channel();
let _ = self.sender.send((CacheSender::Clean, oneshot.0));
match oneshot.1.await.unwrap() {
CacheReceiver::Clean(value) => value,
_ => panic!("err receiver"),
}
}
}