use std::future::Future;
use crate::CallerContext;
#[cfg(doc)] use crate::{wrap, SyncWrapContext};
pub trait AsyncWrapContext<T> {
#[allow(async_fn_in_trait)]
async fn new() -> Self
where
Self: Sized;
#[allow(async_fn_in_trait, unused_variables, clippy::unused_async)]
async fn before(&self, caller_context: &CallerContext) {}
#[allow(async_fn_in_trait, unused_variables, clippy::unused_async)]
async fn after(self, caller_context: &CallerContext, result: &T)
where
Self: Sized,
{
}
#[allow(async_fn_in_trait)]
async fn run(caller_context: CallerContext, block: impl Future<Output = T>) -> T
where
Self: Sized,
{
let context = Self::new().await;
context.before(&caller_context).await;
let result = block.await;
context.after(&caller_context, &result).await;
result
}
}
#[cfg(test)]
mod tests {
use crate::CallerContext;
use super::AsyncWrapContext;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
#[tokio::test]
async fn wrapper_usage_on_async_function() {
static VALUE: AtomicUsize = AtomicUsize::new(100);
struct Async;
impl AsyncWrapContext<usize> for Async {
async fn new() -> Self {
Self
}
async fn before(&self, _: &CallerContext) {
VALUE.store(0, Ordering::Relaxed);
}
async fn after(self, _: &CallerContext, result: &usize) {
VALUE.store(2 * *result, Ordering::Relaxed);
}
}
assert_eq!(
Async::run(CallerContext::new("test"), async {
assert_eq!(VALUE.load(Ordering::Relaxed), 0);
42
},)
.await,
42
);
assert_eq!(VALUE.load(Ordering::Relaxed), 84);
}
}