use futures::Future;
use crate::{data::RuntimeDataStore, error::Error, UserResult};
pub trait User: Send {
fn call(&mut self) -> impl std::future::Future<Output = UserResult> + std::marker::Send;
}
impl<F, Fut> User for F
where
F: FnMut() -> Fut + Send,
Fut: Future<Output = UserResult> + Send,
{
async fn call(&mut self) -> UserResult {
self().await
}
}
#[async_trait::async_trait]
pub trait AsyncUserBuilder<'a>: Sync {
type Output: User + 'a;
async fn build(&self, store: &'a RuntimeDataStore) -> Result<Self::Output, Error>;
}
#[async_trait::async_trait]
impl<'a, F> AsyncUserBuilder<'a> for F
where
F: async_fn_traits::AsyncFn1<&'a RuntimeDataStore> + Sync,
<F as async_fn_traits::AsyncFn1<&'a RuntimeDataStore>>::Output: User + 'a,
for<'b> <F as async_fn_traits::AsyncFn1<&'b RuntimeDataStore>>::OutputFuture: Send,
{
type Output = <F as async_fn_traits::AsyncFn1<&'a RuntimeDataStore>>::Output;
async fn build(&self, store: &'a RuntimeDataStore) -> Result<Self::Output, Error> {
Ok((self)(store).await)
}
}
#[cfg(test)]
mod tests {
use crate::{
data::RuntimeDataStore,
user::{AsyncUserBuilder, User},
UserResult,
};
#[allow(dead_code)]
struct BorrowUser<'a> {
s: &'a str,
}
impl<'a> User for BorrowUser<'a> {
async fn call(&mut self) -> UserResult {
Ok(())
}
}
#[test]
fn test_lifetimes() {
let mut store = RuntimeDataStore::default();
store.insert("A".to_string());
async fn user_builder(r: &RuntimeDataStore) -> BorrowUser<'_> {
let s: &String = r.get().unwrap();
BorrowUser { s: s.as_str() }
}
let _ = futures::executor::block_on(AsyncUserBuilder::build(&user_builder, &store));
}
}